From 97914180815761dab84d0956aaa456a237bcef3b Mon Sep 17 00:00:00 2001 From: Soare Robert Daniel Date: Mon, 6 Apr 2026 12:14:09 +0300 Subject: [PATCH 1/3] refactor: change Black Friday label for Neve promotion (#508) --- AGENTS.md | 69 +++++++++++++++++++ composer.lock | 20 +++--- .../classes/wp-maintenance-mode-admin.php | 14 ++-- 3 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..814d4ca --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,69 @@ +# Agent Workflow + +## Project Overview + +WP Maintenance Mode (LightStart) is a WordPress plugin by Themeisle that displays a maintenance mode, coming soon, or landing page to visitors. Text domain: `wp-maintenance-mode`. Option key: `wpmm_settings`. All constants prefixed with `WPMM_`. + +## Commands + +```bash +# Install dependencies +composer install +npm install + +# Lint (PHP_CodeSniffer with WordPress coding standards) +composer run lint + +# Auto-fix coding standards +composer run format + +# Run PHPUnit tests +./vendor/bin/phpunit + +# Run a single test file +./vendor/bin/phpunit tests/generic-test.php + +# Build assets (minify JS + CSS via Grunt) +npm run build # or: npx grunt + +# Watch for asset changes during development +npx grunt watch +``` + +## Architecture + +### Entry Point & Bootstrap + +`wp-maintenance-mode.php` — Main plugin file. Defines all `WPMM_*` constants (paths, URLs), requires function files, then loads the two core singleton classes via `plugins_loaded`. + +### Core Classes (`includes/classes/`) + +- **`WP_Maintenance_Mode`** — Frontend singleton. Handles maintenance mode display logic, page templates, redirect rules, multisite/network mode support, and shortcode registration. Loaded on every request. +- **`WP_Maintenance_Mode_Admin`** — Admin singleton. Settings page, AJAX handlers (prefixed `wp_ajax_wpmm_*`), wizard flow, template management, subscriber export, and notices. Only loaded in `is_admin()` context. +- **`WP_Maintenance_Mode_Shortcodes`** + `shortcodes/` — Shortcode registration (e.g., login form shortcode). + +### Functions (`includes/functions/`) + +- **`hooks.php`** — Plugin header filters and email content type hook. +- **`helpers.php`** — Utility functions (e.g., `wpmm_get_option()`). + +### Views (`views/`) + +PHP template files for admin settings tabs (`settings.php`, `contact.php`, `google-analytics.php`), the frontend maintenance page (`maintenance.php`), wizard (`wizard.php`), network settings, notices, and sidebar. + +### Assets + +- `assets/js/` — Frontend (`scripts.js`) and admin (`scripts-admin.js`, `scripts-admin-global.js`) JavaScript, plus chatbot (`bot.js`, `bot.async.js`). Grunt minifies to `.min.js`. +- `assets/css/` — Stylesheets minified via PostCSS/cssnano to `.min.css`. +- `assets/templates/` — Block template JSON files organized by category: `coming-soon/`, `maintenance/`, `landing-page/`. + +### Settings Structure + +Plugin settings stored as serialized array in `wpmm_settings` option, with sections: `general` (status, network_mode), plus additional tabs managed by the admin class. Network/multisite settings stored in `wpmm_settings_network`. + +## Coding Standards + +- WordPress-Core standards enforced via PHPCS (`phpcs.xml`), with specific exclusions (no Yoda conditions required, loose comparison allowed, etc.) +- i18n text domain: `wp-maintenance-mode` +- PHP minimum: 7.0 (runtime set in PHPCS) +- Assets use `.min.` suffix in production; controlled by `SCRIPT_DEBUG` constant diff --git a/composer.lock b/composer.lock index 951d036..3f80008 100644 --- a/composer.lock +++ b/composer.lock @@ -4,25 +4,25 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b5f5da36c50a2fe2bccfce677431bfbc", + "content-hash": "6acace5af549ca9a6ced24d8aeef359d", "packages": [ { "name": "codeinwp/themeisle-sdk", - "version": "3.3.48", + "version": "3.3.51", "source": { "type": "git", "url": "https://github.com/Codeinwp/themeisle-sdk.git", - "reference": "0727d2cf2fc9bfb81b42968aeaf2bf4e340f021e" + "reference": "bb2a8414b0418b18c68c9ff1df3d7fb10467928d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/0727d2cf2fc9bfb81b42968aeaf2bf4e340f021e", - "reference": "0727d2cf2fc9bfb81b42968aeaf2bf4e340f021e", + "url": "https://api.github.com/repos/Codeinwp/themeisle-sdk/zipball/bb2a8414b0418b18c68c9ff1df3d7fb10467928d", + "reference": "bb2a8414b0418b18c68c9ff1df3d7fb10467928d", "shasum": "" }, "require-dev": { "codeinwp/phpcs-ruleset": "dev-main", - "yoast/phpunit-polyfills": "^2.0" + "yoast/phpunit-polyfills": "^4.0" }, "type": "library", "notification-url": "https://packagist.org/downloads/", @@ -36,16 +36,16 @@ "homepage": "https://themeisle.com" } ], - "description": "ThemeIsle SDK", + "description": "Themeisle SDK.", "homepage": "https://github.com/Codeinwp/themeisle-sdk", "keywords": [ "wordpress" ], "support": { "issues": "https://github.com/Codeinwp/themeisle-sdk/issues", - "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.3.48" + "source": "https://github.com/Codeinwp/themeisle-sdk/tree/v3.3.51" }, - "time": "2025-08-11T16:47:24+00:00" + "time": "2026-03-30T07:58:49+00:00" } ], "packages-dev": [ @@ -671,5 +671,5 @@ "platform-overrides": { "php": "5.6" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/includes/classes/wp-maintenance-mode-admin.php b/includes/classes/wp-maintenance-mode-admin.php index 7721e34..69c81ff 100644 --- a/includes/classes/wp-maintenance-mode-admin.php +++ b/includes/classes/wp-maintenance-mode-admin.php @@ -1324,15 +1324,19 @@ public function add_inline_global_style() { public function add_black_friday_data( $configs ) { $config = $configs['default']; - // translators: %1$s - plugin namce, %2$s - HTML tag, %3$s - discount, %4$s - HTML tag, %5$s - company name. - $message_template = __( 'Brought to you by the team behind %1$s— our biggest sale of the year is here: %2$sup to %3$s OFF%4$s on premium products from %5$s! Limited-time only.', 'wp-maintenance-mode' ); + if ( defined( 'NEVE_VERSION' ) ) { + return $configs; + } - $config['message'] = sprintf( $message_template, 'WP Maintenance Mode', '', '70%', '', 'Themeisle' ); - $config['sale_url'] = add_query_arg( + // translators: 1. Number of free licenses, 2. The price of the product. + $config['message'] = sprintf( __( 'You\'re using LightStart, and the team behind it is celebrating Black Friday by giving away %1$s licences of Neve Pro. A premium WordPress theme worth %2$s, packed with starter sites, a header builder, and WooCommerce layouts. Claim yours before they run out.', 'wp-maintenance-mode' ), 100, '$69' ); + $config['cta_label'] = __( 'Get Neve Pro free', 'wp-maintenance-mode' ); + $config['plugin_meta_message'] = __( 'Black Friday Sale - Get Neve Pro free', 'wp-maintenance-mode' ); + $config['sale_url'] = add_query_arg( array( 'utm_term' => 'free', ), - tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/all-bf', 'bfcm', 'wp-maintenance-mode' ) ) + tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/neve-claim-bf', 'bfcm', 'lightstart' ) ) ); $configs[ WPMM_PRODUCT_SLUG ] = $config; From 57a30fea5e700c0f00cfe6926c64c5de7a097de4 Mon Sep 17 00:00:00 2001 From: Girish Panchal <79647963+girishpanchal30@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:45:41 +0530 Subject: [PATCH 2/3] feat: add tracking opt-in checkbox (#507) --- assets/css/style-wizard.css | 13 +++++++++ assets/js/scripts-admin.js | 2 ++ .../classes/wp-maintenance-mode-admin.php | 4 +++ includes/classes/wp-maintenance-mode.php | 27 +++++++++++++++++++ views/wizard.php | 7 +++++ 5 files changed, 53 insertions(+) diff --git a/assets/css/style-wizard.css b/assets/css/style-wizard.css index 133c527..b57b63b 100644 --- a/assets/css/style-wizard.css +++ b/assets/css/style-wizard.css @@ -296,6 +296,19 @@ h2.wpmm-title span img { font-size: 18px; } +.subscribe-step .opt-in-container { + display: flex; + gap: 8px; + margin-top: 20px; +} + +.subscribe-step .opt-in-container svg.components-checkbox-control__checked { + top: 20%; +} + +.subscribe-step .opt-in-container label { + text-align: left; +} #email-input-wrap { position: relative; display: flex; diff --git a/assets/js/scripts-admin.js b/assets/js/scripts-admin.js index cdd5f72..42b7ef8 100644 --- a/assets/js/scripts-admin.js +++ b/assets/js/scripts-admin.js @@ -429,11 +429,13 @@ jQuery( function( $ ) { emailInput.removeClass( 'invalid' ); subscribeButton.addClass( 'is-busy' ); + const optIn = $('#wizard-opt-in').is( ':checked' ); $.post( wpmmVars.ajaxURL, { action: 'wpmm_subscribe', email, _wpnonce: wpmmVars.wizardNonce, + opt_in: optIn ? 1 : 0, }, function( response ) { if ( ! response.success ) { alert( response.data ); diff --git a/includes/classes/wp-maintenance-mode-admin.php b/includes/classes/wp-maintenance-mode-admin.php index 69c81ff..b9ff304 100644 --- a/includes/classes/wp-maintenance-mode-admin.php +++ b/includes/classes/wp-maintenance-mode-admin.php @@ -806,6 +806,10 @@ public function subscribe_newsletter() { die( esc_html__( 'Empty field: email', 'wp-maintenance-mode' ) ); } + if ( isset( $_POST['opt_in'] ) && sanitize_text_field( $_POST['opt_in'] ) ) { + update_option( 'wp_maintenance_mode_logger_flag', 'yes' ); + } + $response = wp_remote_post( self::SUBSCRIBE_ROUTE, array( diff --git a/includes/classes/wp-maintenance-mode.php b/includes/classes/wp-maintenance-mode.php index e144f7e..3090bc7 100644 --- a/includes/classes/wp-maintenance-mode.php +++ b/includes/classes/wp-maintenance-mode.php @@ -159,6 +159,9 @@ function() { } ); } + + add_action( 'init', array( $this, 'initialize_telemetry' ) ); + } /** @@ -1449,6 +1452,30 @@ public function set_current_page_category( $category ) { public function get_current_page_category() { return $this->current_page_category; } + + /** + * Initialize telemetry. + * + * @return void + */ + public function initialize_telemetry() { + if ( 'yes' === get_option( 'wp_maintenance_mode_logger_flag' ) ) { + add_filter( 'themeisle_sdk_enable_telemetry', '__return_true' ); + add_filter( + 'themeisle_sdk_telemetry_products', + function( $products ) { + foreach ( $products as &$product ) { + if ( isset( $product['slug'] ) && 'wp' === $product['slug'] ) { + $product['slug'] = 'wp_maintenance_mode'; + } + } + + return $products; + } + ); + } + + } } } diff --git a/views/wizard.php b/views/wizard.php index 59ef19d..90a30b2 100644 --- a/views/wizard.php +++ b/views/wizard.php @@ -116,6 +116,13 @@ +
+ + + + + +
From b2373b22c5a81681bb0ce65ced789afe309e3509 Mon Sep 17 00:00:00 2001 From: Girish Panchal <79647963+girishpanchal30@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:46:58 +0530 Subject: [PATCH 3/3] fix: store subscriber data (#496) Store the subscriber data while the user submits the form on the Maintenance Mode page. --- includes/classes/wp-maintenance-mode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/wp-maintenance-mode.php b/includes/classes/wp-maintenance-mode.php index 3090bc7..558be69 100644 --- a/includes/classes/wp-maintenance-mode.php +++ b/includes/classes/wp-maintenance-mode.php @@ -1388,7 +1388,7 @@ public function send_contact() { */ public function otter_add_subscriber( $form_data ) { if ( $form_data ) { - $input_data = $form_data->get_payload_field( 'formInputsData' ); + $input_data = $form_data->get_data_from_payload( 'formInputsData' ); $input_data = array_map( function( $input_field ) { if ( isset( $input_field['type'] ) && 'email' === $input_field['type'] ) {