PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.8
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | vendor/codeinwp/themeisle-sdk/src/Modules/Promotions.php +65 -598 4.0.43.11.8 View file →
@@ -31,9 +31,9 @@
31 31 * Holds the promotions.
32 32 *
33 33 * @var array
34 34 */
35 - public $promotions = array();
35 + private $promotions = array();
36 36
37 37 /**
38 38 * Holds the values of the promotions that are not allowed to be shown.
39 39 * Can be filtered by each product.
@@ -98,22 +98,8 @@
98 98 */
99 99 private $option_wp_full_pay = 'themeisle_sdk_promotions_wp_full_pay_installed';
100 100
101 101 /**
102 - * Option key for Feedzy.
103 - *
104 - * @var string
105 - */
106 - private $option_feedzy = 'themeisle_sdk_promotions_feedzy_installed';
107 -
108 - /**
109 - * Option key for Masteriyo promos.
110 - *
111 - * @var string
112 - */
113 - private $option_masteriyo = 'themeisle_sdk_promotions_masteriyo_installed';
114 -
115 - /**
116 102 * Loaded promotion.
117 103 *
118 104 * @var string
119 105 */
@@ -147,11 +133,10 @@
147 133 if ( $this->is_from_partner( $product ) ) {
148 134 return false;
149 135 }
150 136
151 - $this->debug = apply_filters( 'themeisle_sdk_promo_debug', $this->debug );
152 - $promotions_to_load = apply_filters( $product->get_key() . '_load_promotions', array() );
153 -
137 + $this->debug = apply_filters( 'themeisle_sdk_promo_debug', $this->debug );
138 + $promotions_to_load = apply_filters( $product->get_key() . '_load_promotions', array() );
154 139 $promotions_to_load[] = 'optimole';
155 140 $promotions_to_load[] = 'rop';
156 141 $promotions_to_load[] = 'woo_plugins';
157 142 $promotions_to_load[] = 'neve';
@@ -157,14 +142,9 @@
157 142 $promotions_to_load[] = 'neve';
158 143 $promotions_to_load[] = 'redirection-cf7';
159 144 $promotions_to_load[] = 'hyve';
160 145 $promotions_to_load[] = 'wp_full_pay';
161 - $promotions_to_load[] = 'feedzy_import';
162 - $promotions_to_load[] = 'learning-management-system';
163 146
164 - if ( defined( 'NEVE_VERSION' ) || defined( 'WPMM_PATH' ) || defined( 'OTTER_BLOCKS_VERSION' ) || defined( 'OBFX_URL' ) ) {
165 - $promotions_to_load[] = 'feedzy_embed';
166 - }
167 147 $promotions_to_load = array_unique( $promotions_to_load );
168 148
169 149 $this->promotions = $this->get_promotions();
170 150
@@ -174,8 +154,9 @@
174 154 if ( ! in_array( $slug, $promotions_to_load, true ) ) {
175 155 unset( $this->promotions[ $slug ] );
176 156 }
177 157 }
158 +
178 159 add_action( 'init', array( $this, 'register_settings' ), 99 );
179 160 add_action( 'admin_init', array( $this, 'register_reference' ), 99 );
180 161
181 162 return ! empty( $this->promotions );
@@ -201,216 +182,17 @@
201 182
202 183 add_filter( 'attachment_fields_to_edit', array( $this, 'add_attachment_field' ), 10, 2 );
203 184 add_action( 'current_screen', [ $this, 'load_available' ] );
204 185 add_action( 'elementor/editor/after_enqueue_scripts', array( $this, 'enqueue' ) );
205 - add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_visualizer_block_editor_shim' ), 100 );
206 186 add_action( 'wp_ajax_tisdk_update_option', array( $this, 'dismiss_promotion' ) );
207 - add_filter( 'plugins_api_result', array( $this, 'inject_visualizer_block_directory_suggestion' ), 10, 3 );
208 - add_filter( 'option_visualizer-activated', array( $this, 'suppress_visualizer_onboarding_in_editor' ) );
209 187 add_filter( 'themeisle_sdk_ran_promos', '__return_true' );
210 188
211 189 if ( get_option( $this->option_neve, false ) !== true ) {
212 - add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', 'ThemeisleSDK\Modules\Notification::dismiss' );
190 + add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', 'ThemeisleSDK\Modules\Notification::regular_dismiss' );
213 191 }
214 192 }
215 193
216 -
217 194 /**
218 - * Inject Visualizer as the first block-directory suggestion for chart queries.
219 - *
220 - * @param object|WP_Error $res Response object or WP_Error.
221 - * @param string $action The API action.
222 - * @param object $args The API arguments.
223 - * @return object|WP_Error
224 - */
225 - public function inject_visualizer_block_directory_suggestion( $res, $action, $args ) {
226 - if ( 'query_plugins' !== $action || ! is_object( $args ) || empty( $args->block ) ) {
227 - return $res;
228 - }
229 -
230 - if ( ! $this->should_suggest_visualizer( $args->block ) ) {
231 - return $res;
232 - }
233 -
234 - if ( $this->is_plugin_installed( 'visualizer' ) ) {
235 - return $res;
236 - }
237 -
238 - $plugin = $this->get_visualizer_block_directory_data();
239 - if ( empty( $plugin ) ) {
240 - return $res;
241 - }
242 -
243 - if ( is_wp_error( $res ) ) {
244 - $res = (object) array( 'plugins' => array() );
245 - }
246 -
247 - if ( ! isset( $res->plugins ) || ! is_array( $res->plugins ) ) {
248 - $res->plugins = array();
249 - }
250 -
251 - $res->plugins = array_values(
252 - array_filter(
253 - $res->plugins,
254 - function ( $existing ) use ( $plugin ) {
255 - return ! isset( $existing['slug'] ) || $existing['slug'] !== $plugin['slug'];
256 - }
257 - )
258 - );
259 -
260 - array_unshift( $res->plugins, $plugin );
261 -
262 - return $res;
263 - }
264 -
265 - /**
266 - * Check if the query should trigger the Visualizer suggestion.
267 - *
268 - * @param string $term Search term.
269 - * @return bool
270 - */
271 - private function should_suggest_visualizer( $term ) {
272 - $term = strtolower( (string) $term );
273 - return false !== strpos( $term, 'chart' ) || false !== strpos( $term, 'visualizer' ) || false !== strpos( $term, 'visualization' ) || false !== strpos( $term, 'graph' );
274 - }
275 -
276 - /**
277 - * Build the plugin data for Visualizer block directory results.
278 - *
279 - * @return array
280 - */
281 - private function get_visualizer_block_directory_data() {
282 - $slug = 'visualizer';
283 - $plugin_info = $this->call_plugin_api( $slug );
284 -
285 - if ( is_wp_error( $plugin_info ) || empty( $plugin_info ) ) {
286 - return array();
287 - }
288 -
289 - $icons = array();
290 - if ( ! empty( $plugin_info->icons ) ) {
291 - if ( ! empty( $plugin_info->icons['1x'] ) ) {
292 - $icons['1x'] = $plugin_info->icons['1x'];
293 - }
294 - if ( ! empty( $plugin_info->icons['2x'] ) ) {
295 - $icons['2x'] = $plugin_info->icons['2x'];
296 - }
297 - }
298 -
299 - $name = isset( $plugin_info->name ) ? $plugin_info->name : 'Visualizer';
300 -
301 - return array(
302 - 'slug' => $slug,
303 - 'name' => $name,
304 - 'short_description' => isset( $plugin_info->short_description ) ? $plugin_info->short_description : '',
305 - 'author' => isset( $plugin_info->author ) ? wp_strip_all_tags( $plugin_info->author ) : '',
306 - 'rating' => isset( $plugin_info->rating ) ? (int) $plugin_info->rating : 0,
307 - 'num_ratings' => isset( $plugin_info->num_ratings ) ? (int) $plugin_info->num_ratings : 0,
308 - 'active_installs' => isset( $plugin_info->active_installs ) ? (int) $plugin_info->active_installs : 0,
309 - 'author_block_rating' => isset( $plugin_info->author_block_rating ) ? (int) $plugin_info->author_block_rating : 0,
310 - 'author_block_count' => isset( $plugin_info->author_block_count ) ? (int) $plugin_info->author_block_count : 0,
311 - 'icons' => $icons,
312 - 'last_updated' => isset( $plugin_info->last_updated ) ? $plugin_info->last_updated : gmdate( 'Y-m-d H:i:s' ),
313 - 'blocks' => array(
314 - array(
315 - 'name' => 'visualizer/chart',
316 - 'title' => $name,
317 - ),
318 - ),
319 - );
320 - }
321 -
322 -
323 - /**
324 - * Prevent Visualizer onboarding redirects while in the block editor.
325 - *
326 - * @param mixed $value Option value.
327 - * @return mixed
328 - */
329 - public function suppress_visualizer_onboarding_in_editor( $value ) {
330 - if ( ! $this->is_block_editor_screen() ) {
331 - return $value;
332 - }
333 -
334 - return false;
335 - }
336 -
337 - /**
338 - * Add a small compatibility shim for Visualizer's block editor bundle.
339 - *
340 - * Visualizer's "Display an existing chart" flow reads
341 - * `google.visualization.Version` before the Google Charts loader has fully
342 - * populated `google.visualization`, which can throw after dynamic install.
343 - *
344 - * @return void
345 - */
346 - public function enqueue_visualizer_block_editor_shim() {
347 - global $themeisle_sdk_max_version;
348 -
349 - if ( ! $this->is_block_editor_screen() ) {
350 - return;
351 - }
352 -
353 - if ( ! wp_script_is( 'visualizer-gutenberg-block', 'enqueued' ) ) {
354 - return;
355 - }
356 -
357 - wp_register_script(
358 - 'ti-sdk-visualizer-editor-shim',
359 - '',
360 - array(),
361 - $themeisle_sdk_max_version,
362 - true
363 - );
364 - wp_enqueue_script( 'ti-sdk-visualizer-editor-shim' );
365 - wp_add_inline_script(
366 - 'ti-sdk-visualizer-editor-shim',
367 - 'window.google = window.google || {}; window.google.visualization = window.google.visualization || {}; window.google.visualization.Version = window.google.visualization.Version || "current";'
368 - );
369 - }
370 -
371 - /**
372 - * Check if the current admin screen is the block editor.
373 - *
374 - * @return bool
375 - */
376 - private function is_block_editor_screen() {
377 - if ( ! function_exists( 'get_current_screen' ) ) {
378 - return $this->is_block_editor_request();
379 - }
380 -
381 - $screen = get_current_screen();
382 - if ( is_object( $screen ) && method_exists( $screen, 'is_block_editor' ) && $screen->is_block_editor() ) {
383 - return true;
384 - }
385 -
386 - return $this->is_block_editor_request();
387 - }
388 -
389 - /**
390 - * Detect block editor requests before the current screen is available.
391 - *
392 - * @return bool
393 - */
394 - private function is_block_editor_request() {
395 - global $pagenow;
396 -
397 - if ( 'post-new.php' === $pagenow ) {
398 - $post_type = isset( $_GET['post_type'] ) ? sanitize_key( $_GET['post_type'] ) : 'post';
399 -
400 - return function_exists( 'use_block_editor_for_post_type' ) ? use_block_editor_for_post_type( $post_type ) : true;
401 - }
402 -
403 - if ( 'post.php' === $pagenow && isset( $_GET['post'] ) ) {
404 - $post_id = absint( $_GET['post'] );
405 -
406 - return function_exists( 'use_block_editor_for_post' ) ? use_block_editor_for_post( $post_id ) : true;
407 - }
408 -
409 - return false;
410 - }
411 -
412 - /**
413 195 * Load available promotions.
414 196 */
415 197 public function load_available() {
416 198 $this->promotions = $this->filter_by_screen_and_merge();
@@ -463,13 +245,8 @@
463 245
464 246 if ( isset( $_GET['wp_full_pay_reference_key'] ) ) {
465 247 update_option( 'wp_full_pay_reference_key', sanitize_key( $_GET['wp_full_pay_reference_key'] ) );
466 248 }
467 -
468 - if ( isset( $_GET['feedzy_reference_key'] ) || ( isset( $_GET['from'], $_GET['plugin'] ) && $_GET['from'] === 'import' && str_starts_with( sanitize_key( $_GET['plugin'] ), 'feedzy' ) ) ) {
469 - update_option( 'feedzy_reference_key', sanitize_key( $_GET['feedzy_reference_key'] ?? 'i-' . $this->product->get_key() ) );
470 - update_option( $this->option_feedzy, 1 );
471 - }
472 249 }
473 250
474 251 /**
475 252 * Register Settings
@@ -557,18 +334,8 @@
557 334 'show_in_rest' => true,
558 335 'default' => false,
559 336 )
560 337 );
561 - register_setting(
562 - 'themeisle_sdk_settings',
563 - $this->option_masteriyo,
564 - array(
565 - 'type' => 'boolean',
566 - 'sanitize_callback' => 'rest_sanitize_boolean',
567 - 'show_in_rest' => true,
568 - 'default' => false,
569 - )
570 - );
571 338 }
572 339
573 340 /**
574 341 * Check if the path is writable.
@@ -620,17 +387,13 @@
620 387 $has_sparks = defined( 'SPARKS_WC_VERSION' ) || $this->is_plugin_installed( 'sparks-for-woocommerce' );
621 388 $has_ppom = defined( 'PPOM_VERSION' ) || $this->is_plugin_installed( 'woocommerce-product-addon' );
622 389 $has_redirection_cf7 = defined( 'WPCF7_PRO_REDIRECT_PLUGIN_VERSION' ) || $this->is_plugin_installed( 'wpcf7-redirect' );
623 390 $had_redirection_cf7_promo = get_option( $this->option_redirection_cf7, false );
624 - $is_min_php_7_4 = version_compare( PHP_VERSION, '7.4', '>=' );
625 - $is_min_php_7_2 = version_compare( PHP_VERSION, '7.2', '>=' );
626 - $can_check_plugin_install = $this->can_check_plugin_install_promo();
627 391 $has_hyve = defined( 'HYVE_LITE_VERSION' ) || $this->is_plugin_installed( 'hyve' ) || $this->is_plugin_installed( 'hyve-lite' );
628 392 $had_hyve_from_promo = get_option( $this->option_hyve, false );
629 - $has_hyve_conditions = $is_min_php_7_4 && ! $has_hyve && ! $had_hyve_from_promo && version_compare( get_bloginfo( 'version' ), '6.2', '>=' ) && $can_check_plugin_install && $this->has_support_page();
393 + $has_hyve_conditions = version_compare( get_bloginfo( 'version' ), '6.2', '>=' ) && $this->has_support_page();
630 394 $has_wfp_full_pay = defined( 'WP_FULL_STRIPE_BASENAME' ) || $this->is_plugin_installed( 'wp-full-stripe-free' );
631 395 $had_wfp_from_promo = get_option( $this->option_wp_full_pay, false );
632 - $has_wfp_conditions = ! $has_wfp_full_pay && ! $had_wfp_from_promo && $can_check_plugin_install && $this->has_donate_page();
633 396 $is_min_req_v = version_compare( get_bloginfo( 'version' ), '5.8', '>=' );
634 397 $current_theme = wp_get_theme();
635 398 $has_neve = $current_theme->template === 'neve' || $current_theme->parent() === 'neve';
636 399 $has_neve_from_promo = get_option( $this->option_neve, false );
@@ -635,15 +398,12 @@
635 398 $has_neve = $current_theme->template === 'neve' || $current_theme->parent() === 'neve';
636 399 $has_neve_from_promo = get_option( $this->option_neve, false );
637 400 $has_enough_attachments = $this->has_min_media_attachments();
638 401 $has_enough_old_posts = $this->has_old_posts();
639 - $has_feedzy = defined( 'FEEDZY_BASEFILE' ) || $this->is_plugin_installed( 'feedzy-rss-feedss' );
640 - $had_feedzy_from_promo = get_option( $this->option_feedzy, false );
641 - $had_masteriyo_from_promo = get_option( $this->option_masteriyo, false );
642 - $has_masteriyo_conditions = $is_min_php_7_2 && ! $had_masteriyo_from_promo && ! $this->has_active_lms_plugin() && $can_check_plugin_install && $this->has_lms_tagline();
402 + $is_min_php_8_1 = version_compare( PHP_VERSION, '8.1', '>=' );
643 403
644 404 $all = [
645 - 'optimole' => [
405 + 'optimole' => [
646 406 'om-editor' => [
647 407 'env' => ! $has_optimole && $is_min_req_v && ! $had_optimole_from_promo,
648 408 'screen' => 'editor',
649 409 'delayed' => true,
@@ -666,22 +426,9 @@
666 426 'screen' => 'elementor',
667 427 'delayed' => true,
668 428 ],
669 429 ],
670 - 'feedzy_import' => [
671 - 'feedzy-import' => [
672 - 'env' => true,
673 - 'screen' => 'import',
674 - 'always' => true,
675 - ],
676 - ],
677 - 'feedzy_embed' => [
678 - 'feedzy-editor' => [
679 - 'env' => ! $has_feedzy && is_main_site() && ! $had_feedzy_from_promo,
680 - 'screen' => 'editor',
681 - ],
682 - ],
683 - 'otter' => [
430 + 'otter' => [
684 431 'blocks-css' => [
685 432 'env' => ! $has_otter && $is_min_req_v && ! $had_otter_from_promo,
686 433 'screen' => 'editor',
687 434 'delayed' => true,
@@ -696,9 +443,9 @@
696 443 'screen' => 'editor',
697 444 'delayed' => true,
698 445 ],
699 446 ],
700 - 'rop' => [
447 + 'rop' => [
701 448 'rop-posts' => [
702 449 'env' => ! $has_rop && ! $had_rop_from_promo && $has_enough_old_posts,
703 450 'screen' => 'edit-post',
704 451 'delayed' => true,
@@ -703,9 +450,9 @@
703 450 'screen' => 'edit-post',
704 451 'delayed' => true,
705 452 ],
706 453 ],
707 - 'woo_plugins' => [
454 + 'woo_plugins' => [
708 455 'ppom' => [
709 456 'env' => ! $has_ppom && $has_woocommerce,
710 457 'screen' => 'edit-product',
711 458 ],
@@ -721,15 +468,15 @@
721 468 'env' => ! $has_sparks && $has_woocommerce,
722 469 'screen' => 'edit-product',
723 470 ],
724 471 ],
725 - 'neve' => [
472 + 'neve' => [
726 473 'neve-themes-popular' => [
727 474 'env' => ! $has_neve && ! $has_neve_from_promo,
728 475 'screen' => 'themes-install-popular',
729 476 ],
730 477 ],
731 - 'redirection-cf7' => [
478 + 'redirection-cf7' => [
732 479 'wpcf7' => [
733 480 'env' => ! $has_redirection_cf7 && ! $had_redirection_cf7_promo,
734 481 'screen' => 'wpcf7',
735 482 'delayed' => true,
@@ -734,26 +481,20 @@
734 481 'screen' => 'wpcf7',
735 482 'delayed' => true,
736 483 ],
737 484 ],
738 - 'hyve' => [
485 + 'hyve' => [
739 486 'hyve-plugins-install' => [
740 - 'env' => $has_hyve_conditions,
487 + 'env' => $is_min_php_8_1 && ! $has_hyve && ! $had_hyve_from_promo && $has_hyve_conditions,
741 488 'screen' => 'plugin-install',
742 489 ],
743 490 ],
744 - 'wp_full_pay' => [
491 + 'wp_full_pay' => [
745 492 'wp-full-pay-plugins-install' => [
746 - 'env' => $has_wfp_conditions,
493 + 'env' => ! $has_wfp_full_pay && ! $had_wfp_from_promo,
747 494 'screen' => 'plugin-install',
748 495 ],
749 496 ],
750 - 'learning-management-system' => [
751 - 'masteriyo-plugins-install' => [
752 - 'env' => $has_masteriyo_conditions,
753 - 'screen' => 'plugin-install',
754 - ],
755 - ],
756 497 ];
757 498
758 499 foreach ( $all as $slug => $data ) {
759 500 foreach ( $data as $key => $conditions ) {
@@ -771,8 +512,9 @@
771 512 if ( empty( $all[ $slug ] ) ) {
772 513 unset( $all[ $slug ] );
773 514 }
774 515 }
516 +
775 517 return $all;
776 518 }
777 519
778 520 /**
@@ -820,38 +562,33 @@
820 562 $is_editor = method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor();
821 563 $is_theme_install = isset( $current_screen->id ) && ( $current_screen->id === 'theme-install' );
822 564 $is_plugin_install = isset( $current_screen->id ) && ( $current_screen->id === 'plugin-install' );
823 565 $is_product = isset( $current_screen->id ) && $current_screen->id === 'product';
824 - $is_import = isset( $current_screen->id ) && $current_screen->id === 'import';
825 566 $is_cf7_install = isset( $current_screen->id ) && function_exists( 'str_contains' ) ? str_contains( $current_screen->id, 'page_wpcf7' ) : false;
826 567
827 - $return = [];
568 + $return = [];
569 +
828 570 $product_install_time = (int) $this->product->get_install_time();
829 571 $is_older = time() > ( $product_install_time + ( 3 * DAY_IN_SECONDS ) );
830 572 $is_newer = time() < ( $product_install_time + ( 6 * HOUR_IN_SECONDS ) );
573 +
831 574 foreach ( $this->promotions as $slug => $promos ) {
832 575 foreach ( $promos as $key => $data ) {
833 576
834 - $data = wp_parse_args(
835 - $data,
836 - [
837 - 'delayed' => false,
838 - 'always' => false,
839 - ]
840 - );
577 + $data = wp_parse_args( $data, [ 'delayed' => false ] );
841 578
842 579 if (
843 - ! $this->debug &&
580 + ! $this->debug &&
844 581 (
845 582 ( $data['delayed'] === true && ! $is_older ) || // Skip promotions that are delayed for 3 days.
846 583 $is_newer // Skip promotions for the first 6 hours after install.
847 584 )
848 - && ! $data['always']
849 585 ) {
850 586 unset( $this->promotions[ $slug ][ $key ] );
851 587
852 588 continue;
853 589 }
590 +
854 591 switch ( $data['screen'] ) {
855 592 case 'media-editor':
856 593 if ( ! $is_media && ! $is_editor ) {
857 594 unset( $this->promotions[ $slug ][ $key ] );
@@ -866,13 +603,8 @@
866 603 if ( ! $is_editor || $is_elementor ) {
867 604 unset( $this->promotions[ $slug ][ $key ] );
868 605 }
869 606 break;
870 - case 'import':
871 - if ( ! $is_import ) {
872 - unset( $this->promotions[ $slug ][ $key ] );
873 - }
874 - break;
875 607 case 'elementor':
876 608 if ( ! $is_elementor ) {
877 609 unset( $this->promotions[ $slug ][ $key ] );
878 610 }
@@ -949,17 +681,13 @@
949 681 if ( $this->get_upsells_dismiss_time( 'wp-full-pay-plugins-install' ) === false ) {
950 682 add_action( 'admin_notices', [ $this, 'render_wp_full_pay_notice' ] );
951 683 }
952 684
953 - if ( $this->get_upsells_dismiss_time( 'masteriyo-plugins-install' ) === false ) {
954 - add_action( 'admin_notices', [ $this, 'render_masteriyo_notice' ] );
955 - }
956 -
957 - add_action( 'load-import.php', [ $this, 'add_import' ] );
958 685 $this->load_woo_promos();
959 686
960 687 return;
961 688 }
689 +
962 690 switch ( $slug ) {
963 691 case 'om-editor':
964 692 case 'om-image-block':
965 693 case 'blocks-css':
@@ -977,15 +705,8 @@
977 705 case 'rop-posts':
978 706 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
979 707 add_action( 'admin_notices', [ $this, 'render_rop_dash_notice' ] );
980 708 break;
981 - case 'feedzy-import':
982 - add_action( 'load-import.php', [ $this, 'add_import' ] );
983 -
984 - break;
985 - case 'feedzy-editor':
986 - add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue' ] );
987 - break;
988 709 case 'ppom':
989 710 case 'sparks-wishlist':
990 711 case 'sparks-announcement':
991 712 case 'sparks-product-reviews':
@@ -1018,35 +739,12 @@
1018 739 case 'wp-full-pay-plugins-install':
1019 740 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
1020 741 add_action( 'admin_notices', [ $this, 'render_wp_full_pay_notice' ] );
1021 742 break;
1022 - case 'masteriyo-plugins-install':
1023 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
1024 - add_action( 'admin_notices', [ $this, 'render_masteriyo_notice' ] );
1025 - break;
1026 743 }
1027 744 }
1028 745
1029 746 /**
1030 - * Add import row.
1031 - *
1032 - * @return void
1033 - */
1034 - public function add_import() {
1035 - global $wp_importers;
1036 - if ( isset( $wp_importers['feedzy-rss-feeds'] ) ) {
1037 - return;
1038 - }
1039 - $wp_importers['feedzy-rss-feeds'] = array( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1040 - 'Feedzy',
1041 - sprintf( Loader::$labels['promotions']['feedzy']['import_desc'], '<span style="float: left; font-style: italic;margin-top:0.4em;">', $this->product->get_friendly_name(), '</span>' ),
1042 - 'install' => 'feedzy-rss-feeds',
1043 - );
1044 - if ( defined( 'FEEDZY_BASEFILE' ) ) {
1045 - unset( $wp_importers['feedzy-rss-feeds']['install'] );
1046 - }
1047 - }
1048 - /**
1049 747 * Render dashboard notice.
1050 748 */
1051 749 public function render_optimole_dash_notice() {
1052 750 $screen = get_current_screen();
@@ -1069,25 +767,11 @@
1069 767 $user = wp_get_current_user();
1070 768 $asset_file = require $themeisle_sdk_max_path . '/assets/js/build/promos/index.asset.php';
1071 769 $deps = array_merge( $asset_file['dependencies'], [ 'updates' ] );
1072 770
1073 - $themes = wp_get_themes();
1074 - $neve_action = isset( $themes['neve'] ) ? 'activate' : 'install';
1075 - $labels = Loader::$labels['promotions'];
1076 - $labels['feedzy']['editor_recommends'] = sprintf(
1077 - $labels['feedzy']['editor_recommends'],
1078 - $this->product->get_friendly_name(),
1079 - '<a target="_blank" href="' . add_query_arg(
1080 - array(
1081 - 'tab' => 'plugin-information',
1082 - 'plugin' => 'feedzy-rss-feeds',
1083 - '_wpnonce' => wp_create_nonce( 'activate-plugin_feedzy-rss-feeds' ),
1084 - 'feedzy_reference_key' => 'e-' . $this->product->get_key(),
1085 - ),
1086 - network_admin_url( 'plugin-install.php' )
1087 - ) . '">',
1088 - '</a>'
1089 - );
771 + $themes = wp_get_themes();
772 + $neve_action = isset( $themes['neve'] ) ? 'activate' : 'install';
773 +
1090 774 wp_register_script( $handle, $themeisle_sdk_src . 'assets/js/build/promos/index.js', $deps, $asset_file['version'], true );
1091 775 wp_localize_script(
1092 776 $handle,
1093 777 'themeisleSDKPromotions',
@@ -1092,9 +776,9 @@
1092 776 $handle,
1093 777 'themeisleSDKPromotions',
1094 778 [
1095 779 'debug' => $this->debug,
1096 - 'labels' => $labels,
780 + 'labels' => Loader::$labels['promotions'],
1097 781 'email' => $user->user_email,
1098 782 'showPromotion' => $this->loaded_promo,
1099 783 'optionKey' => $this->option_main,
1100 784 'product' => $this->product->get_name(),
@@ -1115,10 +799,8 @@
1115 799 'hyveActivationUrl' => $this->get_plugin_activation_link( 'hyve-lite' ),
1116 800 'hyveDash' => esc_url( add_query_arg( [ 'page' => 'wpfs-settings-stripe' ], admin_url( 'admin.php' ) ) ),
1117 801 'wpFullPayActivationUrl' => $this->get_plugin_activation_link( 'wp-full-stripe-free' ),
1118 802 'wpFullPayDash' => esc_url( add_query_arg( [ 'page' => 'wpfs-settings-stripe' ], admin_url( 'admin.php' ) ) ),
1119 - 'masteriyoActivationUrl' => $this->get_plugin_activation_link( 'masteriyo' ),
1120 - 'masteriyoDash' => esc_url( add_query_arg( [ 'page' => 'masteriyo-onboard' ], admin_url( 'index.php' ) ) ),
1121 803 'nevePreviewURL' => esc_url( add_query_arg( [ 'theme' => 'neve' ], admin_url( 'theme-install.php' ) ) ),
1122 804 'neveAction' => $neve_action,
1123 805 'activateNeveURL' => esc_url(
1124 806 add_query_arg(
@@ -1126,9 +808,9 @@
1126 808 'action' => 'activate',
1127 809 'stylesheet' => 'neve',
1128 810 '_wpnonce' => wp_create_nonce( 'switch-theme_neve' ),
1129 811 ],
1130 - admin_url( 'themes.php' )
812 + admin_url( 'themes.php' )
1131 813 )
1132 814 ),
1133 815 ]
1134 816 );
@@ -1177,15 +859,8 @@
1177 859 echo '<div id="ti-redirection-cf7-notice" class="notice notice-info ti-sdk-om-notice"></div>';
1178 860 }
1179 861
1180 862 /**
1181 - * Render Masteriyo notice.
1182 - */
1183 - public function render_masteriyo_notice() {
1184 - echo '<div id="ti-masteriyo-notice" class="notice notice-info ti-sdk-om-notice"></div>';
1185 - }
1186 -
1187 - /**
1188 863 * Add promo to attachment modal.
1189 864 *
1190 865 * @param array $fields Fields array.
1191 866 * @param \WP_Post $post Post object.
@@ -1597,265 +1272,57 @@
1597 1272 /**
1598 1273 * Check if the user has a support page.
1599 1274 */
1600 1275 public function has_support_page() {
1601 - $page_title_matches = $this->get_page_title_keyword_matches();
1276 + $transient_name = 'tisdk_has_support_page';
1277 + $has_support = get_transient( $transient_name );
1602 1278
1603 - return 'yes' === $page_title_matches['support'];
1604 - }
1279 + if ( false === $has_support ) {
1280 + global $wpdb;
1605 1281
1606 - /**
1607 - * Check if the user has a donate page.
1608 - */
1609 - public function has_donate_page() {
1610 - $page_title_matches = $this->get_page_title_keyword_matches();
1282 + // We use %i escape identifier that was added in WP 6.2.0, hence need to ignore PHPCS warning.
1283 + // We only show this notice to users on higher version as that is the minimum for Hyve as well.
1284 + $query = $wpdb->get_var( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1285 + $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
1286 + 'SELECT ID FROM %i WHERE post_type = %s AND post_status = %s AND post_title LIKE %s LIMIT 1', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnsupportedPlaceholder
1287 + $wpdb->posts,
1288 + 'page',
1289 + 'publish',
1290 + '%support%'
1291 + )
1292 + );
1611 1293
1612 - return 'yes' === $page_title_matches['donate'];
1613 - }
1294 + $has_support = $query ? 'yes' : 'no';
1614 1295
1615 - /**
1616 - * Check if the tagline or a published page title contains LMS related keywords.
1617 - *
1618 - * @return bool True if LMS-related keywords are found, false otherwise.
1619 - */
1620 - public function has_lms_tagline() {
1621 - $tagline = strtolower( get_bloginfo( 'description' ) );
1622 -
1623 - foreach ( $this->get_lms_keywords() as $keyword ) {
1624 - if ( $this->has_lms_keyword_match( $tagline, $keyword ) ) {
1625 - return true;
1626 - }
1296 + set_transient( $transient_name, $has_support, 7 * DAY_IN_SECONDS );
1627 1297 }
1628 1298
1629 - return $this->has_lms_page_title();
1299 + return 'yes' === $has_support;
1630 1300 }
1631 1301
1632 1302 /**
1633 - * Check if a supported LMS plugin is active.
1634 - *
1635 - * @return bool True if an LMS plugin is active, false otherwise.
1303 + * Check if the user has a donate page.
1636 1304 */
1637 - private function has_active_lms_plugin() {
1638 - if ( defined( 'MASTERIYO_VERSION' ) ) {
1639 - return true;
1640 - }
1305 + public function has_donate_page() {
1306 + $transient_name = 'tisdk_has_donate_page';
1307 + $has_donate = get_transient( $transient_name );
1641 1308
1642 - include_once ABSPATH . 'wp-admin/includes/plugin.php';
1309 + if ( false === $has_donate ) {
1310 + global $wpdb;
1643 1311
1644 - $lms_plugins = array(
1645 - 'tutor/tutor.php',
1646 - 'sfwd-lms/sfwd_lms.php',
1647 - 'lifterlms/lifterlms.php',
1648 - 'sensei-lms/sensei-lms.php',
1649 - 'learnpress/learnpress.php',
1650 - 'masterstudy-lms-learning-management-system/masterstudy-lms-learning-management-system.php',
1651 - 'learning-management-system/lms.php',
1652 - );
1312 + $query = $wpdb->get_var( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1313 + $wpdb->prepare(
1314 + 'SELECT ID FROM ' . $wpdb->posts . ' WHERE post_type = %s AND post_status = %s AND post_title LIKE %s LIMIT 1',
1315 + 'page',
1316 + 'publish',
1317 + '%donate%'
1318 + )
1319 + );
1653 1320
1654 - foreach ( $lms_plugins as $plugin ) {
1655 - if ( is_plugin_active( $plugin ) || ( is_multisite() && is_plugin_active_for_network( $plugin ) ) ) {
1656 - return true;
1657 - }
1658 - }
1321 + $has_donate = $query ? 'yes' : 'no';
1659 1322
1660 - return false;
1661 - }
1662 -
1663 - /**
1664 - * Check if the current request can display a plugin install promo.
1665 - *
1666 - * @return bool True if a plugin install promo can be displayed, false otherwise.
1667 - */
1668 - private function can_check_plugin_install_promo() {
1669 - if ( ! is_admin() || ! current_user_can( 'install_plugins' ) ) {
1670 - return false;
1323 + set_transient( $transient_name, $has_donate, 7 * DAY_IN_SECONDS );
1671 1324 }
1672 1325
1673 - $current_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
1674 - if ( isset( $current_screen->id ) ) {
1675 - return $current_screen->id === 'plugin-install';
1676 - }
1677 -
1678 - global $pagenow;
1679 -
1680 - return isset( $pagenow ) && $pagenow === 'plugin-install.php';
1681 - }
1682 -
1683 - /**
1684 - * Check if a published page title contains LMS related keywords.
1685 - *
1686 - * @return bool True if an LMS-related page title is found, false otherwise.
1687 - */
1688 - private function has_lms_page_title() {
1689 - $lms_page_title_signal = get_transient( 'tisdk_lms_page_title_signal_v1' );
1690 -
1691 - if ( in_array( $lms_page_title_signal, array( 'yes', 'no' ), true ) ) {
1692 - return 'yes' === $lms_page_title_signal;
1693 - }
1694 -
1695 - $has_lms_page_title = $this->has_published_page_title_with_keywords( $this->get_lms_page_title_keywords() );
1696 -
1697 - set_transient( 'tisdk_lms_page_title_signal_v1', $has_lms_page_title ? 'yes' : 'no', 7 * DAY_IN_SECONDS );
1698 -
1699 - return $has_lms_page_title;
1700 - }
1701 -
1702 - /**
1703 - * Get cached keyword matches for published page titles.
1704 - *
1705 - * @return array Page title keyword matches.
1706 - */
1707 - private function get_page_title_keyword_matches() {
1708 - $default_matches = array(
1709 - 'support' => 'no',
1710 - 'donate' => 'no',
1711 - );
1712 -
1713 - $page_title_matches = get_transient( 'tisdk_page_title_signals_v1' );
1714 -
1715 - if ( is_array( $page_title_matches ) && empty( array_diff_key( $default_matches, $page_title_matches ) ) ) {
1716 - return array_merge( $default_matches, $page_title_matches );
1717 - }
1718 -
1719 - global $wpdb;
1720 -
1721 - $select_clauses = array();
1722 - $query_values = array();
1723 - $page_checks = $this->get_page_title_checks();
1724 -
1725 - foreach ( $page_checks as $match_key => $keywords ) {
1726 - $match_clauses = array();
1727 -
1728 - $query_values[] = 'page';
1729 - $query_values[] = 'publish';
1730 -
1731 - foreach ( $keywords as $keyword ) {
1732 - $match_clauses[] = 'post_title LIKE %s';
1733 - $query_values[] = '%' . $wpdb->esc_like( $keyword ) . '%';
1734 - }
1735 -
1736 - $select_clauses[] = 'EXISTS( SELECT 1 FROM ' . $wpdb->posts . ' WHERE post_type = %s AND post_status = %s AND ( ' . implode( ' OR ', $match_clauses ) . ' ) LIMIT 1 ) AS has_' . $match_key;
1737 - }
1738 -
1739 - // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
1740 - $query = $wpdb->get_row( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1741 - $wpdb->prepare(
1742 - 'SELECT ' . implode( ', ', $select_clauses ),
1743 - $query_values
1744 - ),
1745 - ARRAY_A
1746 - );
1747 - // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
1748 -
1749 - $page_title_matches = $default_matches;
1750 -
1751 - if ( is_array( $query ) ) {
1752 - foreach ( array_keys( $page_checks ) as $match_key ) {
1753 - $page_title_matches[ $match_key ] = ! empty( $query[ 'has_' . $match_key ] ) ? 'yes' : 'no';
1754 - }
1755 - }
1756 -
1757 - set_transient( 'tisdk_page_title_signals_v1', $page_title_matches, 7 * DAY_IN_SECONDS );
1758 -
1759 - return $page_title_matches;
1760 - }
1761 -
1762 - /**
1763 - * Check if a keyword matches content.
1764 - *
1765 - * @param string $content Content to check.
1766 - * @param string $keyword Keyword to look for.
1767 - *
1768 - * @return bool True if the keyword matches, false otherwise.
1769 - */
1770 - private function has_lms_keyword_match( $content, $keyword ) {
1771 - if ( in_array( $keyword, array( 'lms', 'course', 'class' ), true ) ) {
1772 - return preg_match( '/(^|[^a-z0-9])' . preg_quote( $keyword, '/' ) . '([^a-z0-9]|$)/', $content ) === 1;
1773 - }
1774 -
1775 - return strpos( $content, $keyword ) !== false;
1776 - }
1777 -
1778 - /**
1779 - * Get LMS related keywords.
1780 - *
1781 - * @return array LMS related keywords.
1782 - */
1783 - private function get_lms_keywords() {
1784 - return array(
1785 - 'lms',
1786 - 'learning',
1787 - 'course',
1788 - 'courses',
1789 - 'academy',
1790 - 'training',
1791 - 'lesson',
1792 - 'lessons',
1793 - 'class',
1794 - 'classes',
1795 - 'student',
1796 - 'students',
1797 - 'teach',
1798 - 'teaching',
1799 - 'tutor',
1800 - 'quiz',
1801 - 'education',
1802 - 'online course',
1803 - 'online courses',
1804 - );
1805 - }
1806 -
1807 - /**
1808 - * Get LMS related keywords for page title matching.
1809 - *
1810 - * @return array LMS related keywords.
1811 - */
1812 - private function get_lms_page_title_keywords() {
1813 - return array_values( array_diff( $this->get_lms_keywords(), array( 'lms', 'course', 'class' ) ) );
1814 - }
1815 -
1816 - /**
1817 - * Check if a published page title contains any of the provided keywords.
1818 - *
1819 - * @param array $keywords Keywords to look for.
1820 - *
1821 - * @return bool True if a matching page title is found, false otherwise.
1822 - */
1823 - private function has_published_page_title_with_keywords( $keywords ) {
1824 - if ( empty( $keywords ) ) {
1825 - return false;
1826 - }
1827 -
1828 - global $wpdb;
1829 -
1830 - $query_values = array( 'page', 'publish' );
1831 - $clauses = array();
1832 -
1833 - foreach ( $keywords as $keyword ) {
1834 - $clauses[] = 'post_title LIKE %s';
1835 - $query_values[] = '%' . $wpdb->esc_like( $keyword ) . '%';
1836 - }
1837 -
1838 - // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
1839 - $page_title_match = $wpdb->get_var( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1840 - $wpdb->prepare(
1841 - 'SELECT 1 FROM ' . $wpdb->posts . ' WHERE post_type = %s AND post_status = %s AND ( ' . implode( ' OR ', $clauses ) . ' ) LIMIT 1',
1842 - $query_values
1843 - )
1844 - );
1845 - // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
1846 -
1847 - return ! empty( $page_title_match );
1848 - }
1849 -
1850 - /**
1851 - * Get page title keyword checks.
1852 - *
1853 - * @return array Page title keyword checks.
1854 - */
1855 - private function get_page_title_checks() {
1856 - return array(
1857 - 'support' => array( 'support' ),
1858 - 'donate' => array( 'donate' ),
1859 - );
1326 + return 'yes' === $has_donate;
1860 1327 }
1861 1328 }