Changeset 3474640
- Timestamp:
- 03/04/2026 02:07:07 PM (4 weeks ago)
- Location:
- export-wp-page-to-static-html
- Files:
-
- 31 added
- 13 deleted
- 4 edited
-
assets/screenshot-1.png (modified) (previous)
-
assets/screenshot-2.png (deleted)
-
trunk/LICENSE.txt (deleted)
-
trunk/README.txt (modified) (2 diffs)
-
trunk/admin (deleted)
-
trunk/assets (added)
-
trunk/assets/admin.css (added)
-
trunk/assets/admin.js (added)
-
trunk/export-wp-page-to-static-html.php (modified) (1 diff)
-
trunk/includes/class-admin.php (added)
-
trunk/includes/class-advanced-debugger.php (added)
-
trunk/includes/class-asset-extractor.php (added)
-
trunk/includes/class-asset-manager.php (added)
-
trunk/includes/class-bulk-asset-collector.php (added)
-
trunk/includes/class-core.php (added)
-
trunk/includes/class-diagnostic.php (added)
-
trunk/includes/class-export-wp-page-to-static-html-activator.php (deleted)
-
trunk/includes/class-export-wp-page-to-static-html-deactivator.php (deleted)
-
trunk/includes/class-export-wp-page-to-static-html-i18n.php (deleted)
-
trunk/includes/class-export-wp-page-to-static-html-loader.php (deleted)
-
trunk/includes/class-export-wp-page-to-static-html.php (deleted)
-
trunk/includes/class-exporter.php (added)
-
trunk/includes/class-ftp-uploader.php (added)
-
trunk/includes/class-rest.php (added)
-
trunk/includes/class-s3-uploader.php (added)
-
trunk/includes/global_functions.php (deleted)
-
trunk/includes/html-export-metabox.php (deleted)
-
trunk/includes/index.php (deleted)
-
trunk/includes/url (added)
-
trunk/includes/url-discovery (added)
-
trunk/includes/url-discovery/class-wp-to-html-url-discovery.php (added)
-
trunk/includes/url-discovery/class-wp-to-html-url-rules.php (added)
-
trunk/includes/url-discovery/crawlers (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-author-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-date-archive-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-pagination-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-post-type-archive-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-rest-api-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-rss-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-sitemap-crawler.php (added)
-
trunk/includes/url-discovery/crawlers/class-wp-to-html-taxonomy-crawler.php (added)
-
trunk/includes/url-discovery/interface-wp-to-html-url-crawler.php (added)
-
trunk/includes/url/join_url.php (added)
-
trunk/includes/url/split_url.php (added)
-
trunk/includes/url/url_to_absolute.php (added)
-
trunk/index.php (modified) (1 diff)
-
trunk/languages/export-wp-page-to-static-html.pot (deleted)
-
trunk/uninstall.php (deleted)
Legend:
- Unmodified
- Added
- Removed
-
export-wp-page-to-static-html/trunk/README.txt
r3457772 r3474640 1 === Export WP Pages to HTML & PDF – Simply Create a Static Website === 2 Contributors: recorp 3 Tags: HTML, html, pdf, static, site 4 Requires at least: 4.1 5 Tested up to: 6.8 6 Stable tag: 5.0.1 7 License: GPLv2 or later 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html 9 10 Simply turn your WordPress site into a secure, SEO-friendly static website. Export pages to optimized HTML/CSS and professional PDFs in one click. 1 === Export WP Pages to Static HTML – Simply Create a Static Website === 2 Contributors: recorp 3 Tags: static html export, static site generator, html export, export posts, export pages 4 Requires at least: 5.8 5 Tested up to: 6.7 6 Requires PHP: 7.4 7 Stable tag: 6.0.0 8 License: GPLv2 or later 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 11 Export any WordPress post, page, or custom post type to clean static HTML — one at a time or in bulk. Grouped assets, role-based export, FTP upload & more. 11 12 12 13 == Description == 13 **Export WP Page to HTML & PDF – Simply Create a Static Website** is a powerful site and page exporter plugin for WordPress. It helps you convert any post or page into **static HTML/CSS** files or **print-ready PDF documents**. You can host your exported content from a static hosting provider, CDN, or your own server — boosting speed and reducing server-side risks. 14 It significantly improves your website's performance and security by removing the need for database connections when serving exported content. 15 🎥 [Watch Demo](https://www.youtube.com/watch?v=VEDG-5saLzY) 16 17 == Features == 18 19 ### 🔹 Free Features 20 * **One-Click HTML Export** – Instantly convert WordPress pages or posts to clean static HTML/CSS files. 21 * **Lightweight & Easy-to-Use UI** – Clean, minimal design that works out-of-the-box. 22 * **Faster Loading** – Serve your site without dynamic database queries. 23 * **Simple Shortcodes** – Use `[export_html_button]` anywhere to trigger HTML export. 24 25 ### 📑 PDF Generator (Free + Pro) 26 * **Print-Ready PDF Export** – Generate professional PDFs from your content. 27 * **Custom PDF Templates** – Configure headers, footers, fonts, page numbers, and even watermarks. 28 * **Responsive PDFs** – Your content fits beautifully on any page size. 29 * **Shortcode Support** – Use `[generate_pdf_button]` to place a PDF button anywhere. 30 * **Role-Based Access** – Only specific WordPress roles will see the PDF export option. 31 32 --- 33 34 == 🚀 Pro Features == 35 Upgrade to the premium version for advanced functionality: 36 37 * Export entire **WordPress site** with all related links. 38 * Export **external URLs** into static HTML. 39 * Create a **completely offline version** of your site. 40 * **Login-as-any-role** option to export pages based on different user views. 41 * Export multiple posts/pages **simultaneously**. 42 * Automatically export content after it’s **published or updated**. 43 * Run background exports (no need to stay on the settings page). 44 * Upload exported files directly to an **FTP server**. 45 * Receive **notifications** on export completion. 46 * Enhanced **PDF customization** options. 47 * … and much more. 48 49 🎯 [Get the Premium Version](https://myrecorp.com/product/export-wp-pages-to-static-html-css-pro/?clk=wp&a=readme) 14 15 **Export WP Pages to Static HTML** is the most flexible static HTML export plugin for WordPress. Unlike full-site generators, Export WP Pages to Static HTML gives you surgical control — export exactly the posts, pages, or custom post types you need, in the status you want, as the user role you choose. 16 17 Whether you're archiving a campaign landing page, delivering client work as a self-contained HTML package, or building a lightning-fast static copy of your content, Export WP Pages to Static HTML makes it effortless. 18 19 > 🔒 **[Export WP Pages to Static HTML Pro Available](https://myrecorp.com/export-wp-page-to-static-html-pro/)** — Unlock All Posts, Full Site exports, AWS S3 deployment & more! 20 21 --- 22 23 ### 🎯 Why Export WP Pages to Static HTML Is Different 24 25 Most static site plugins convert your *entire* WordPress site in one go. Export WP Pages to Static HTML lets you target exactly what you need: 26 27 ✅ Export a **single post** or **hand-pick multiple posts, pages, or CPT items** in one run 28 ✅ Export **across all post statuses** — Published, Draft, Private, Pending, Scheduled 29 ✅ Export content exactly as it appears to a **specific user role** (subscriber, editor, etc.) 30 ✅ **Group assets cleanly** into `/images`, `/css`, `/js` — developer-ready output 31 ✅ Save parent posts as **clean root-level `.html` files** — no nested folders 32 ✅ **Preview** exported files right inside WordPress before downloading 33 ✅ **Download assets as ZIP** — all images, CSS, JS packaged in one click 34 ✅ **FTP / SFTP upload** directly from the export panel 35 ✅ **Email notification** when your export completes 36 ✅ Built-in **System Status** diagnostics page 37 38 --- 39 40 ### ⚡ Core Features (Free) 41 42 **All Pages Export** 43 44 Export all your WordPress pages in one click — no need to select them one by one. Perfect for exporting your entire page-based site (landing pages, portfolios, business sites) as clean static HTML. 45 46 **Granular Export Control** 47 48 Pick exactly what to export — no need to regenerate your entire site every time. Select one post, a handful of pages, or choose from any custom post type. Use the built-in search to find content instantly and the "Select All" button for quick bulk selection. 49 50 **All Post Statuses Supported** 51 52 Export content regardless of its WordPress status. Publish, Draft, Private, Pending, and Scheduled posts are all supported. Perfect for previewing unpublished pages as static HTML before they go live. 53 54 **Role-Based Export** 55 56 Export pages exactly as they appear to a specific WordPress user role. Export WP Pages to Static HTML temporarily creates a user of the chosen role, renders the pages through their eyes, then cleans up — no permanent users left behind. Essential for membership sites, gated content previews, and client deliveries. 57 58 **Grouped Asset Organization** 59 60 Turn on "Group assets by type" and Export WP Pages to Static HTML automatically sorts all exported assets into clean subdirectories: `/images`, `/css`, `/js`. The result is a well-structured, developer-friendly HTML package that's easy to hand off or deploy. 61 62 **Parent Posts in Root Directory** 63 64 Enable "Parent posts in root dir" and Export WP Pages to Static HTML flattens your URL structure — `/postname/index.html` becomes `/postname.html` at the export root. Ideal for clean, flat static site structures. 65 66 **Live Export Preview** 67 68 After every export, a built-in file browser lets you preview exactly what was generated — HTML files, images, scripts, and stylesheets — right inside your WordPress dashboard. 69 70 **Download Assets as ZIP** 71 72 Download all exported images or other asset types as a single ZIP archive in one click. No need to manually browse folders or FTP into your server. 73 74 **FTP / SFTP Upload** 75 76 Push exports directly to a remote server over FTP or SFTP without leaving WordPress. Set your host, port, credentials, and remote path once — then upload with a button click. Supports FTPS (SSL) and passive mode. 77 78 **Email Notification on Complete** 79 80 Running a large export in the background? Enable "Notify on complete" and Export WP Pages to Static HTML emails you (and optional additional addresses) the moment the export finishes. 81 82 **Smart Asset Collection Modes** 83 84 Three modes give you precise control over which assets are bundled: Strict (only assets directly referenced by exported pages), Hybrid (referenced assets + media library, recommended), and Full (everything: uploads, theme assets, and plugin assets). 85 86 **Intelligent URL Discovery and Crawling** 87 88 Export WP Pages to Static HTML's built-in crawlers automatically discover all URLs needed for your selected content, including pagination, taxonomy archives, author pages, date archives, RSS feeds, post-type archives, sitemap URLs, and REST API endpoints — so no linked assets or pages are ever missed. 89 90 **Fault-Tolerant Export Engine** 91 92 Exports don't break on bad URLs. Export WP Pages to Static HTML automatically retries failed URLs with exponential backoff, tracks every failure with its last error message, and lets you re-run only the failed URLs without restarting the whole export. A background watchdog monitors stuck processes and repairs them automatically. 93 94 **Pause, Resume, and Cancel** 95 96 Long exports? Pause mid-run, pick up later, or cancel entirely without corrupting your export directory. Full export lifecycle control from the admin panel. 97 98 **System Status and Diagnostics** 99 100 A dedicated System Status page checks your PHP version, WordPress environment, file permissions, REST API availability, and more — so you can diagnose issues before they stop an export. 101 102 **Translation Ready** 103 104 Export WP Pages to Static HTML is fully internationalized and ready for translation via the WordPress translation system. 105 106 --- 107 108 ### 🚀 Export WP Pages to Static HTML Pro Features 109 110 * **All Posts export** — export every post (or selected custom post types) in one run 111 * **Full Site export** — complete WordPress-to-static-HTML conversion with URL discovery 112 * **AWS S3 deployment** — push exports directly to an S3 bucket 113 * Email support and priority bug fixes 114 115 [Upgrade to Export WP Pages to Static HTML Pro →](https://myrecorp.com/export-wp-page-to-static-html-pro/) 116 117 --- 118 119 ### 🛠️ Perfect For 120 121 * **Developers and agencies** delivering static HTML proofs or archives to clients 122 * **Content teams** exporting specific posts for offline review or archiving 123 * **Marketing teams** saving landing pages and campaign pages as standalone HTML 124 * **Site owners** creating lightweight static mirrors of posts or pages 125 * **Freelancers** handing off finished pages as a self-contained HTML package 126 127 ### ❌ Not Suitable For 128 129 * Sites that require real-time dynamic content (live chat, WooCommerce checkout, membership portals) 130 * Sites where the goal is replacing WordPress with a fully automated static deployment pipeline — consider Export WP Pages to Static HTML Pro for bulk and full-site generation 131 132 --- 133 134 ### 🔌 Compatibility 135 136 * Works with **all WordPress themes** including block themes and classic themes 137 * **Page builders:** Elementor, Divi, Beaver Builder, Bricks, Gutenberg 138 * **SEO plugins:** Yoast SEO, Rank Math, AIOSEO, SEOPress 139 * **Custom post types:** auto-detected, available in the export scope selector 140 * PHP 7.4 – 8.3 | WordPress 5.8 – 6.7 141 142 --- 143 144 ### 📖 Documentation and Support 145 146 * 📖 [Documentation](https://myrecorp.com/documentation/export-wp-page-to-static-html-documentation) 147 * 💬 [Support Forum](https://wordpress.org/support/plugin/export-wp-page-to-static-html/) 50 148 51 149 == Installation == 52 1. Upload the folder `export-wp-page-static-html-pdf` to `/wp-content/plugins/`. 53 2. Activate **Export WP Page to Static HTML & PDF** from the **Plugins** screen. 54 3. Go to **Settings → Static HTML & PDF Export** to configure: 55 - **User Roles**: Select which WordPress roles can see the export buttons. 56 - **PDF Template**: Customize headers, footers, watermarks, fonts, and page numbers. 57 - **Export Limits**: Set daily PDF export caps and notification settings. 58 4. Place the export buttons: 59 - **Admin Bar**: Auto-injects “Generate PDF†and “Export HTML†into the admin bar for allowed users. 60 - **Shortcode**: Add `[generate_pdf_button]` or `[export_html_button]` in any post, page, or widget. 61 62 63 = More plugins you may like = 64 * [AI Content Writing Assistant (Content Writer, ChatGPT, Image Generator) All in One](https://wordpress.org/plugins/ai-content-writing-assistant/) 65 https://www.youtube.com/watch?v=HvOkfBs7qss 66 * [Different Menu in Different Pages](https://wordpress.org/plugins/different-menus-in-different-pages/) 67 * [Pipe ReCaptcha](https://wordpress.org/plugins/pipe-recaptcha/) 68 * [Divi MailChimp Extension](https://wordpress.org/plugins/recorp-divi-mailchimp-extension/?clk=wp) 69 * [Menu import & export pro](https://myrecorp.com/product/menu-import-and-export-pro/?r=export-html&clk=wp) 150 151 = Automatic Installation (Recommended) = 152 153 1. In your WordPress dashboard, go to **Plugins → Add New** 154 2. Search for **"Export WP Pages to Static HTML"** 155 3. Click **Install Now**, then **Activate** 156 4. Navigate to **Tools → Export WP Pages to Static HTML** 157 158 = Manual Installation = 159 160 1. Download the plugin `.zip` file from WordPress.org 161 2. Go to **Plugins → Add New → Upload Plugin** 162 3. Upload the ZIP and click **Install Now**, then **Activate** 163 4. Navigate to **Tools → Export WP Pages to Static HTML** 164 165 = Your First Export = 166 167 1. Go to **Tools → Export WP Pages to Static HTML** 168 2. Choose your **Export Scope** (Custom, All Pages, or Pro: All Posts / Full Site) 169 3. Select the posts or pages you want to export 170 4. (Optional) Choose a **Post Status**, **Login Role**, and **Asset Options** 171 5. Click **Start Export** 172 6. When complete, click **Preview** to browse the files or **Download ZIP** to save them 173 174 == Frequently Asked Questions == 175 176 = Is Export WP Pages to Static HTML free? = 177 178 Yes! The core plugin is completely free and includes Custom and All Pages export scopes. Export WP Pages to Static HTML Pro is an optional add-on that unlocks All Posts, Full Site exports, and AWS S3 deployment. 179 180 = How is Export WP Pages to Static HTML different from Simply Static or other full-site generators? = 181 182 Export WP Pages to Static HTML is built for precision over full-site generation. Instead of converting your entire WordPress installation, you choose exactly which posts, pages, or custom post type items to export — and in what status and user-role context. This makes it far more useful for client deliveries, content archiving, and partial static exports. 183 184 = Can I export draft or private posts as static HTML? = 185 186 Yes. Export WP Pages to Static HTML supports all five WordPress post statuses: Publish, Draft, Private, Pending, and Scheduled. This is rare in static export plugins and a key differentiator of Export WP Pages to Static HTML. 187 188 = What does "role-based export" mean? = 189 190 You can choose a WordPress user role (e.g., Subscriber, Editor) and Export WP Pages to Static HTML will render the exported pages exactly as that role would see them. It temporarily creates a user of that role, renders the content, then deletes the user — nothing is left behind. 191 192 = What does "Group assets by type" do? = 193 194 When enabled, Export WP Pages to Static HTML sorts all exported assets into subdirectories: images go into `/images`, stylesheets into `/css`, and scripts into `/js`. This produces clean, organized output that is immediately ready for handoff or deployment. 195 196 = What does "Parent posts in root dir" do? = 197 198 It flattens the URL structure of parent posts. Instead of `/postname/index.html`, the file is saved as `/postname.html` directly in the export root — ideal for hosting on simple static servers. 199 200 = Can I re-run only the failed URLs? = 201 202 Yes. Export WP Pages to Static HTML tracks every failed URL with its error message and retry count. A dedicated "Re-run failed" button retries only the failed items without restarting the entire export. 203 204 = Can I pause and resume an export? = 205 206 Yes. Use the Pause and Resume buttons in the export panel at any time. Exports can also be cancelled without corrupting already-exported files. 207 208 = Can I upload exports directly to my FTP/SFTP server? = 209 210 Yes. Configure your FTP/SFTP credentials in **Settings → FTP/SFTP** and enable "Upload to FTP" before starting an export. Supports passive mode and FTPS (SSL). You can also browse remote directories directly from the settings panel. 211 212 = How does email notification work? = 213 214 Enable "Notify on complete" in the Delivery and Notifications panel. You can optionally add extra email addresses for teammates or clients. A notification email is sent automatically when the export finishes. 215 216 = What is the Preview feature? = 217 218 After an export completes, the built-in file browser lets you browse all generated files — HTML pages, images, CSS, JS — directly in your WordPress admin. You can also download groups of assets (like all images) as ZIP archives from the preview panel. 219 220 = Does Export WP Pages to Static HTML work with Elementor, Divi, and other page builders? = 221 222 Yes. Export WP Pages to Static HTML works with all major page builders and has been tested with Elementor, Divi, Beaver Builder, Bricks Builder, and the native Gutenberg editor. 223 224 = Does it work with custom post types? = 225 226 Yes. All public, registered custom post types are automatically detected and appear in the Export Scope selector under the "Post types" tab. 227 228 = Does it work on WordPress Multisite? = 229 230 The free plugin works on individual sites in a multisite network. 231 232 = What are the asset collection modes? = 233 234 Strict exports only assets directly referenced by the exported pages. Hybrid (the recommended default) adds your media library on top of referenced assets. Full includes everything — theme and plugin asset directories included. 235 236 = Will this affect my live WordPress site? = 237 238 No. Exports are written to a separate directory (`/wp-content/wp-to-html-exports/`). Your live WordPress site remains fully intact and unchanged. 239 240 = Where can I get help? = 241 242 Post in the [WordPress.org support forum](https://wordpress.org/support/plugin/export-wp-page-to-static-html/). Export WP Pages to Static HTML Pro customers receive priority email support. 70 243 71 244 == Screenshots == 72 1. Default settings page layout of the plugin. 73 2. PDF generation button in the admin bar of a post. 74 75 76 == Shortcodes == 77 `[generate_pdf_button]` 78 : Inserts a “Generate PDF†button. Visible only to allowed roles. 79 `[export_html_button]` 80 : Inserts an “Export HTML†button. Visible only to allowed roles. 81 82 == Frequently Asked Questions == 83 = How do I control which users see the export buttons? = 84 Go to **Settings → Static HTML & PDF Export** and select the user roles under **Role-Based Access**. 85 86 = What happens when the daily limit is reached? = 87 Admin or Users see a friendly popup informing them they have reached their export limit. The button is disabled until the next 24-hour window. 88 89 = Will this work with page builders like Elementor or Divi? = 90 Absolutely. Exports capture the fully rendered front-end output—page builder layouts included. 245 1. **Export Panel** — Select posts, pages, or CPT items, choose scope, and start your export 246 91 247 92 248 == Changelog == 249 250 = 6.0.0 = 251 * Refactored the core export engine for improved stability and performance. 252 * Improved: Watchdog now automatically detects and repairs stalled export processes. 253 * Improved: Enhanced failed URL tracking with per-URL retry counts and detailed error reporting. 254 * Improved: Re-run only failed URLs without restarting the entire export process. 255 * Improved: Implemented exponential backoff for asset retries to reduce server load. 256 * Improved: Asset collection mode (Strict / Hybrid / Full) is now saved and respected across cron runs. 257 * Fixed: Export context is now correctly propagated to background workers during server cron execution. 258 * Added: `single_root_index` and `root_parent_html` options are now persisted within the export context. 259 * Improved: More user-friendly interface and overall UX enhancements. 260 * Removed: PDF Exporting option removed temporarily. 261 93 262 94 263 = 5.0.1 - 2 February 2026 = … … 241 410 * Initialize the plugin 242 411 412 413 == Upgrade Notice == 414 415 = 6.1.0 = 416 This release improves export reliability with enhanced retry logic, watchdog repair, and better background processing. Recommended update for all users. -
export-wp-page-to-static-html/trunk/export-wp-page-to-static-html.php
r3457772 r3474640 1 1 <?php 2 3 /** 4 * @link https://www.upwork.com/fl/rayhan1 5 * @since 1.0.0 6 * @package Export_Wp_Page_To_Static_Html 7 * 8 * @wordpress-plugin 9 * Plugin Name: Export WP Pages to HTML & PDF – Simply Create a Static Website 2 /** 3 * Plugin Name: Export WP Page to Static HTML 10 4 * Plugin URI: https://myrecorp.com 11 * Description: Seamlessly export any WordPress page or post into lightweight, fully responsive static HTML/CSS and print-ready PDF with a single click. Boost your site’s performance and security by serving pre-rendered pages, create offline-friendly backups. Perfect for developers, content creators, and businesses needing fast, reliable exports of WordPress content.12 * Version: 5.0.15 * Description: Export WP Pages to Static HTML is the most flexible static HTML export plugin for WordPress. Unlike full-site generators, Export WP Pages to Static HTML gives you surgical control — export exactly the posts, pages, or custom post types you need, in the status you want, as the user role you choose. 6 * Version: 6.0.0 13 7 * Author: ReCorp 14 8 * Author URI: https://www.upwork.com/fl/rayhan1 15 9 * License: GPL-2.0+ 16 10 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt 17 * Text Domain: export-wp-page-to-static-html11 * Text Domain: wp-to-html 18 12 * Domain Path: /languages 19 13 */ 20 21 // If this file is called directly, abort. 22 if ( ! defined( 'WPINC' ) ) { 23 die; 24 } 25 26 // if (version_compare(PHP_VERSION, '8.1.13') > 0) { 27 // add_action('admin_notices', function (){ 28 // $content = __("To use the \"<strong>Export WP Pages to HTML & PDF – Simply Create a Static Website</strong>\" plugin, you require PHP version <strong>8.1.13 or lower</strong>. Your current PHP version is: <strong>" . PHP_VERSION . '</strong>', 'export-wp-page-to-static-html') ; 29 // $html = '<div class="notice notice-error wpptsh wpptsh-php-not-compatible" wpptsh_notice_key="" style="padding: 19px;font-size: 16px;"> 30 // '.$content.' 31 // </div>'; 32 33 // echo $html; 34 // }); 35 // echo ' ' . "\n"; 36 // } 37 // else{ 38 14 if (!defined('ABSPATH')) exit; 15 16 /** 17 * Load plugin text domain for translations. 18 */ 19 add_action('init', function () { 20 load_plugin_textdomain('wp-to-html', false, dirname(plugin_basename(__FILE__)) . '/languages'); 21 }); 22 define('WP_TO_HTML_VERSION', '6.0.0'); 23 define('WP_TO_HTML_PATH', plugin_dir_path(__FILE__)); 24 define('WP_TO_HTML_URL', plugin_dir_url(__FILE__)); 25 define('WP_TO_HTML_EXPORT_DIR', WP_CONTENT_DIR . '/wp-to-html-exports'); 26 define('WP_TO_HTML_DEBUG', false); 27 28 // Advanced debugger (super debugger) 29 // Enable in wp-config.php: define('WP_TO_HTML_ADVANCED_DEBUG', true); 30 if (!defined('WP_TO_HTML_ADVANCED_DEBUG')) { 31 define('WP_TO_HTML_ADVANCED_DEBUG', false); 32 } 33 34 /** 35 * Pro bridge helpers 36 * 37 * The Free plugin exposes these helpers so a separate Pro plugin can enable 38 * premium scopes (All Pages / All Posts / Full Site) without modifying core logic. 39 */ 40 if (!function_exists('wp_to_html_is_pro_active')) { 41 function wp_to_html_is_pro_active(): bool { 42 // Fast path: Pro plugin can define this constant. 43 if (defined('WP_TO_HTML_PRO_ACTIVE') && WP_TO_HTML_PRO_ACTIVE) { 44 return true; 45 } 46 47 // Alternative: Pro can load a class. 48 if (class_exists('WpToHtml_Pro\\Plugin')) { 49 return true; 50 } 51 52 // Extensible hook for other licensing/loader mechanisms. 53 return (bool) apply_filters('wp_to_html/pro_active', false); 54 } 55 } 56 57 if (!function_exists('wp_to_html_allowed_scopes')) { 39 58 /** 40 * The code that runs during plugin activation41 * 42 * This action is documented in includes/class-export-wp-page-to-static-html-activator.php59 * Allowed export scopes for the current installation. 60 * Free: selected (aka custom) + all_pages 61 * Pro: selected + all_pages + all_posts + full_site 43 62 */ 44 function activate_export_wp_page_to_static_html() { 45 require_once plugin_dir_path( __FILE__ ) . 'includes/class-export-wp-page-to-static-html-activator.php'; 46 Export_Wp_Page_To_Static_Html_Activator::activate(); 47 } 48 49 50 register_activation_hook( __FILE__, 'activate_export_wp_page_to_static_html' ); 51 52 if (!function_exists('run_export_wp_page_to_static_html_pro')){ 53 54 /** 55 * Currently plugin version. 56 * Start at version 1.0.0 and use SemVer - https://semver.org 57 * Rename this for your plugin and update it as you release new versions. 58 */ 59 define( 'EXPORT_WP_PAGE_TO_STATIC_HTML_VERSION', '5.0.1' ); 60 define( 'EWPPTSH_PLUGIN_DIR_URL', plugin_dir_url(__FILE__) ); 61 define( 'EWPPTSH_PLUGIN_DIR_PATH', plugin_dir_path(__FILE__) ); 62 define( 'EWPPTSH_DEVELOPER_MODE', false ); 63 define( 'WPPTSH_DB_VERSION', '1.2'); 64 65 /** 66 * The code that runs during plugin deactivation. 67 * This action is documented in includes/class-export-wp-page-to-static-html-deactivator.php 68 */ 69 function deactivate_export_wp_page_to_static_html() { 70 require_once plugin_dir_path( __FILE__ ) . 'includes/class-export-wp-page-to-static-html-deactivator.php'; 71 Export_Wp_Page_To_Static_Html_Deactivator::deactivate(); 72 } 73 register_deactivation_hook( __FILE__, 'deactivate_export_wp_page_to_static_html' ); 74 75 register_activation_hook(__FILE__, 'export_wp_page_to_html_save_redirect_option'); 76 add_action('admin_init', 'export_wp_page_to_html_redirect_to_menu'); 77 78 79 /*Activating daily task*/ 80 register_activation_hook( __FILE__, 'rc_static_html_task_events_activate' ); 81 register_deactivation_hook( __FILE__, 'rc_static_html_task_events_deactivate' ); 82 83 84 /*Redirect to plugin's settings page when plugin will active*/ 85 function export_wp_page_to_html_save_redirect_option() { 86 add_option('export_wp_page_to_html_activation_check', true); 87 } 88 89 90 function export_wp_page_to_html_redirect_to_menu() { 91 if (get_option('export_wp_page_to_html_activation_check', false)) { 92 delete_option('export_wp_page_to_html_activation_check'); 93 wp_redirect( esc_url_raw( admin_url( 'admin.php?page=export-wp-page-to-html&welcome=true' ) ) ); 94 exit; 95 } 96 } 97 98 99 /** 100 * The core plugin class that is used to define internationalization, 101 * admin-specific hooks, and public-facing site hooks. 102 */ 103 require plugin_dir_path( __FILE__ ) . 'includes/class-export-wp-page-to-static-html.php'; 104 105 /** 106 * Begins execution of the plugin. 107 * 108 * Since everything within the plugin is registered via hooks, 109 * then kicking off the plugin from this point in the file does 110 * not affect the page life cycle. 111 * 112 * @since 1.0.0 113 */ 114 function run_export_wp_page_to_static_html() { 115 116 $plugin = new Export_Wp_Page_To_Static_Html(); 117 $plugin->run(); 118 119 } 120 run_export_wp_page_to_static_html(); 121 122 123 function wpptsh_error_log($log){ 124 if (EWPPTSH_DEVELOPER_MODE) { 125 error_log($log); 126 } 127 } 128 // On plugin activation (once), create/store a token 129 register_activation_hook(__FILE__, function(){ 130 if (!get_option('ewptshp_worker_token')) { 131 add_option('ewptshp_worker_token', wp_generate_password(32, false, false)); 132 } 133 }); 134 135 // Runs on every load, no __FILE__ here 136 function wpptsh_update_db_check() { 137 global $wpdb; 138 139 $installed_ver = get_option('wpptsh_db_version', '0'); 140 $table_name = $wpdb->prefix . 'export_urls_logs'; 141 $column_name = 'type'; 142 143 // Early bail if version is current 144 if ((string) $installed_ver === (string) WPPTSH_DB_VERSION) { 145 return; 146 } 147 148 // Ensure we have upgrade helpers for dbDelta 149 if ( ! function_exists('dbDelta')) { 150 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 151 } 152 153 // --- 1) Try to add the column via dbDelta (preferred) --- 154 // dbDelta needs a full CREATE TABLE statement. If you know the table schema, 155 // define it here. If not, skip to the fallback below. 156 // NOTE: Replace the columns below with your real schema (keep 'type' in it). 157 $charset_collate = $wpdb->get_charset_collate(); 158 159 $known_schema = " 160 CREATE TABLE {$table_name} ( 161 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 162 url TEXT NOT NULL, 163 `{$column_name}` TINYTEXT NOT NULL, 164 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 165 PRIMARY KEY (id) 166 ) {$charset_collate}; 167 "; 168 169 // If you KNOW the table structure above is accurate, uncomment the next line: 170 // dbDelta($known_schema); 171 172 // --- 2) Cache the existence check to satisfy NoCaching sniff --- 173 $cache_group = 'wpptsh_schema'; 174 $cache_key = 'has_col_' . md5($table_name . '|' . $column_name); 175 176 $column_exists = wp_cache_get($cache_key, $cache_group); 177 178 if (false === $column_exists) { 179 // PHPCS flags any $wpdb call as "direct", but this is a read-only, prepared query. 180 // We cache the result to address the NoCaching rule. 181 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 182 $column_exists = (bool) $wpdb->get_var( 183 $wpdb->prepare( 184 "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS 185 WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s", 186 DB_NAME, 187 $table_name, 188 $column_name 189 ) 190 ); 191 wp_cache_set($cache_key, $column_exists, $cache_group, 12 * HOUR_IN_SECONDS); 192 } 193 194 // --- 3) Fallback: add column via ALTER if still missing --- 195 if ( ! $column_exists ) { 196 // If you cannot reliably use dbDelta with the full CREATE TABLE statement, 197 // do a minimal ALTER TABLE. Document and ignore the PHPCS warnings: 198 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.DirectDatabaseQuery.DirectQuery 199 $wpdb->query("ALTER TABLE `{$table_name}` ADD COLUMN `{$column_name}` TINYTEXT NOT NULL"); 200 201 // Invalidate cache after schema change 202 wp_cache_delete($cache_key, $cache_group); 203 } 204 205 // --- 4) Update DB version --- 206 update_option('wpptsh_db_version', WPPTSH_DB_VERSION); 207 208 // --- 5) Ensure worker token exists --- 209 if ( ! get_option('ewptshp_worker_token')) { 210 add_option('ewptshp_worker_token', wp_generate_password(32, false, false)); 211 } 212 } 213 214 215 add_action('plugins_loaded', 'wpptsh_update_db_check'); 216 } 217 218 //} 63 function wp_to_html_allowed_scopes(): array { 64 $scopes = ['selected', 'all_pages']; 65 if (wp_to_html_is_pro_active()) { 66 $scopes = ['selected', 'all_posts', 'all_pages', 'full_site']; 67 } 68 69 return (array) apply_filters('wp_to_html/allowed_scopes', $scopes); 70 } 71 } 72 73 /** 74 * DB schema upgrades (runs on every load, but only applies changes when needed). 75 */ 76 77 add_action('plugins_loaded', function () { 78 global $wpdb; 79 80 $status = $wpdb->prefix . 'wp_to_html_status'; 81 // If the table doesn't exist yet, activation will create it. 82 $exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $status)); 83 if (!$exists) return; 84 85 // Ensure required columns exist (handles upgrades from older schemas). 86 $required_cols = [ 87 'state' => "ALTER TABLE {$status} ADD COLUMN state VARCHAR(20) DEFAULT 'idle'", 88 'is_running' => "ALTER TABLE {$status} ADD COLUMN is_running TINYINT(1) NOT NULL DEFAULT 0 AFTER state", 89 'total_urls' => "ALTER TABLE {$status} ADD COLUMN total_urls INT DEFAULT 0", 90 'processed_urls' => "ALTER TABLE {$status} ADD COLUMN processed_urls INT DEFAULT 0", 91 'total_assets' => "ALTER TABLE {$status} ADD COLUMN total_assets INT DEFAULT 0", 92 'processed_assets' => "ALTER TABLE {$status} ADD COLUMN processed_assets INT DEFAULT 0", 93 'last_progress_at' => "ALTER TABLE {$status} ADD COLUMN last_progress_at DATETIME NULL", 94 'last_progress_stage' => "ALTER TABLE {$status} ADD COLUMN last_progress_stage VARCHAR(30) NULL", 95 'last_progress_done' => "ALTER TABLE {$status} ADD COLUMN last_progress_done INT DEFAULT 0", 96 'watchdog_runs' => "ALTER TABLE {$status} ADD COLUMN watchdog_runs INT DEFAULT 0", 97 'watchdog_repairs' => "ALTER TABLE {$status} ADD COLUMN watchdog_repairs INT DEFAULT 0", 98 'failed_assets' => "ALTER TABLE {$status} ADD COLUMN failed_assets INT DEFAULT 0", 99 ]; 100 101 foreach ($required_cols as $name => $sql) { 102 $col = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$status} LIKE %s", $name)); 103 if (!$col) { 104 $wpdb->query($sql); 105 } 106 } 107 108 // Ensure row id=1 exists WITHOUT overwriting live state (REPLACE would reset columns to defaults). 109 // Only insert defaults if the row is missing. 110 $row_exists = (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$status} WHERE id=%d", 1)); 111 if (!$row_exists) { 112 $wpdb->insert($status, [ 113 'id' => 1, 114 'state' => 'idle', 115 'is_running' => 0, 116 'total_urls' => 0, 117 'processed_urls' => 0, 118 'total_assets' => 0, 119 'processed_assets' => 0, 120 'failed_assets' => 0, 121 ]); 122 } 123 }); 124 125 require_once WP_TO_HTML_PATH . 'includes/class-core.php'; 126 require_once WP_TO_HTML_PATH . 'includes/class-admin.php'; 127 require_once WP_TO_HTML_PATH . 'includes/class-rest.php'; 128 require_once WP_TO_HTML_PATH . 'includes/class-exporter.php'; 129 require_once WP_TO_HTML_PATH . 'includes/class-diagnostic.php'; 130 require_once WP_TO_HTML_PATH . 'includes/class-advanced-debugger.php'; 131 require_once WP_TO_HTML_PATH . 'includes/class-asset-manager.php'; 132 require_once WP_TO_HTML_PATH . 'includes/class-asset-extractor.php'; 133 require_once WP_TO_HTML_PATH . 'includes/class-bulk-asset-collector.php'; 134 require_once WP_TO_HTML_PATH . 'includes/class-ftp-uploader.php'; 135 136 // Robust RFC3986 URL absolutizer (ported from the older exporter). 137 require_once WP_TO_HTML_PATH . 'includes/url/url_to_absolute.php'; 138 139 add_action('plugins_loaded', function () { 140 \WpToHtml\Core::get_instance(); 141 }); 142 143 register_activation_hook(__FILE__, function() { 144 // Buffer output to prevent PHP warnings/notices from dbDelta() 145 // from being counted as "unexpected output" during activation 146 // (especially when WP_DEBUG_DISPLAY is enabled). 147 ob_start(); 148 wp_to_html_ensure_tables(); 149 ob_end_clean(); 150 151 // Store version on activation so first-install doesn't trigger the "What's New" page. 152 update_option('wp_to_html_version', WP_TO_HTML_VERSION, false); 153 }); 154 155 /** 156 * Redirect to "What's New" page after plugin update (not on first activation). 157 */ 158 add_action('admin_init', function () { 159 // Only run for admins. 160 if (!current_user_can('manage_options')) return; 161 162 // Skip during AJAX, cron, bulk activate, or CLI. 163 if (wp_doing_ajax() || wp_doing_cron()) return; 164 if (isset($_GET['activate-multi'])) return; 165 if (defined('WP_CLI') && WP_CLI) return; 166 167 $stored = get_option('wp_to_html_version', ''); 168 169 if ($stored === '') { 170 // First install — store version, no redirect. 171 update_option('wp_to_html_version', WP_TO_HTML_VERSION, false); 172 return; 173 } 174 175 if (version_compare($stored, WP_TO_HTML_VERSION, '<')) { 176 // Plugin was updated — set transient and bump stored version. 177 update_option('wp_to_html_version', WP_TO_HTML_VERSION, false); 178 set_transient('wp_to_html_show_whats_new', 1, 60); 179 } 180 }, 1); 181 182 add_action('admin_init', function () { 183 if (!get_transient('wp_to_html_show_whats_new')) return; 184 delete_transient('wp_to_html_show_whats_new'); 185 186 // Don't redirect if already on the page. 187 if (isset($_GET['page']) && $_GET['page'] === 'wp-to-html-whats-new') return; 188 189 wp_safe_redirect(admin_url('admin.php?page=wp-to-html-whats-new')); 190 exit; 191 }, 99); 192 193 register_deactivation_hook(__FILE__, function() { 194 wp_clear_scheduled_hook('wp_to_html_process_event'); 195 196 global $wpdb; 197 198 $tables = [ 199 $wpdb->prefix . 'wp_to_html_status', 200 $wpdb->prefix . 'wp_to_html_queue', 201 $wpdb->prefix . 'wp_to_html_assets', 202 ]; 203 204 foreach ($tables as $table) { 205 $wpdb->query("DROP TABLE IF EXISTS {$table}"); 206 } 207 208 }); 209 210 function wp_to_html_ensure_tables() { 211 212 global $wpdb; 213 214 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 215 216 $charset_collate = $wpdb->get_charset_collate(); 217 218 $queue_table = $wpdb->prefix . 'wp_to_html_queue'; 219 $assets_table = $wpdb->prefix . 'wp_to_html_assets'; 220 $status_table = $wpdb->prefix . 'wp_to_html_status'; 221 222 /* 223 |-------------------------------------------------------------------------- 224 | 1. Queue Table 225 |-------------------------------------------------------------------------- 226 */ 227 // Queue now supports retries/backoff + failed-only reruns. 228 $sql_queue = "CREATE TABLE $queue_table ( 229 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 230 url TEXT NOT NULL, 231 status VARCHAR(20) NOT NULL DEFAULT 'pending', 232 retry_count INT NOT NULL DEFAULT 0, 233 last_error LONGTEXT NULL, 234 last_attempt_at DATETIME NULL, 235 next_attempt_at DATETIME NULL, 236 started_at DATETIME NULL, 237 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 238 PRIMARY KEY (id), 239 KEY status (status), 240 KEY next_attempt_at (next_attempt_at) 241 ) $charset_collate;"; 242 243 dbDelta($sql_queue); 244 245 246 /* 247 |-------------------------------------------------------------------------- 248 | 2. Assets Table 249 |-------------------------------------------------------------------------- 250 */ 251 252 $sql_assets = "CREATE TABLE $assets_table ( 253 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 254 url TEXT NOT NULL, 255 found_on TEXT NULL, 256 asset_type VARCHAR(30) NOT NULL DEFAULT 'asset', 257 local_path TEXT NULL, 258 status VARCHAR(20) NOT NULL DEFAULT 'pending', 259 retry_count INT NOT NULL DEFAULT 0, 260 last_error LONGTEXT NULL, 261 last_attempt_at DATETIME NULL, 262 next_attempt_at DATETIME NULL, 263 started_at DATETIME NULL, 264 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 265 PRIMARY KEY (id), 266 267 UNIQUE KEY unique_url (url(191)), 268 KEY status (status), 269 KEY asset_type (asset_type), 270 KEY next_attempt_at (next_attempt_at), 271 KEY started_at (started_at) 272 ) $charset_collate;"; 273 274 dbDelta($sql_assets); 275 276 277 /* 278 |-------------------------------------------------------------------------- 279 | 3. Status Table 280 |-------------------------------------------------------------------------- 281 */ 282 $sql_status = "CREATE TABLE $status_table ( 283 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 284 state VARCHAR(20) DEFAULT 'idle', 285 is_running TINYINT(1) DEFAULT 0, 286 pipeline_stage VARCHAR(30) NOT NULL DEFAULT 'idle', 287 stage_total INT DEFAULT 0, 288 stage_done INT DEFAULT 0, 289 failed_urls INT DEFAULT 0, 290 failed_assets INT DEFAULT 0, 291 total_urls INT DEFAULT 0, 292 processed_urls INT DEFAULT 0, 293 total_assets INT DEFAULT 0, 294 processed_assets INT DEFAULT 0, 295 last_progress_at DATETIME NULL, 296 last_progress_stage VARCHAR(30) NULL, 297 last_progress_done INT DEFAULT 0, 298 watchdog_runs INT DEFAULT 0, 299 watchdog_repairs INT DEFAULT 0, 300 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 301 PRIMARY KEY (id) 302 ) $charset_collate;"; 303 304 dbDelta($sql_status); 305 306 307 /* 308 |-------------------------------------------------------------------------- 309 | 4. Ensure Single Status Row Exists 310 |-------------------------------------------------------------------------- 311 */ 312 $exists = $wpdb->get_var("SELECT COUNT(*) FROM $status_table"); 313 314 if (!$exists) { 315 $wpdb->insert($status_table, [ 316 'state' => 'idle', 317 'is_running' => 0, 318 'total_urls' => 0, 319 'processed_urls' => 0, 320 'total_assets' => 0, 321 'processed_assets' => 0, 322 'failed_assets' => 0, 323 ]); 324 } 325 326 } 327 328 function wp_to_html_plugin_update() { 329 global $wpdb; 330 331 $installed_version = get_option('wp_to_html_version'); // previous plugin version 332 $current_version = '6.0.0'; 333 $tables_removed = get_option('wp_to_html_old_tables_removed', false); 334 335 // Run only if plugin version has changed 336 if ( $installed_version !== $current_version ) { 337 338 // Remove old tables only once 339 if ( ! $tables_removed ) { 340 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}exportable_urls" ); 341 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}export_page_to_html_logs" ); 342 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}export_urls_logs" ); 343 344 // Mark old tables as removed 345 update_option( 'wp_to_html_old_tables_removed', true ); 346 347 // Create new tables 348 wp_to_html_ensure_tables(); 349 } 350 351 352 // Update plugin version 353 update_option( 'wp_to_html_version', $current_version ); 354 } 355 } 356 add_action( 'plugins_loaded', 'wp_to_html_plugin_update' ); -
export-wp-page-to-static-html/trunk/index.php
r2316499 r3474640 1 <?php // Silence is golden
Note: See TracChangeset
for help on using the changeset viewer.