diff --git a/assets/js/src/RedirectionForCF7/index.js b/assets/js/src/RedirectionForCF7/index.js new file mode 100644 index 00000000..45e94ec4 --- /dev/null +++ b/assets/js/src/RedirectionForCF7/index.js @@ -0,0 +1,141 @@ +import {useState} from '@wordpress/element'; +import {Button} from '@wordpress/components'; + +import './style.scss'; +import {activatePlugin, installPluginOrTheme} from "../common/utils"; +import useSettings from "../common/useSettings"; + +export default function RedirectionForCF7({stacked = false, noImage = false, type, onDismiss, onSuccess, initialStatus = null }) { + const { + assets, + title, + email: initialEmail, + option, + optionKey, + labels, + rfCF7ActivationUrl, + cf7Dash, + } = window.themeisleSDKPromotions; + + const [showStatus, setShowStatus] = useState(false); + const [email, setEmail] = useState(initialEmail || ''); + const [dismissed, setDismissed] = useState(false); + const [progress, setProgress] = useState( initialStatus ); + const [getOption, updateOption] = useSettings(); + + const dismissNotice = async () => { + setDismissed(true); + const newValue = {...option}; + newValue[type] = new Date().getTime() / 1000 | 0; + window.themeisleSDKPromotions.option = newValue; + await updateOption(optionKey, JSON.stringify(newValue)); + + if (onDismiss) { + onDismiss(); + } + }; + + const installPluginRequest = async (e) => { + e.preventDefault(); + setShowStatus(true); + setProgress('installing'); + await installPluginOrTheme('wpcf7-redirect'); + + setProgress('activating'); + await activatePlugin(rfCF7ActivationUrl); + + updateOption('themeisle_sdk_promotions_redirection_cf7_installed', !Boolean(getOption('themeisle_sdk_promotions_redirection_cf7_installed'))); + + setProgress('done'); + + } + + if (dismissed) { + return null; + } + + const installPluginRequestStatus = () => { + if (progress === 'done') { + return ( +
+

{labels.redirectionCF7.all_set}

+ +
+ ); + } + + if (progress) { + return ( +

+ + + {progress === 'installing' && labels.redirectionCF7.installing} + {progress === 'activating' && labels.redirectionCF7.activating} + … + +

+ ); + } + }; + + const dismissButton = () => ( + + ); + + + if (stacked) { + return ( +
+
+ {dismissButton()} +

{labels.redirectionCF7.heading}

+ +

{labels.redirectionCF7.message}

+ + {( !showStatus && 'done' !== progress ) && ( + + )} + {( showStatus || 'done' === progress ) && installPluginRequestStatus()} + + {title} +
+
+ ); + } + + return ( + <> + {dismissButton()} +
+
+

{title}

+

{labels.redirectionCF7.message}

+ {!showStatus && ( +
+ + +
+ )} + {showStatus && ( +
+ {installPluginRequestStatus()} +
+ )} +
+
+ + ); +} \ No newline at end of file diff --git a/assets/js/src/RedirectionForCF7/style.scss b/assets/js/src/RedirectionForCF7/style.scss new file mode 100644 index 00000000..9603ca06 --- /dev/null +++ b/assets/js/src/RedirectionForCF7/style.scss @@ -0,0 +1,303 @@ +.ti-redirection-cf7-notice { + --wp-admin-theme-color: #3858E9; + --wp-admin-theme-color-darker-10: #2e47ba; + position: relative; + padding: 0; + border-left-color: #3858E9; + + .content { + background: rgba(255, 255, 255, 0.75); + display: flex; + align-items: center; + padding: 15px 20px; + } + + img { + max-width: 100px; + margin-right: 20px; + display: none; + } + + .description { + font-size: 14px; + margin-bottom: 20px; + color: #000; + } + + .actions { + margin-top: auto; + display: flex; + margin-bottom: 0; + gap: 20px; + } + + form { + display: flex; + align-items: center; + gap: 10px; + } + + .form-wrap { + display: grid; + + span:not(.dashicons) { + margin-bottom: 5px; + font-weight: 500; + } + } + + input { + border-radius: 0; + min-width: 250px; + } + + a.components-button { + display: flex; + align-items: center; + justify-content: center; + } + + .is-link { + text-decoration: none; + display: flex; + align-items: center; + + span { + line-height: normal; + } + } + + .dashicons { + margin-right: 2px; + text-decoration: none; + } + + .done { + display: flex; + flex-direction: column; + align-items: flex-start; + + a { + width: auto; + } + } +} + +@media screen and (min-width: 768px) { + .ti-sdk-rf-cf7-notice { + img { + display: block; + } + } +} + +.compat-field-optimole { + th { + display: none !important; + } + + td { + width: 100% !important; + } + + .ti-sdk-rf-cf7-notice { + margin: 0; + } +} + +.rf-cf7-notice-dismiss { + right: 10px; + top: 10px; + text-decoration: none !important; + position: absolute; + + &:before { + content: none; + } +} + +.ti-rf-cf7-stack-wrap { + .rf-cf7-stack-notice { + --wp-admin-theme-color: #3858E9; + --wp-admin-theme-color-darker-10: #2e47ba; + + display: flex; + flex-direction: column; + align-items: center; + position: relative; + text-align: center; + padding: 20px 10px; + + > span { + display: none; + } + + img { + max-width: 90px !important; + } + + h2 { + font-size: 18px; + margin: 30px auto 10px; + font-weight: 600; + } + + p { + font-size: 13px; + max-width: 250px; + margin: 0 auto; + line-height: 17px; + } + + i { + margin-top: 10px; + font-size: 12px; + color: #757575; + } + + .cta { + margin: 20px auto 0; + padding: 10px 25px !important; + } + + .rf-cf7-notice-dismiss { + color: inherit; + } + + input { + border-radius: 0; + } + + form { + place-items: center; + width: 75%; + display: grid; + margin-top: 10px; + gap: 10px; + } + + .done { + margin-top: 15px; + display: grid; + gap: 10px; + + p { + font-size: 15px; + font-weight: 500; + } + } + + .rf-cf7-progress { + margin: 20px 0; + } + } +} + +.block-editor-block-inspector { + .ti-rf-cf7-stack-wrap { + border-top: 1px solid #e0e0e0; + } +} + + +.rf-cf7-progress { + gap: 5px; + font-size: 14px; + display: flex; + align-items: center; + + .spin { + animation: rf-cf7-rotation 2s infinite linear; + } +} + +@keyframes rf-cf7-rotation { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} + +.ti-sdk-rf-cf7-promo.hidden { + display: none; +} + +.media-sidebar { + .ti-sdk-rf-cf7-notice { + input { + min-width: unset; + flex-grow: 1; + } + + .description { + margin-bottom: 10px; + } + + .content { + padding: 15px 10px; + } + + .actions { + gap: 10px; + } + + form { + flex-wrap: wrap; + justify-content: center; + } + } +} + +.attachment-info { + .ti-sdk-rf-cf7-notice { + input { + min-width: unset; + flex-grow: 1; + } + form { + flex-wrap: wrap; + justify-content: center; + + @media screen and (min-width: 1200px) { + flex-wrap: unset; + } + } + } +} + +.ti-sdk-rop-notice { + position: relative; + padding: 10px; + + .rop-notice-actions { + display: flex; + gap: 10px; + } + + p { + padding: 0 10px 0 0; + } +} +.ti-sdk-neve-fse-notice { + position: relative; + padding: 10px; + + .neve-fse-notice-actions { + display: flex; + gap: 10px; + + a { + text-decoration: none; + span:not(.dashicons) { + text-decoration: underline; + } + } + } + + p { + padding: 0 10px 0 0; + font-size: 14px; + } +} diff --git a/assets/js/src/index.js b/assets/js/src/index.js index d0b4309c..024b74bd 100644 --- a/assets/js/src/index.js +++ b/assets/js/src/index.js @@ -2,3 +2,4 @@ import './otter.js'; import './optimole.js'; import './rop.js'; import './neve-fse.js'; +import './redirection-for-cf7.js'; diff --git a/assets/js/src/redirection-for-cf7.js b/assets/js/src/redirection-for-cf7.js new file mode 100644 index 00000000..c6970d34 --- /dev/null +++ b/assets/js/src/redirection-for-cf7.js @@ -0,0 +1,43 @@ +import {Fragment, render, unmountComponentAtNode, useState} from '@wordpress/element'; +import {registerPlugin,} from '@wordpress/plugins'; +import {PluginPostPublishPanel} from '@wordpress/edit-post'; +import {useSelect} from '@wordpress/data'; +import {createHigherOrderComponent} from '@wordpress/compose'; +import {addFilter} from '@wordpress/hooks'; +import {InspectorControls} from '@wordpress/block-editor'; + +import {getBlocksByType} from "./common/utils"; +import RedirectionForCF7 from "./RedirectionForCF7"; + +class RedirectionForCF7Notice { + constructor() { + const {showPromotion, debug} = window.themeisleSDKPromotions; + this.promo = showPromotion; + this.debug = debug === '1'; + this.domRef = null; + + this.run(); + } + + run() { + if (window.themeisleSDKPromotions.option['redirection-cf7']) { + return; + } + + const root = document.querySelector('#ti-redirection-cf7-notice'); + + if (!root) { + return; + } + + render( + { + root.style.opacity = 0; + }} + />, root); + } +} + +new RedirectionForCF7Notice(); \ No newline at end of file diff --git a/composer.json b/composer.json index 3efa502c..fdae78a6 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,8 @@ "codeinwp/phpcs-ruleset": "dev-main" }, "scripts": { - "format": "phpcbf --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 5.6- ", - "phpcs": "phpcs --standard=phpcs.xml -s --runtime-set testVersion 5.6-", + "format": "phpcbf --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 7.2- ", + "phpcs": "phpcs --standard=phpcs.xml -s --runtime-set testVersion 7.2-", "lint": "composer run-script phpcs" }, "support": { diff --git a/src/Loader.php b/src/Loader.php index f83d924c..a5eabc8b 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -114,8 +114,8 @@ final class Loader { 'no_activations' => 'No more activations left for %s. You need to upgrade your plan in order to use %s on more websites. If you need assistance, please get in touch with %s staff.', ], 'promotions' => [ - 'recommended' => 'Recommended by %s', - 'woo' => [ + 'recommended' => 'Recommended by %s', + 'woo' => [ 'title' => 'More extensions from Themeisle', 'title2' => 'Recommended extensions', 'cta_install' => 'Install', @@ -130,7 +130,7 @@ final class Loader { 'spark_desc2' => 'Add a top notification bar on your website to highlight the latest products, offers, or upcoming events.', 'spark_desc3' => 'Enable an advanced review section, enlarging the basic review options with lots of capabilities.', ], - 'optimole' => [ + 'optimole' => [ 'all_set' => 'Awesome! You are all set!', 'gotodash' => 'Go to Optimole dashboard', 'installing' => 'Installing', @@ -147,6 +147,16 @@ final class Loader { 'message2' => 'Leverage Optimole\'s full integration with Elementor to automatically lazyload, resize, compress to AVIF/WebP and deliver from 400 locations around the globe!', 'email_placeholder' => 'Email address', ], + 'redirection_cf7' => [ + 'all_set' => 'Awesome! You are all set!', + 'gotodash' => 'Go to Contact Forms', + 'installing' => 'Installing', + 'activating' => 'Activating', + 'dismisscta' => 'Dismiss this notice.', + 'gst' => 'Get Started Free', + 'learnmore' => 'Learn more', + 'message' => 'Add URL redirects, spam protection, execute JavaScript after submissions, and more with the Redirection for CF7 free plugin.', + ], ], 'welcome' => [ 'ctan' => 'No, thanks.', diff --git a/src/Modules/Promotions.php b/src/Modules/Promotions.php index 08802a68..d58e2ddc 100644 --- a/src/Modules/Promotions.php +++ b/src/Modules/Promotions.php @@ -77,6 +77,13 @@ class Promotions extends Abstract_Module { */ private $option_neve_fse = 'themeisle_sdk_promotions_neve_fse_installed'; + /** + * Option key for Redirection for CF7. + * + * @var string + */ + private $option_redirection_cf7 = 'themeisle_sdk_promotions_redirection_cf7_installed'; + /** * Loaded promotion. * @@ -120,6 +127,9 @@ public function can_load( $product ) { $promotions_to_load[] = 'rop'; $promotions_to_load[] = 'woo_plugins'; $promotions_to_load[] = 'neve-fse'; + $promotions_to_load[] = 'redirection-cf7'; + + $promotions_to_load = array_unique( $promotions_to_load ); $promotions_to_load = array_unique( $promotions_to_load ); @@ -274,6 +284,16 @@ public function register_settings() { 'default' => false, ) ); + register_setting( + 'themeisle_sdk_settings', + $this->option_redirection_cf7, + array( + 'type' => 'boolean', + 'sanitize_callback' => 'rest_sanitize_boolean', + 'show_in_rest' => true, + 'default' => false, + ) + ); } /** @@ -316,24 +336,26 @@ private function has_conflicts() { * @return array */ private function get_promotions() { - $has_otter = defined( 'OTTER_BLOCKS_VERSION' ) || $this->is_plugin_installed( 'otter-blocks' ); - $had_otter_from_promo = get_option( $this->option_otter, false ); - $has_optimole = defined( 'OPTIMOLE_VERSION' ) || $this->is_plugin_installed( 'optimole-wp' ); - $had_optimole_from_promo = get_option( $this->option_optimole, false ); - $has_rop = defined( 'ROP_LITE_VERSION' ) || $this->is_plugin_installed( 'tweet-old-post' ); - $had_rop_from_promo = get_option( $this->option_rop, false ); - $has_woocommerce = class_exists( 'WooCommerce' ); - $has_sparks = defined( 'SPARKS_WC_VERSION' ) || $this->is_plugin_installed( 'sparks-for-woocommerce' ); - $has_ppom = defined( 'PPOM_VERSION' ) || $this->is_plugin_installed( 'woocommerce-product-addon' ); - $is_min_req_v = version_compare( get_bloginfo( 'version' ), '5.8', '>=' ); - $is_min_fse_v = version_compare( get_bloginfo( 'version' ), '6.2', '>=' ); - $current_theme = wp_get_theme(); - $has_neve_fse = $current_theme->template === 'neve-fse' || $current_theme->parent() === 'neve-fse'; - $has_enough_attachments = $this->has_min_media_attachments(); - $has_enough_old_posts = $this->has_old_posts(); + $has_otter = defined( 'OTTER_BLOCKS_VERSION' ) || $this->is_plugin_installed( 'otter-blocks' ); + $had_otter_from_promo = get_option( $this->option_otter, false ); + $has_optimole = defined( 'OPTIMOLE_VERSION' ) || $this->is_plugin_installed( 'optimole-wp' ); + $had_optimole_from_promo = get_option( $this->option_optimole, false ); + $has_rop = defined( 'ROP_LITE_VERSION' ) || $this->is_plugin_installed( 'tweet-old-post' ); + $had_rop_from_promo = get_option( $this->option_rop, false ); + $has_woocommerce = class_exists( 'WooCommerce' ); + $has_sparks = defined( 'SPARKS_WC_VERSION' ) || $this->is_plugin_installed( 'sparks-for-woocommerce' ); + $has_ppom = defined( 'PPOM_VERSION' ) || $this->is_plugin_installed( 'woocommerce-product-addon' ); + $has_redirection_cf7 = defined( 'OPTIMOLE_VERSION' ) || $this->is_plugin_installed( 'optimole-wp' ); + $had_redirection_cf7_promo = get_option( $this->option_optimole, false ); + $is_min_req_v = version_compare( get_bloginfo( 'version' ), '5.8', '>=' ); + $is_min_fse_v = version_compare( get_bloginfo( 'version' ), '6.2', '>=' ); + $current_theme = wp_get_theme(); + $has_neve_fse = $current_theme->template === 'neve-fse' || $current_theme->parent() === 'neve-fse'; + $has_enough_attachments = $this->has_min_media_attachments(); + $has_enough_old_posts = $this->has_old_posts(); $all = [ - 'optimole' => [ + 'optimole' => [ 'om-editor' => [ 'env' => ! $has_optimole && $is_min_req_v && ! $had_optimole_from_promo, 'screen' => 'editor', @@ -355,7 +377,7 @@ private function get_promotions() { 'screen' => 'elementor', ], ], - 'otter' => [ + 'otter' => [ 'blocks-css' => [ 'env' => ! $has_otter && $is_min_req_v && ! $had_otter_from_promo, 'screen' => 'editor', @@ -369,13 +391,13 @@ private function get_promotions() { 'screen' => 'editor', ], ], - 'rop' => [ + 'rop' => [ 'rop-posts' => [ 'env' => ! $has_rop && ! $had_rop_from_promo && $has_enough_old_posts, 'screen' => 'edit-post', ], ], - 'woo_plugins' => [ + 'woo_plugins' => [ 'ppom' => [ 'env' => ! $has_ppom && $has_woocommerce, 'screen' => 'edit-product', @@ -393,12 +415,18 @@ private function get_promotions() { 'screen' => 'edit-product', ], ], - 'neve-fse' => [ + 'neve-fse' => [ 'neve-fse-themes-popular' => [ 'env' => ! $has_neve_fse && $is_min_fse_v, 'screen' => 'themes-install-popular', ], ], + 'redirection-cf7' => [ + 'wpcf7' => [ + 'env' => ! $has_redirection_cf7 && ! $had_redirection_cf7_promo, + 'screen' => 'wpcf7', + ], + ], ]; foreach ( $all as $slug => $data ) { @@ -473,6 +501,7 @@ private function filter_by_screen_and_merge() { $is_editor = method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor(); $is_theme_install = isset( $current_screen->id ) && ( $current_screen->id === 'theme-install' || $current_screen->id === 'themes' ); $is_product = isset( $current_screen->id ) && $current_screen->id === 'product'; + $is_cf7_install = isset( $current_screen->id ) && function_exists( 'str_contains' ) ? str_contains( $current_screen->id, 'page_wpcf7' ) : false; $return = []; @@ -514,6 +543,11 @@ private function filter_by_screen_and_merge() { unset( $this->promotions[ $slug ][ $key ] ); } break; + case 'wpcf7': + if ( ! $is_cf7_install ) { + unset( $this->promotions[ $slug ][ $key ] ); + } + break; } } @@ -551,6 +585,9 @@ private function load_promotion( $slug ) { if ( $this->get_upsells_dismiss_time( 'neve-fse-themes-popular' ) === false ) { add_action( 'admin_notices', [ $this, 'render_neve_fse_themes_notice' ] ); } + if ( $this->get_upsells_dismiss_time( 'redirection-cf7' ) === false ) { + add_action( 'admin_notices', [ $this, 'render_redirection_cf7_notice' ] ); + } $this->load_woo_promos(); @@ -598,6 +635,10 @@ private function load_promotion( $slug ) { add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] ); add_action( 'admin_notices', [ $this, 'render_neve_fse_themes_notice' ] ); break; + case 'wpcf7': + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] ); + add_action( 'admin_notices', [ $this, 'render_redirection_cf7_notice' ] ); + break; } } @@ -633,7 +674,8 @@ public function enqueue() { [ 'debug' => $this->debug, 'labels' => [ - 'optimole' => Loader::$labels['promotions']['optimole'], + 'optimole' => Loader::$labels['promotions']['optimole'], + 'redirectionCF7' => Loader::$labels['promotions']['redirection_cf7'], ], 'email' => $user->user_email, 'showPromotion' => $this->loaded_promo, @@ -651,6 +693,9 @@ public function enqueue() { 'neveFSEMoreUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve-fse/', 'neve-fse-themes-popular', 'theme-install' ), // translators: %s is the product name. 'title' => esc_html( sprintf( Loader::$labels['promotions']['recommended'], $this->product->get_name() ) ), + 'redirectionCF7MoreUrl' => tsdk_utmify( 'https://docs.themeisle.com/collection/2014-redirection-for-contact-form-7', 'redirection-for-contact-form-7', 'plugin-install' ), + 'rfCF7ActivationUrl' => $this->get_plugin_activation_link( 'wpcf7-redirect' ), + 'cf7Dash' => esc_url( add_query_arg( [ 'page' => 'wpcf7-new' ], admin_url( 'admin.php' ) ) ), ] ); wp_enqueue_script( $handle ); @@ -677,6 +722,13 @@ public function render_neve_fse_themes_notice() { echo '
'; } + /** + * Render Redirection for CF7 notice. + */ + public function render_redirection_cf7_notice() { + echo '
'; + } + /** * Add promo to attachment modal. *