diff --git a/composer.json b/composer.json index cd5d2b0a..ae9d44ec 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "php": ">=7.4", "wa72/url": "^0.7.1", "leonstafford/wp2staticguzzle": "^7.2.0", + "symfony/polyfill-php80": "^1.27.0", "ext-mbstring": "*", "ext-simplexml": "*", "lib-libxml": "*" @@ -34,7 +35,7 @@ "thecodingmachine/phpstan-strict-rules": "*", "szepeviktor/phpstan-wordpress": "*", "squizlabs/php_codesniffer": "*", - "phpunit/phpunit": "*", + "phpunit/phpunit": "9.5.24", "dealerdirect/phpcodesniffer-composer-installer": "*", "wp-coding-standards/wpcs": "*", "phpcompatibility/php-compatibility": "*", diff --git a/composer.lock b/composer.lock index ee159219..253724c8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7316e9fdacf5afa5df610fc114420f9f", + "content-hash": "cb7958cf72fddecc01791173dbf7a464", "packages": [ { "name": "leonstafford/wp2staticguzzle", @@ -364,6 +364,89 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, { "name": "wa72/url", "version": "v0.7.1", @@ -511,35 +594,38 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.2", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", + "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0" + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -555,7 +641,7 @@ }, { "name": "Contributors", - "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -579,10 +665,10 @@ "tests" ], "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2022-02-04T12:51:07+00:00" + "time": "2023-01-05T11:28:13+00:00" }, { "name": "doctrine/instantiator", @@ -889,16 +975,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.2", + "version": "v4.15.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", - "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", "shasum": "" }, "require": { @@ -939,9 +1025,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" }, - "time": "2022-11-12T15:38:23+00:00" + "time": "2023-01-16T22:05:37+00:00" }, { "name": "phar-io/manifest", @@ -1222,16 +1308,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.9.6", + "version": "1.9.14", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "ef38a25950e5d0e6c95eedf49d8a784272f8dc5e" + "reference": "e5fcc96289cf737304286a9b505fbed091f02e58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ef38a25950e5d0e6c95eedf49d8a784272f8dc5e", - "reference": "ef38a25950e5d0e6c95eedf49d8a784272f8dc5e", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58", + "reference": "e5fcc96289cf737304286a9b505fbed091f02e58", "shasum": "" }, "require": { @@ -1261,7 +1347,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.6" + "source": "https://github.com/phpstan/phpstan/tree/1.9.14" }, "funding": [ { @@ -1277,20 +1363,20 @@ "type": "tidelift" } ], - "time": "2023-01-03T13:40:32+00:00" + "time": "2023-01-19T10:47:09+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.23", + "version": "9.2.24", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c" + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", - "reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", "shasum": "" }, "require": { @@ -1346,7 +1432,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" }, "funding": [ { @@ -1354,7 +1440,7 @@ "type": "github" } ], - "time": "2022-12-28T12:41:10+00:00" + "time": "2023-01-26T08:26:55+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1599,16 +1685,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.27", + "version": "9.5.24", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38" + "reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38", - "reference": "a2bc7ffdca99f92d959b3f2270529334030bba38", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5", + "reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5", "shasum": "" }, "require": { @@ -1630,14 +1716,14 @@ "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", + "sebastian/comparator": "^4.0.5", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", + "sebastian/exporter": "^4.0.3", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/type": "^3.1", "sebastian/version": "^3.0.2" }, "suggest": { @@ -1681,7 +1767,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24" }, "funding": [ { @@ -1691,13 +1777,9 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" } ], - "time": "2022-12-09T07:31:23+00:00" + "time": "2022-08-30T07:42:16+00:00" }, { "name": "sebastian/cli-parser", diff --git a/css/admin/style.css b/css/admin/style.css index c719176c..286dd78f 100644 --- a/css/admin/style.css +++ b/css/admin/style.css @@ -1,10 +1,45 @@ a[href*="wp2static-try-1-click-publish"], .try-1-click-publish-menu-item { - color: white; + color: white !important; background-color: #FB4247; font-weight: bold; } +.try-1-click-publish-menu-item:hover { + color: #FB4247 !important; + background-color: white !important; + font-weight: bold; +} + #wp2static-try-1-click-publish-plugin-screen { color: #FB4247; font-weight: bold; } + +.wp2static-admin-notice { + margin-left: 2px; + margin-right: 36px; + margin-top: 20px; + margin-bottom: -7px; + padding-top: 10px; +} + +.wp2static-admin-notice a .button-primary { + margin-bottom: 10px; + margin-right: 10px; +} + +a[id*="wp2static-admin-notice-dismiss"] { + display: block; + float: right; + margin-top: -75px; + text-decoration: none; +} + +#wp2static-admin-notice-nonce, #wp2static-admin-notice-user-id { + display: none; +} + +.strattic-logo { + margin-bottom: -5px; + padding-right: 5px; +} diff --git a/js/admin/override-menu-style.js b/js/admin/override-menu-style.js index 82e3a077..7f5457a5 100644 --- a/js/admin/override-menu-style.js +++ b/js/admin/override-menu-style.js @@ -1,4 +1,4 @@ -document.addEventListener("DOMContentLoaded", function(event) { +jQuery(document).ready(function($){ // locate the submenu item by partial match of its href value const try1ClickPublish = document.querySelector('a[href*="wp2static-try-1-click-publish"]'); @@ -10,6 +10,47 @@ document.addEventListener("DOMContentLoaded", function(event) { try1ClickPublish.target = "_blank"; // set a custom external href for the submenu item - try1ClickPublish.href = 'https://www.strattic.com/pricing/?utm_campaign=start-trial&utm_source=wp2static&utm_medium=wp-dash&utm_content=sidebar'; + try1ClickPublish.href = 'https://link.strattic.com/one-click-deploy'; + // send admin notice dismissal events to backend + const wp2staticAdminNotice = document.querySelector('.wp2static-admin-notice'); + + if ( wp2staticAdminNotice ) { + wp2staticAdminNotice.addEventListener('click', function (e) { + const targetParent = e.target.parentNode; + + if (targetParent.className === 'wp2static-admin-notice-dismiss') { + // notify backend which admin notice was dismissed by user + dismissedAdminNotice = targetParent.id.replace('wp2static-admin-notice-dismiss-', '') + + adminNoticeNonce = + document.querySelector('#wp2static-admin-notice-nonce').textContent; + + adminNoticeUserID = + document.querySelector('#wp2static-admin-notice-user-id').textContent; + + const ajax_data = { + action: 'wp2static_admin_notice_dismissal', + security: adminNoticeNonce, + dismissedNotice: dismissedAdminNotice, + userID: adminNoticeUserID, + }; + + $.ajax({ + url: ajaxurl, + type: 'POST', + data: ajax_data, + timeout: 0, + success: function() { + // hide the admin notice once backend has handled it + wp2staticAdminNotice.remove(); + }, + error: function() { + alert('Couldn\'t dismiss WP2Static admin notice. Please try again.'); + } + }); + } + }); + + } }); diff --git a/src/Addons.php b/src/Addons.php index 954e2fe2..1d4d6398 100755 --- a/src/Addons.php +++ b/src/Addons.php @@ -52,7 +52,6 @@ public static function registerAddon( */ public static function getAll( string $type = 'all' ) : array { global $wpdb; - $addons = []; $table_name = $wpdb->prefix . 'wp2static_addons'; diff --git a/src/AdminNotices.php b/src/AdminNotices.php new file mode 100755 index 00000000..b52d9b89 --- /dev/null +++ b/src/AdminNotices.php @@ -0,0 +1,395 @@ +prefix . 'wp2static_notices'; + + $charset_collate = $wpdb->get_charset_collate(); + + $sql = "CREATE TABLE $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + name VARCHAR(191) NOT NULL, + user_id bigint(20) NOT NULL, + action VARCHAR(191) NOT NULL, + timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) + ) $charset_collate;"; + + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + dbDelta( $sql ); + } + + /** + * Displays WP2Static admin notices + */ + public static function showAdminNotices() : void { + if ( ! ( new self() )->userAllowedToSeeNotices() ) { + return; + } + + // avoid missing table error for git users who don't re-activate plugin + global $wpdb; + $table_name = $wpdb->prefix . 'wp2static_notices'; + + $check_table_query = + $wpdb->prepare( + 'SHOW TABLES LIKE %s', + $wpdb->esc_like( $table_name ) + ); + + if ( $wpdb->get_var( $check_table_query ) !== $table_name ) { + return; + } + + $notice_to_display = ( new self() )->getNoticeBasedOnRules(); + + if ( ! $notice_to_display ) { + return; + } + + ( new self() )->logNoticeAction( $notice_to_display['name'], 'displayed' ); + + $hostname = base64_encode( SiteInfo::getUrl( 'site' ) ); + $deploy_url = base64_encode( CoreOptions::getValue( 'deploymentURL' ) ); + + printf( + '
' . + '' . + '%2$s

%3$s

' . + // phpcs:disable Generic.Files.LineLength.TooLong + '' . + // phpcs:disable Generic.Files.LineLength.TooLong + '' . + '' . + // phpcs:disable Generic.Files.LineLength.MaxExceeded + '' . + '
' . + wp_create_nonce( 'wp2static-admin-notice' ) . '
' . + '
' . + get_current_user_id() . '
' . + '
', + esc_attr( $notice_to_display['class'] ), + esc_html( $notice_to_display['title'] ), + nl2br( $notice_to_display['message'] ), + esc_html( $notice_to_display['primary_button_url'] ), + esc_html( $notice_to_display['primary_button_title'] ), + esc_html( $notice_to_display['secondary_button_url'] ), + esc_html( $notice_to_display['secondary_button_title'] ) + ); + } + + /** + * Determine if a user should user see any notices + */ + public static function userAllowedToSeeNotices() : bool { + return current_user_can( 'manage_options' ); + } + + public static function handleDismissedNotice() : void { + check_ajax_referer( 'wp2static-admin-notice', 'security' ); + + $dismissed_notice = strval( filter_input( INPUT_POST, 'dismissedNotice' ) ); + + ( new self() )->logNoticeAction( $dismissed_notice, 'dismissed' ); + + wp_die(); + } + + public static function logNoticeAction( string $notice_name, string $action ) : void { + global $wpdb; + + $table_name = $wpdb->prefix . 'wp2static_notices'; + + $current_user_id = get_current_user_id(); + + $wpdb->insert( + $table_name, + [ + 'name' => $notice_name, + 'user_id' => $current_user_id, + 'action' => $action, + ] + ); + } + + /** + * Apply rules to determine which, if any, notice to show + * + * @return string[]|null + */ + public function getNoticeBasedOnRules() { + // don't show if no publish history (empty CrawlCache) + if ( CrawlCache::getTotal() === 0 ) { + return null; + } + + // common notice properties + $notice = [ + 'name' => 'generic', + 'class' => 'notice notice-info wp2static-admin-notice', + 'primary_button_title' => 'Start my trial', + 'secondary_button_title' => 'Learn more', + ]; + + $addons = Addons::getAll(); + + if ( ! ( new self() )->noticeAlreadyDismissed( 'wp2static-addons-installed' ) && + $addons !== [] + ) { + $notice['name'] = 'wp2static-addons-installed'; + $notice = array_merge( ( new self() )->getNoticeContents( 'wp2static-addons-installed' ), $notice ); + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'elementor-pro' ) && + is_plugin_active( 'elementor-pro/elementor-pro.php' ) + ) { + $notice['name'] = 'elementor-pro'; + $notice = array_merge( ( new self() )->getNoticeContents( 'elementor-pro' ), $notice ); + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'wp-rocket' ) && + is_plugin_active( 'wp-rocket/wp-rocket.php' ) + ) { + $notice['name'] = 'wp-rocket'; + $notice = array_merge( ( new self() )->getNoticeContents( 'wp-rocket' ), $notice ); + // show notice if Gravity Forms or Contact Form 7 active and hasn't dismissed notice + // if both are active, prioritise showing message for Gravity Forms + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'forms-plugin-activated' ) && + ( is_plugin_active( 'gravityforms/gravityforms.php' ) || + is_plugin_active( 'contact-form-7/wp-contact-form-7.php' ) ) + ) { + $notice['name'] = 'forms-plugin-activated'; + + if ( is_plugin_active( 'gravityforms/gravityforms.php' ) ) { + $notice = array_merge( ( new self() )->getNoticeContents( 'gravity-forms' ), $notice ); + } else { + $notice = array_merge( ( new self() )->getNoticeContents( 'contact-form-7' ), $notice ); + } + // if both are active, prioritise showing message for WPML + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'multilingual-plugin-activated' ) && + ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) || + is_plugin_active( 'polylang/polylang.php' ) ) + ) { + $notice['name'] = 'multilingual-plugin-activated'; + + if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) { + $notice = array_merge( ( new self() )->getNoticeContents( 'wpml' ), $notice ); + } else { + $notice = array_merge( ( new self() )->getNoticeContents( 'polylang' ), $notice ); + } + // if both are active, prioritise showing message for Yoast + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'seo-plugin-activated' ) && + ( is_plugin_active( 'wordpress-seo/wp-seo.php' ) || + is_plugin_active( 'seo-by-rank-math/rank-math.php' ) ) + ) { + $notice['name'] = 'seo-plugin-activated'; + + if ( is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) { + $notice = array_merge( ( new self() )->getNoticeContents( 'yoast' ), $notice ); + } else { + $notice = array_merge( ( new self() )->getNoticeContents( 'rankmath' ), $notice ); + } + // if both are active, prioritise showing message for Redirection + } elseif ( ! ( new self() )->noticeAlreadyDismissed( 'redirection-plugin-activated' ) && + ( is_plugin_active( 'redirection/redirection.php' ) || + is_plugin_active( 'simple-301-redirects/wp-simple-301-redirects.php' ) ) + ) { + $notice['name'] = 'redirection-plugin-activated'; + + if ( is_plugin_active( 'redirection/redirection.php' ) ) { + $notice = array_merge( ( new self() )->getNoticeContents( 'redirection' ), $notice ); + } else { + $notice = array_merge( ( new self() )->getNoticeContents( 'simple-301-redirects' ), $notice ); + } + } elseif ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) { + // if at least one WooCommerce order exists, don't show any notices + global $wpdb; + $table_name = $wpdb->prefix . 'wc_order_stats'; + $woocommerce_orders = $wpdb->get_var( + $wpdb->prepare( + "SELECT count(*) FROM $table_name" + ) + ); + + if ( $woocommerce_orders ) { + return null; + } + + $notice = array_merge( ( new self() )->getNoticeContents( 'generic' ), $notice ); + } else { + // if no other notices to be shown, fall back to this generic one + $notice = array_merge( ( new self() )->getNoticeContents( 'generic' ), $notice ); + } + + if ( ( new self() )->noticeAlreadyDismissed( $notice['name'] ) ) { + return null; + } + + return $notice; + } + + public function noticeAlreadyDismissed( string $notice_name ) : bool { + // don't show if same notice has been dismissed by this user + $current_user_id = get_current_user_id(); + + // query for notice matching name, user id and 'dismissed' action + global $wpdb; + + $table_name = $wpdb->prefix . 'wp2static_notices'; + + $sql = $wpdb->prepare( + "SELECT count(*) FROM $table_name WHERE" . + ' name = %s AND user_id = %s AND action = "dismissed"', + $notice_name, + $current_user_id + ); + + $already_dismissed = $wpdb->get_var( $sql ); + + return $already_dismissed != 0; + } + + /** + * Get notice contents for a specified notice + * + * @return string[] + */ + public function getNoticeContents( string $notice_name ) { + $notice_contents = []; + switch ( $notice_name ) { + case 'generic': + $notice_contents = [ + 'title' => + 'Super charge your static website using Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Enjoy blindingly fast, secure and simple WordPress static hosting, with dozens of dynamic features. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-general', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-general', + ]; + break; + case 'contact-form-7': + $notice_contents = [ + 'title' => + 'Want integrated forms on your static site, out-of-the-box?', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Contact Form 7 on your static site, without implementing any extra configurations. \nGet it, plus secure and simple WordPress static hosting. Start a 14 day free trial today, no credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-forms', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-forms', + ]; + break; + case 'gravity-forms': + $notice_contents = [ + 'title' => + 'Want integrated forms on your static site, out-of-the-box?', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Gravity Forms on your static site, without implementing any extra configurations. \nGet it, plus secure and simple WordPress static hosting. Start a 14 day free trial today, no credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-forms', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-forms', + ]; + break; + case 'wpml': + $notice_contents = [ + 'title' => + 'Create dynamic, multi-lingual static websites using Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use WPML on your static site, without implementing any extra configurations. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-multilingual', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-multilingual', + ]; + break; + case 'polylang': + $notice_contents = [ + 'title' => + 'Create dynamic, multi-lingual static websites using Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Polylang on your static site, without implementing any extra configurations. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-multilingual', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-multilingual', + ]; + break; + case 'elementor-pro': + $notice_contents = [ + 'title' => + 'Get more out of your static website using Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Enjoy fast, secure and simple WordPress static hosting, plus dozens of powerful features, such as integrated support for various Elementor and Elementor Pro features. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-elementor', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-elementor', + ]; + break; + case 'yoast': + $notice_contents = [ + 'title' => + 'Improve the SEO results on your static site with Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Yoast on your static site, without implementing any extra configurations. \nGet fast, secure and simple WordPress static hosting, with dozens of dynamic features like XML sitemaps, search engine pinging, robots.txt support. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-seo', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-seo', + ]; + break; + case 'rankmath': + $notice_contents = [ + 'title' => + 'Improve the SEO results on your static site with Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Rank Math on your static site, without implementing any extra configurations. \nGet fast, secure and simple WordPress static hosting, with dozens of dynamic features like XML sitemaps, search engine pinging, robots.txt support. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-seo', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-seo', + ]; + break; + case 'wp-rocket': + $notice_contents = [ + 'title' => + 'Enhance your static site’s performance with Strattic by Elementor!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you combine WP Rocket with static hosting - giving you blindingly fast, secure and simple WordPress static hosting, with dozens of dynamic features without implementing any extra configurations. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-performance', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-performance', + ]; + break; + case 'redirection': + $notice_contents = [ + 'title' => + 'Redirect visitors between static pages, just like you would on your live site.', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Redirection on your static site, without implementing any extra configurations. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-redirect', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-redirect', + ]; + break; + case 'simple-301-redirects': + $notice_contents = [ + 'title' => + 'Redirect visitors between static pages, just like you would on your live site.', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Strattic by Elementor lets you use Simple 301 Redirects on your static site, without implementing any extra configurations. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-redirect', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-redirect', + ]; + break; + case 'wp2static-addons-installed': + $notice_contents = [ + 'title' => + 'Strattic by Elementor: The simplest way to publish powerful static sites!', + // phpcs:disable Generic.Files.LineLength.MaxExceeded + 'message' => "Enjoy blindingly fast, secure and simple WordPress static hosting, with dozens of dynamic features. \nGet 14 days for free. No credit card required!", + 'primary_button_url' => 'https://link.strattic.com/try-strattic-publish', + 'secondary_button_url' => 'https://link.strattic.com/learn-strattic-publish', + ]; + break; + } + + return $notice_contents; + } +} + diff --git a/src/Controller.php b/src/Controller.php index c1f5bf54..8304487a 100755 --- a/src/Controller.php +++ b/src/Controller.php @@ -109,6 +109,7 @@ public static function activateForSingleSite() : void { DeployCache::createTable(); JobQueue::createTable(); Addons::createTable(); + AdminNotices::createTable(); } public static function activate( bool $network_wide = null ) : void { diff --git a/src/URLHelper.php b/src/URLHelper.php index bf568e1f..7d3742c6 100755 --- a/src/URLHelper.php +++ b/src/URLHelper.php @@ -6,8 +6,9 @@ class URLHelper { public static function isSecure() : bool { - return ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) || - $_SERVER['SERVER_PORT'] == 443; + return ( ! empty( filter_input( INPUT_SERVER, 'HTTPS' ) ) && + filter_input( INPUT_SERVER, 'HTTPS' ) !== 'off' ) || + filter_input( INPUT_SERVER, 'SERVER_PORT' ) == 443; } /* @@ -17,14 +18,14 @@ public static function isSecure() : bool { */ public static function getCurrent() : string { $scheme = self::isSecure() ? 'https' : 'http'; - $url = $scheme . '://' . $_SERVER['HTTP_HOST']; + $url = $scheme . '://' . filter_input( INPUT_SERVER, 'HTTP_HOST' ); // Only include port number if needed - if ( ! in_array( $_SERVER['SERVER_PORT'], [ 80, 443 ] ) ) { - $url .= ':' . $_SERVER['SERVER_PORT']; + if ( ! in_array( filter_input( INPUT_SERVER, 'SERVER_PORT' ), [ 80, 443 ] ) ) { + $url .= ':' . filter_input( INPUT_SERVER, 'SERVER_PORT' ); } - $url .= $_SERVER['REQUEST_URI']; + $url .= filter_input( INPUT_SERVER, 'REQUEST_URI' ); return $url; } diff --git a/src/WordPressAdmin.php b/src/WordPressAdmin.php index d56428d0..86b08111 100755 --- a/src/WordPressAdmin.php +++ b/src/WordPressAdmin.php @@ -341,6 +341,27 @@ public static function registerHooks( string $bootstrap_file ) : void { 10, 2 ); + + add_action( + 'wp_ajax_wp2static_admin_notice_dismissal', + [ AdminNotices::class, 'handleDismissedNotice' ], + 10, + 1 + ); + + // show admin notices on WP2Static pages if rules are met + if ( str_contains( URLHelper::getCurrent(), 'page=wp2static' ) ) { + add_action( + 'admin_notices', + [ AdminNotices::class, 'showAdminNotices' ], + 0 + ); + + add_filter( + 'admin_footer_text', + [ self::class, 'wp2staticAdminFooterText' ] + ); + } } /** @@ -382,7 +403,7 @@ public static function adminPostProcessQueue() : void { Controller::wp2staticProcessQueue(); } - public function wp2staticAdminStyles() : void { + public static function wp2staticAdminStyles() : void { wp_register_style( 'wp2static_admin_styles', plugins_url( '../css/admin/style.css', __FILE__ ), @@ -392,7 +413,7 @@ public function wp2staticAdminStyles() : void { wp_enqueue_style( 'wp2static_admin_styles' ); } - public function wp2staticAdminScripts() : void { + public static function wp2staticAdminScripts() : void { wp_register_script( 'wp2static_admin_scripts', plugins_url( '../js/admin/override-menu-style.js', __FILE__ ), @@ -403,6 +424,14 @@ public function wp2staticAdminScripts() : void { wp_enqueue_script( 'wp2static_admin_scripts' ); } + public static function wp2staticAdminFooterText( string $content ) : string { + return 'Thank you for using ' . + // @phpcs:ignore Generic.Files.LineLength.TooLong + 'WP2Static by ' . + // @phpcs:ignore Generic.Files.LineLength.TooLong + 'Strattic.'; + } + /** * Add extra link to WP2Static's Plugins page entry * @@ -410,10 +439,10 @@ public function wp2staticAdminScripts() : void { * @param string $file path to the plugin's entrypoint * @return mixed[] $links plugin meta links */ - public function wp2staticPluginMetaLinks( $links, $file ) { + public static function wp2staticPluginMetaLinks( $links, $file ) { if ( $file === 'wp2static/wp2static.php' ) { // phpcs:ignore Generic.Files.LineLength.MaxExceeded - $links[] = 'Try 1-Click Publish'; + $links[] = 'Try 1-Click Publish'; } return $links; diff --git a/tools/build_release.sh b/tools/build_release.sh index ac31ea81..8cd63824 100755 --- a/tools/build_release.sh +++ b/tools/build_release.sh @@ -36,6 +36,8 @@ composer install --quiet --no-dev --optimize-autoloader cp -r "$EXEC_DIR"/src "$TMP_DIR"/wp2static/ cp -r "$EXEC_DIR"/vendor "$TMP_DIR"/wp2static/ cp -r "$EXEC_DIR"/views "$TMP_DIR"/wp2static/ +cp -r "$EXEC_DIR"/css "$TMP_DIR"/wp2static/ +cp -r "$EXEC_DIR"/js "$TMP_DIR"/wp2static/ cp -r "$EXEC_DIR"/*.php "$TMP_DIR"/wp2static/ cd "$TMP_DIR" || exit diff --git a/tools/phpcs.xml b/tools/phpcs.xml index b841067b..7ce577fc 100755 --- a/tools/phpcs.xml +++ b/tools/phpcs.xml @@ -2,6 +2,11 @@ WP2Static Project Coding Standard + +