Plugin Directory

Changeset 3474640


Ignore:
Timestamp:
03/04/2026 02:07:07 PM (4 weeks ago)
Author:
recorp
Message:

6.0.0

  • Refactored the core export engine for improved stability and performance.
  • Improved: Watchdog now automatically detects and repairs stalled export processes.
  • Improved: Enhanced failed URL tracking with per-URL retry counts and detailed error reporting.
  • Improved: Re-run only failed URLs without restarting the entire export process.
  • Improved: Implemented exponential backoff for asset retries to reduce server load.
  • Improved: Asset collection mode (Strict / Hybrid / Full) is now saved and respected across cron runs.
  • Fixed: Export context is now correctly propagated to background workers during server cron execution.
  • Added: single_root_index and root_parent_html options are now persisted within the export context.
  • Improved: More user-friendly interface and overall UX enhancements.
  • Removed: PDF Exporting option removed temporarily.
Location:
export-wp-page-to-static-html
Files:
31 added
13 deleted
4 edited

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 ===
     2Contributors:       recorp
     3Tags:               static html export, static site generator, html export, export posts, export pages
     4Requires at least:  5.8
     5Tested up to:       6.7
     6Requires PHP:       7.4
     7Stable tag:         6.0.0
     8License:            GPLv2 or later
     9License URI:        https://www.gnu.org/licenses/gpl-2.0.html
     10
     11Export 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.
    1112
    1213== 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
     17Whether 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
     25Most 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
     44Export 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
     48Pick 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
     52Export 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
     56Export 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
     60Turn 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
     64Enable "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
     68After 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
     72Download 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
     76Push 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
     80Running 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
     84Three 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
     88Export 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
     92Exports 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
     96Long 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
     100A 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
     104Export 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/)
    50148
    51149== 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
     1531. In your WordPress dashboard, go to **Plugins → Add New**
     1542. Search for **"Export WP Pages to Static HTML"**
     1553. Click **Install Now**, then **Activate**
     1564. Navigate to **Tools → Export WP Pages to Static HTML**
     157
     158= Manual Installation =
     159
     1601. Download the plugin `.zip` file from WordPress.org
     1612. Go to **Plugins → Add New → Upload Plugin**
     1623. Upload the ZIP and click **Install Now**, then **Activate**
     1634. Navigate to **Tools → Export WP Pages to Static HTML**
     164
     165= Your First Export =
     166
     1671. Go to **Tools → Export WP Pages to Static HTML**
     1682. Choose your **Export Scope** (Custom, All Pages, or Pro: All Posts / Full Site)
     1693. Select the posts or pages you want to export
     1704. (Optional) Choose a **Post Status**, **Login Role**, and **Asset Options**
     1715. Click **Start Export**
     1726. 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
     178Yes! 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
     182Export 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
     186Yes. 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
     190You 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
     194When 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
     198It 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
     202Yes. 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
     206Yes. 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
     210Yes. 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
     214Enable "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
     218After 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
     222Yes. 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
     226Yes. 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
     230The free plugin works on individual sites in a multisite network.
     231
     232= What are the asset collection modes? =
     233
     234Strict 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
     238No. 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
     242Post 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.
    70243
    71244== 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. 
     2451. **Export Panel** — Select posts, pages, or CPT items, choose scope, and start your export
     246
    91247
    92248== 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
    93262
    94263= 5.0.1 - 2 February 2026 =
     
    241410* Initialize the plugin
    242411
     412
     413== Upgrade Notice ==
     414
     415= 6.1.0 =
     416This 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  
    11<?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
    104 * 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.1
     5 * 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
    137 * Author:            ReCorp
    148 * Author URI:        https://www.upwork.com/fl/rayhan1
    159 * License:           GPL-2.0+
    1610 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
    17  * Text Domain:       export-wp-page-to-static-html
     11 * Text Domain:       wp-to-html
    1812 * Domain Path:       /languages
    1913 */
    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 
     14if (!defined('ABSPATH')) exit;
     15
     16/**
     17 * Load plugin text domain for translations.
     18 */
     19add_action('init', function () {
     20    load_plugin_textdomain('wp-to-html', false, dirname(plugin_basename(__FILE__)) . '/languages');
     21});
     22define('WP_TO_HTML_VERSION', '6.0.0');
     23define('WP_TO_HTML_PATH', plugin_dir_path(__FILE__));
     24define('WP_TO_HTML_URL', plugin_dir_url(__FILE__));
     25define('WP_TO_HTML_EXPORT_DIR', WP_CONTENT_DIR . '/wp-to-html-exports');
     26define('WP_TO_HTML_DEBUG', false);
     27
     28// Advanced debugger (super debugger)
     29// Enable in wp-config.php: define('WP_TO_HTML_ADVANCED_DEBUG', true);
     30if (!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 */
     40if (!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
     57if (!function_exists('wp_to_html_allowed_scopes')) {
    3958    /**
    40      * The code that runs during plugin activation
    41      *
    42      * This action is documented in includes/class-export-wp-page-to-static-html-activator.php
     59     * Allowed export scopes for the current installation.
     60     * Free: selected (aka custom) + all_pages
     61     * Pro: selected + all_pages + all_posts + full_site
    4362     */
    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
     77add_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
     125require_once WP_TO_HTML_PATH . 'includes/class-core.php';
     126require_once WP_TO_HTML_PATH . 'includes/class-admin.php';
     127require_once WP_TO_HTML_PATH . 'includes/class-rest.php';
     128require_once WP_TO_HTML_PATH . 'includes/class-exporter.php';
     129require_once WP_TO_HTML_PATH . 'includes/class-diagnostic.php';
     130require_once WP_TO_HTML_PATH . 'includes/class-advanced-debugger.php';
     131require_once WP_TO_HTML_PATH . 'includes/class-asset-manager.php';
     132require_once WP_TO_HTML_PATH . 'includes/class-asset-extractor.php';
     133require_once WP_TO_HTML_PATH . 'includes/class-bulk-asset-collector.php';
     134require_once WP_TO_HTML_PATH . 'includes/class-ftp-uploader.php';
     135
     136// Robust RFC3986 URL absolutizer (ported from the older exporter).
     137require_once WP_TO_HTML_PATH . 'includes/url/url_to_absolute.php';
     138
     139add_action('plugins_loaded', function () {
     140    \WpToHtml\Core::get_instance();
     141});
     142
     143register_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 */
     158add_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
     182add_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
     193register_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
     210function 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
     328function 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}
     356add_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.