PluginProbe ʕ •ᴥ•ʔ
Starter Sites & Templates by Neve / trunk
Starter Sites & Templates by Neve vtrunk
1.4.0 1.3.0 1.2.29 1.2.28 1.2.6 1.2.7 1.2.8 1.2.9 trunk 1.0.10 1.0.11 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.21 1.1.22 1.1.23 1.1.24 1.1.25 1.1.26 1.1.27 1.1.28 1.1.29 1.1.3 1.1.30 1.1.31 1.1.32 1.1.33 1.1.34 1.1.35 1.1.36 1.1.37 1.1.38 1.1.39 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.3 1.2.4 1.2.5
templates-patterns-collection / includes / Admin.php
templates-patterns-collection / includes Last commit date
Importers 2 months ago Admin.php 1 week ago Editor.php 1 year ago Elementor.php 1 year ago License.php 1 year ago Logger.php 2 years ago Main.php 1 week ago Rest_Server.php 2 weeks ago Sites_Listing.php 2 weeks ago Starter_Ranking.php 1 week ago TI_Beaver.php 1 year ago WP_Cli.php 3 months ago White_Label_Config.php 3 years ago
Admin.php
1460 lines
1 <?php
2 /**
3 * Handles admin logic for the onboarding.
4 *
5 * @package templates-patterns-collection
6 */
7
8 namespace TIOB;
9
10 use TIOB\Importers\Cleanup\Active_State;
11
12 /**
13 * Class Admin
14 *
15 * @package templates-patterns-collection
16 */
17 class Admin {
18 use White_Label_Config;
19
20 // TODO: revert this after implementation
21 // const API = 'neve.test/wp-json';
22 const API = 'api.themeisle.com';
23
24 const IMPORTED_TEMPLATES_COUNT_OPT = 'tiob_premade_imported';
25 const FEEDBACK_DISMISSED_OPT = 'tiob_feedback_dismiss';
26
27 const TC_REMOVED_KEY = 'tiob_tc_removed';
28 const TC_NEW_NOTICE_DISMISSED = 'tiob_new_tc_notice_dismissed';
29 const VISITED_LIBRARY_OPT = 'tiob_library_visited';
30
31 /**
32 * Admin page slug
33 *
34 * @var string
35 */
36 private $page_slug = 'tiob-starter-sites';
37
38 /**
39 * Option and transient namespace for email skip.
40 *
41 * @var string
42 */
43 private $skip_email_subscribe_namespace = 'tpc_skip_email_subscribe';
44
45 /**
46 * Neve font pairs
47 *
48 * @var array
49 */
50 private $font_pairs_neve = array();
51
52 /**
53 * Google fonts
54 *
55 * @var array
56 */
57 private $google_fonts = array();
58
59 public static function get_templates_cloud_endpoint() {
60 return 'https://' . self::API . '/templates-cloud/';
61 }
62
63 /**
64 * Initialize the Admin.
65 */
66 public function init() {
67 License::get_instance();
68
69 $this->maybe_remove_tc();
70
71 add_filter( 'query_vars', array( $this, 'add_onboarding_query_var' ) );
72 add_action( 'after_switch_theme', array( $this, 'get_previous_theme' ) );
73 add_filter( 'neve_dashboard_page_data', array( $this, 'localize_sites_library' ) );
74 add_action( 'admin_menu', array( $this, 'register' ) );
75 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
76 add_filter( 'ti_tpc_editor_data', array( $this, 'add_tpc_editor_data' ), 20 );
77 add_action( 'admin_init', array( $this, 'activation_redirect' ) );
78 add_filter( 'themeisle_sdk_blackfriday_data', array( $this, 'add_black_friday_data' ) );
79
80 $this->setup_white_label();
81
82 add_action( 'wp_ajax_skip_subscribe', array( $this, 'skip_subscribe' ) );
83 add_action( 'wp_ajax_nopriv_skip_subscribe', array( $this, 'skip_subscribe' ) );
84
85 add_action( 'wp_ajax_mark_onboarding_done', array( $this, 'mark_onboarding_done' ) );
86 add_action( 'wp_ajax_nopriv_mark_onboarding_done', array( $this, 'mark_onboarding_done' ) );
87
88 add_action( 'wp_ajax_tpc_get_logs', array( $this, 'external_get_logs' ) );
89
90 add_action( 'wp_ajax_dismiss_new_tc_notice', array( $this, 'dismiss_new_tc_notice' ) );
91
92 $this->register_feedback_settings();
93
94 $this->register_prevent_clone_hooks();
95
96 $this->get_font_parings();
97 }
98
99 /**
100 * Removes template cloud for users that:
101 * - didn't have a license key yet;
102 * - have 0 templates saved;
103 *
104 * @return void
105 */
106 public function maybe_remove_tc() {
107 $status = get_option( self::TC_REMOVED_KEY );
108
109 if ( $status !== false ) {
110 return;
111 }
112
113 if ( ! License::has_active_license() ) {
114 update_option( self::TC_REMOVED_KEY, 'yes' );
115
116 return;
117 }
118
119 $license = License::get_instance();
120
121 if ( ! $license->has_any_templates() ) {
122 update_option( self::TC_REMOVED_KEY, 'yes' );
123
124 return;
125 }
126
127 update_option( self::TC_REMOVED_KEY, 'no' );
128 }
129
130
131 /**
132 * Check if the legacy template cloud is still available.
133 *
134 * @return bool
135 */
136 public static function has_legacy_template_cloud() {
137 return get_option( self::TC_REMOVED_KEY, 'no' ) === 'no';
138 }
139
140 public function dismiss_new_tc_notice() {
141 $response = array(
142 'success' => false,
143 'code' => 'ti__ob_not_allowed',
144 'message' => 'Not allowed!',
145 );
146
147 if ( ! isset( $_REQUEST['nonce'] ) ) {
148 $this->ensure_ajax_response( $response );
149 return;
150 }
151
152 if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'dismiss_new_tc_notice' ) ) {
153 $this->ensure_ajax_response( $response );
154 return;
155 }
156
157 unset( $response['code'] );
158 unset( $response['message'] );
159
160 update_option( self::TC_NEW_NOTICE_DISMISSED, 'yes' );
161 $this->ensure_ajax_response( $response );
162 }
163
164 /**
165 * Decide if the business/agency variant of the onboarding promo text should be shown.
166 *
167 * @return bool
168 */
169 private function should_show_business_agency_promo_text() {
170 $license_data = License::get_license_data();
171 $license_key = isset( $license_data->key ) ? strtolower( trim( (string) $license_data->key ) ) : '';
172 $license_tier = License::get_license_tier( 0 );
173 $raw_tier = isset( $license_data->tier ) ? absint( $license_data->tier ) : 0;
174 $neve_plan = $this->neve_license_plan();
175
176 if ( $license_key === '' || $license_key === 'free' ) {
177 return false;
178 }
179
180 if ( ! License::has_active_license() || ! $this->has_valid_addons() ) {
181 return false;
182 }
183
184 if ( -1 !== $neve_plan ) {
185 // The normalized Neve plan uses mapped TPC tiers, where Business and Agency are 2 and 3.
186 return in_array( $neve_plan, array( 2, 3 ), true );
187 }
188
189 if ( in_array( $raw_tier, array( 1, 2, 7, 12, 18 ), true ) ) {
190 return false;
191 }
192
193 return in_array( $license_tier, array( 2, 3 ), true );
194 }
195
196
197 /**
198 * Register hooks to prevent meta cloning for the templates.
199 * This is needed because the template id is unique, and we don't want to clone it.
200 * @return void
201 */
202 public function register_prevent_clone_hooks() {
203 $allowed_post_types = Editor::get_allowed_post_types();
204 if ( empty( $allowed_post_types ) ) {
205 return;
206 }
207 foreach ( $allowed_post_types as $post_type ) {
208 add_filter(
209 'update_' . $post_type . '_metadata',
210 function ( $value, $post_id, $meta_key, $meta_value, $prev_value ) use ( $post_type ) {
211 if ( $this->check_unique_template_id_on_meta_change( $post_id, $meta_key, $post_type, $meta_value ) ) {
212 return true;
213 }
214 return $value;
215 },
216 10,
217 5
218 );
219 add_filter(
220 'add_' . $post_type . '_metadata',
221 function ( $value, $post_id, $meta_key, $meta_value, $unique ) use ( $post_type ) {
222 if ( $this->check_unique_template_id_on_meta_change( $post_id, $meta_key, $post_type, $meta_value ) ) {
223 return true;
224 }
225 return $value;
226 },
227 10,
228 5
229 );
230 }
231 }
232
233 /**
234 * Check that the meta value is unique for the allowed post types that support Templates Cloud.
235 *
236 * @param int $post_id The post ID.
237 * @param string $meta_key The meta key.
238 * @param string $meta_type The meta type. The post type ( post, page, neve_custom_layouts etc. ).
239 * @param string $meta_value The meta value.
240 *
241 * @return bool
242 */
243 public function check_unique_template_id_on_meta_change( $post_id, $meta_key, $meta_type, $meta_value ) {
244 // Skip check if the meta key is not one of the allowed ones.
245 if ( ! in_array(
246 $meta_key,
247 array(
248 '_ti_tpc_template_sync',
249 '_ti_tpc_template_id',
250 '_ti_tpc_screenshot_url',
251 '_ti_tpc_site_slug',
252 '_ti_tpc_published',
253 ),
254 true
255 )
256 ) {
257 return false;
258 }
259
260 if ( empty( $meta_value ) ) {
261 return false;
262 }
263
264 $template_id = get_post_meta( $post_id, '_ti_tpc_template_id', true );
265 if ( empty( $template_id ) && $meta_key === '_ti_tpc_template_id' ) {
266 $template_id = $meta_value;
267 }
268
269 // Check if the template ID is used on any other posts or pages
270 // exclude the current post from the query
271 $args = array(
272 'post_type' => $meta_type,
273 'meta_key' => '_ti_tpc_template_id',
274 'meta_value' => $template_id,
275 'post__not_in' => array( $post_id ),
276 'posts_per_page' => 1,
277 'fields' => 'ids',
278 );
279 $query = new \WP_Query( $args );
280 $duplicate_id = $query->get_posts();
281
282 if ( ! empty( $duplicate_id ) ) {
283 // The template ID is already used on another post
284 return true;
285 }
286 return false;
287 }
288
289 /**
290 * Register feedback settings.
291 *
292 * @return void
293 */
294 private function register_feedback_settings() {
295 register_setting(
296 'tiob_feedback',
297 self::IMPORTED_TEMPLATES_COUNT_OPT,
298 array(
299 'type' => 'integer',
300 'show_in_rest' => true,
301 'default' => 0,
302 )
303 );
304 register_setting(
305 'tiob_feedback',
306 self::FEEDBACK_DISMISSED_OPT,
307 array(
308 'type' => 'boolean',
309 'show_in_rest' => true,
310 'default' => false,
311 )
312 );
313 }
314
315 /**
316 * Return the skip subscribe status.
317 * Used to determine if email form should be displayed.
318 *
319 * @return bool
320 */
321 private function get_skip_subscribe_status() {
322 $status = false;
323 if ( 'yes' === get_option( $this->skip_email_subscribe_namespace, 'no' ) ) {
324 $status = true;
325 }
326
327 if ( get_transient( $this->skip_email_subscribe_namespace ) ) {
328 $status = true;
329 }
330
331 return $status;
332 }
333
334 /**
335 * Utility method to ensure proper response for ajax call.
336 *
337 * @param array $response
338 */
339 private function ensure_ajax_response( $response ) {
340 echo json_encode( $response );
341 die();
342 }
343
344 /**
345 * Handles the `skip_subscribe` ajax action.
346 */
347 public function skip_subscribe() {
348 $response = array(
349 'success' => false,
350 'code' => 'ti__ob_not_allowed',
351 'message' => 'Not allowed!',
352 );
353 if ( ! isset( $_REQUEST['nonce'] ) ) {
354 $this->ensure_ajax_response( $response );
355 return;
356 }
357
358 if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'skip_subscribe_nonce' ) ) {
359 $this->ensure_ajax_response( $response );
360 return;
361 }
362
363 unset( $response['code'] );
364 unset( $response['message'] );
365 $response['success'] = true;
366 if ( isset( $_REQUEST['isTempSkip'] ) ) {
367 set_transient( $this->skip_email_subscribe_namespace, 'yes', 7 * DAY_IN_SECONDS );
368 $this->ensure_ajax_response( $response );
369 return;
370 }
371
372 update_option( $this->skip_email_subscribe_namespace, 'yes' );
373 $this->ensure_ajax_response( $response );
374 }
375
376 /**
377 * Handles the `mark_onboarding_done` ajax action.
378 */
379 public function mark_onboarding_done() {
380 $response = array(
381 'success' => false,
382 'code' => 'ti__ob_not_allowed',
383 'message' => 'Not allowed!',
384 );
385 if ( ! isset( $_REQUEST['nonce'] ) ) {
386 $this->ensure_ajax_response( $response );
387 return;
388 }
389
390 if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'onboarding_done_nonce' ) ) {
391 $this->ensure_ajax_response( $response );
392 return;
393 }
394
395 unset( $response['code'] );
396 unset( $response['message'] );
397
398 update_option( 'tpc_onboarding_done', 'yes' );
399 $this->ensure_ajax_response( $response );
400 }
401
402 /**
403 * Hook into editor data to add Neve plan if available
404 * or return the proper tier if stand-alone license is valid.
405 *
406 * @param array $data tiTpc exported data.
407 *
408 * @return array
409 */
410 public function add_tpc_editor_data( $data ) {
411 $plan = $this->neve_license_plan();
412 $data['tier'] = License::get_license_tier( $plan );
413
414 return $data;
415 }
416
417
418 /**
419 * Redirect to onboarding if user is new.
420 *
421 * @return void
422 */
423 public function activation_redirect() {
424 $should_run_obd = get_option( 'tpc_maybe_run_onboarding', false );
425 if ( ! $should_run_obd ) {
426 return;
427 }
428 if ( ! $this->should_load_onboarding() ) {
429 return;
430 }
431
432 delete_option( 'tpc_maybe_run_onboarding' );
433
434 $query_args = array( 'page' => 'neve-onboarding' );
435
436 if ( defined( 'TI_ONBOARDING_DEFAULT_SITE' ) && TI_ONBOARDING_DEFAULT_SITE ) {
437 $query_args['site'] = sanitize_key( TI_ONBOARDING_DEFAULT_SITE );
438 } else {
439 $query_args['show'] = 'welcome';
440 }
441
442 wp_safe_redirect( add_query_arg( $query_args, admin_url( 'admin.php' ) ) );
443 exit();
444 }
445
446 /**
447 * Use the Neve builtin compatibility to check for specific support.
448 *
449 * @return bool
450 */
451 private function neve_theme_has_support( $feature ) {
452 if ( defined( 'NEVE_COMPATIBILITY_FEATURES' ) ) {
453 $features = NEVE_COMPATIBILITY_FEATURES;
454 return isset( $features[ $feature ] );
455 }
456 return false;
457 }
458
459 /**
460 * Use the features defined in the TIOB plugin to check for specific support.
461 *
462 * @param string $feature The feature to check for.
463 *
464 * @return bool
465 */
466 private function tiob_has_support( $feature ) {
467 if ( defined( 'TIOB_FEATURES' ) ) {
468 $features = TIOB_FEATURES;
469 return isset( $features[ $feature ] );
470 }
471 return false;
472 }
473
474 /**
475 * Utility method to add a theme page from an array.
476 *
477 * @param array $page_data Page data.
478 * @param int $offset Offset for the menu position.
479 *
480 * @return void
481 */
482 private function add_theme_page_for_tiob( $page_data, $offset = 2 ) {
483
484 if ( $this->neve_theme_has_support( 'theme_dedicated_menu' ) ) {
485 global $submenu;
486
487 $theme_page = 'neve-welcome';
488 $capability = 'activate_plugins';
489 add_submenu_page(
490 $theme_page,
491 $page_data['page_title'],
492 $page_data['page_title'],
493 $capability,
494 $page_data['menu_slug'],
495 $page_data['callback']
496 );
497
498 $item = array_pop( $submenu[ $theme_page ] );
499 array_splice( $submenu[ $theme_page ], $offset, 0, array( $item ) );
500 return;
501 }
502
503 // When using the new menu location we will not register items on the theme page anymore.
504 if ( $this->tiob_has_support( 'new_menu' ) ) {
505 return;
506 }
507
508 add_theme_page(
509 $page_data['page_title'],
510 $page_data['menu_title'],
511 $page_data['capability'],
512 $page_data['menu_slug'],
513 $page_data['callback']
514 );
515 }
516
517 /**
518 * Utility method to add a plugin sub-page from an array.
519 *
520 * @param array $page_data Page data.
521 *
522 * @return void
523 */
524 private function add_subpage_for_tiob( $page_data ) {
525 $capability = 'manage_options';
526 add_submenu_page(
527 $page_data['parent_slug'],
528 $page_data['page_title'],
529 $page_data['menu_title'],
530 $capability,
531 $page_data['menu_slug'],
532 $page_data['callback']
533 );
534 }
535
536 /**
537 * Register theme options page.
538 *
539 * @return bool|void
540 */
541 public function register() {
542 $has_neve = defined( 'NEVE_VERSION' );
543
544 // Legacy users that had the plugin and had templates.
545 if ( self::has_legacy_template_cloud() ) {
546 $this->register_legacy_template_cloud_pages();
547
548 return;
549 }
550
551 if ( ! $has_neve ) {
552 $this->register_starter_sites_page( true );
553
554 return;
555 }
556
557 $this->register_starter_sites_page();
558 }
559
560 private function register_starter_sites_page( $in_appearance = false ) {
561 // WL disables starter sites.
562 if ( $this->is_starter_sites_disabled() ) {
563 return;
564 }
565
566 $starter_site_data = array(
567 'page_title' => __( 'Starter Sites', 'templates-patterns-collection' ),
568 'menu_title' => $this->get_prefix_for_menu_item() . __( 'Onboarding', 'templates-patterns-collection' ),
569 'capability' => 'install_plugins',
570 'menu_slug' => 'neve-onboarding',
571 'callback' => array(
572 $this,
573 'render_onboarding',
574 ),
575 );
576
577 if ( $in_appearance ) {
578 $starter_site_data['page_title'] = __( 'Starter Templates', 'templates-patterns-collection' );
579 $starter_site_data['menu_title'] = __( 'Starter Templates', 'templates-patterns-collection' );
580
581 add_theme_page(
582 $starter_site_data['page_title'],
583 $starter_site_data['menu_title'],
584 $starter_site_data['capability'],
585 $starter_site_data['menu_slug'],
586 $starter_site_data['callback']
587 );
588 }
589
590 $this->add_theme_page_for_tiob( $starter_site_data, 2 );
591 }
592
593 /**
594 * Legacy template cloud pages.
595 *
596 * @return false|void
597 */
598 public function register_legacy_template_cloud_pages() {
599 $icon = 'data:image/svg+xml;base64,PHN2ZwogICAgICAgIHdpZHRoPSIxMDAiCiAgICAgICAgaGVpZ2h0PSIxMDAiCiAgICAgICAgdmlld0JveD0iMCAwIDEwMCAxMDAiCiAgICAgICAgZmlsbD0iI2YwZjBmMSIKICAgICAgICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCj4KICAgIDxwYXRoCiAgICAgICAgICAgIGQ9Ik05NS4wMjY0IDEwMEg0Ljk3MzU2QzIuMjI3OTcgMTAwIDAgOTcuNzcyIDAgOTUuMDI2NFY0Ljk3MzU2QzAgMi4yMjc5NyAyLjIyNzk3IDAgNC45NzM1NiAwSDk1LjAyNjRDOTcuNzcyIDAgMTAwIDIuMjI3OTcgMTAwIDQuOTczNTZWOTUuMDI2NEMxMDAgOTcuNzcyIDk3Ljc3MiAxMDAgOTUuMDI2NCAxMDBaIE04Mi42OTQxIDg2Ljc0NDhWMzAuODIwNVYxOC40NjUzSDcwLjM1MDJIMTQuNDE0NkwyNi43NTg0IDMwLjgyMDVINzAuMzUwMlY3NC40MDFMODIuNjk0MSA4Ni43NDQ4WiBNNDIuMjQxNiA1OC45MjkxTDQyLjI1MjggNzEuMTgzTDUzLjIzNTIgODIuMTY1M0w1My4xOTAyIDQ3Ljk4MDZMMTguOTk0MSA0Ny45MzU1TDI5Ljk3NjUgNTguOTA2Nkw0Mi4yNDE2IDU4LjkyOTFaIgogICAgICAgICAgICBmaWxsPSIjZjBmMGYxIgogICAgLz4KPC9zdmc+Cg==';
600 $priority = 61; // The position of the menu item, 60 is the position of the Appearance menu.
601 $plugin_page = 'tiob-plugin';
602
603 $tpc_menu_page_data = array(
604 'page_title' => __( 'Templates Cloud', 'templates-patterns-collection' ),
605 'menu_title' => __( 'Templates Cloud', 'templates-patterns-collection' ),
606 'capability' => 'manage_options',
607 'menu_slug' => $plugin_page,
608 'callback' => array(
609 $this,
610 'render_starter_sites',
611 ),
612 );
613
614 add_menu_page(
615 $tpc_menu_page_data['page_title'],
616 $tpc_menu_page_data['menu_title'],
617 $tpc_menu_page_data['capability'],
618 $tpc_menu_page_data['menu_slug'],
619 $tpc_menu_page_data['callback'],
620 $icon,
621 $priority
622 );
623
624 if ( $this->is_library_disabled() && $this->is_starter_sites_disabled() ) {
625 return false;
626 }
627
628 $library_data = array(
629 'parent_slug' => $plugin_page,
630 'page_title' => __( 'My Library', 'templates-patterns-collection' ),
631 'menu_title' => __( 'My Library', 'templates-patterns-collection' ),
632 'capability' => 'activate_plugins',
633 'menu_slug' => $plugin_page,
634 'callback' => $tpc_menu_page_data['callback'],
635 );
636 $settings_data = array(
637 'parent_slug' => $plugin_page,
638 'page_title' => __( 'Settings', 'templates-patterns-collection' ),
639 'menu_title' => __( 'Settings', 'templates-patterns-collection' ),
640 'capability' => 'activate_plugins',
641 'menu_slug' => 'admin.php?page=' . $plugin_page . '#settings',
642 'callback' => '',
643 );
644
645 if ( $this->is_starter_sites_disabled() && ! $this->is_library_disabled() ) {
646 $library_data['menu_slug'] = $plugin_page;
647 $library_data['callback'] = array(
648 $this,
649 'render_starter_sites',
650 );
651 $this->add_subpage_for_tiob( $library_data );
652 $this->add_subpage_for_tiob( $settings_data );
653 return false;
654 }
655 $this->register_starter_sites_page();
656
657 if ( $this->is_library_disabled() ) {
658 return false;
659 }
660 $this->add_subpage_for_tiob( $library_data );
661 $this->add_subpage_for_tiob( $settings_data );
662 }
663
664 /**
665 * Map license plan from Neve if available.
666 *
667 * @return int
668 */
669 private function neve_license_plan() {
670 $category = apply_filters( 'product_neve_license_plan', -1 );
671
672 $category_mapping = License::NEVE_CATEGORY_MAPPING;
673
674 return $category > -1 && isset( $category_mapping[ $category ] ) ? $category_mapping[ $category ] : -1;
675 }
676
677 /**
678 * Render method for the starter sites page.
679 */
680 public function render_starter_sites() {
681 echo '<div id="tpc-app"/>';
682 }
683
684 /**
685 * Render method for the onboarding page.
686 */
687 public function render_onboarding() {
688 echo '<div id="ob-app"/>';
689 }
690
691 /**
692 * Decide if the new onboarding should load
693 *
694 * @return bool
695 */
696 private function should_load_onboarding() {
697 if ( ! current_user_can( 'install_plugins' ) ) {
698 return false;
699 }
700
701 if ( $this->is_starter_sites_disabled() ) {
702 return false;
703 }
704
705 $current_theme = wp_get_theme();
706 $template = $current_theme->template === 'neve' ? $current_theme->template : $current_theme->parent();
707 if ( $template !== 'neve' ) {
708 return false;
709 }
710
711 $onboarding_done = get_option( 'tpc_onboarding_done', 'no' );
712 if ( $onboarding_done === 'yes' ) {
713 return false;
714 }
715
716 return get_option( 'tpc_obd_new_user', 'no' ) === 'yes';
717 }
718
719 /**
720 * Enqueue scripts and styles
721 *
722 * @return void
723 */
724 public function enqueue() {
725 $screen = get_current_screen();
726 if ( ! isset( $screen->id ) ) {
727 return;
728 }
729
730 if ( strpos( $screen->id, '_page_neve-onboarding' ) ) {
731
732 wp_enqueue_media();
733
734 $onboarding_dependencies = ( include TIOB_PATH . 'onboarding/build/index.asset.php' );
735 wp_register_style( 'tiobObd', TIOB_URL . 'onboarding/build/style-index.css', array( 'wp-components' ), $onboarding_dependencies['version'] );
736 wp_style_add_data( 'tiobObd', 'rtl', 'replace' );
737 wp_enqueue_style( 'tiobObd' );
738
739 wp_register_script( 'tiobObd', TIOB_URL . 'onboarding/build/index.js', array_merge( $onboarding_dependencies['dependencies'], array( 'updates', 'regenerator-runtime' ) ), $onboarding_dependencies['version'], true );
740 wp_localize_script( 'tiobObd', 'tiobDash', apply_filters( 'neve_dashboard_page_data', $this->get_localization() ) );
741 wp_enqueue_script( 'tiobObd' );
742
743 wp_set_script_translations( 'tiobObd', 'templates-patterns-collection' );
744
745 if ( ! empty( $this->google_fonts ) ) {
746 $font_chunks = array_chunk( $this->google_fonts, absint( count( $this->google_fonts ) / 5 ) );
747 foreach ( $font_chunks as $index => $fonts_chunk ) {
748 wp_enqueue_style(
749 'tiob-google-fonts-' . $index,
750 'https://fonts.googleapis.com/css?family=' . implode( '|', $fonts_chunk ) . '&display=swap"',
751 array(),
752 $onboarding_dependencies['version']
753 );
754 }
755 }
756
757 do_action( 'themeisle_internal_page', TIOB_BASENAME, 'onboarding' );
758 }
759
760 $is_tiob_page = strpos( $screen->id, '_page_tiob-plugin' ) !== false;
761 if ( strpos( $screen->id, '_page_' . $this->page_slug ) === false && ! $is_tiob_page ) {
762 return;
763 }
764
765 $dismiss_notice = isset( $_GET['dismiss_notice'] ) && $_GET['dismiss_notice'] === 'yes';
766 if ( $dismiss_notice ) {
767 update_option( self::VISITED_LIBRARY_OPT, 'yes' );
768 }
769
770 $dependencies = ( include TIOB_PATH . 'assets/build/app.asset.php' );
771
772 wp_register_style( 'tiob', TIOB_URL . 'assets/build/style-app.css', array( 'wp-components' ), $dependencies['version'] );
773 wp_style_add_data( 'tiob', 'rtl', 'replace' );
774 wp_enqueue_style( 'tiob' );
775
776 wp_register_script( 'tiob', TIOB_URL . 'assets/build/app.js', array_merge( $dependencies['dependencies'], array( 'updates', 'regenerator-runtime' ) ), $dependencies['version'], true );
777 $tiob_dash = apply_filters( 'neve_dashboard_page_data', $this->get_localization() );
778 if ( $is_tiob_page ) {
779 $tiob_dash['hideStarterSites'] = true;
780 }
781 wp_localize_script( 'tiob', 'tiobDash', apply_filters( 'neve_dashboard_page_data', $tiob_dash ) );
782 wp_enqueue_script( 'tiob' );
783
784 wp_set_script_translations( 'tiob', 'templates-patterns-collection' );
785
786 do_action( 'themeisle_internal_page', TIOB_BASENAME, 'onboarding' );
787 }
788
789 /**
790 * Get localization data for the dashboard script.
791 *
792 * @return array
793 */
794 private function get_localization() {
795 $theme_name = apply_filters( 'ti_wl_theme_name', 'Neve' );
796 $user = wp_get_current_user();
797
798 $neve_upgrade_link = 'https://themeisle.com/themes/neve/upgrade/';
799 $upgrade_url = apply_filters(
800 'neve_upgrade_link_from_child_theme_filter',
801 tsdk_translate_link( tsdk_utmify( $neve_upgrade_link, 'freevspro' ), 'query' )
802 );
803 $upgrade_url_tpc = tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/plugins/templates-cloud', 'tcupgrade' ), 'query' );
804 if ( defined( 'NEVE_VERSION' ) ) {
805 $upgrade_url_tpc = apply_filters(
806 'neve_upgrade_link_from_child_theme_filter',
807 tsdk_translate_link( tsdk_utmify( $neve_upgrade_link, 'templatecloud' ), 'query' )
808 );
809 }
810
811 return array(
812 'version' => TIOB_VERSION,
813 'nonce' => wp_create_nonce( 'wp_rest' ),
814 'assets' => TIOB_URL . 'assets/',
815 'upgradeURL' => $upgrade_url,
816 'upgradeURLTpc' => $upgrade_url_tpc,
817 'siteUrl' => trailingslashit( get_site_url() ),
818 'strings' => array(
819 /* translators: %s - Theme name */
820 'starterSitesTabDescription' => __( 'Choose from multiple unique demos, specially designed for you, that can be installed with a single click. You just need to choose your favorite, and we will take care of everything else.', 'templates-patterns-collection' ),
821 ),
822 'cleanupAllowed' => ( ! empty( get_transient( Active_State::STATE_NAME ) ) ) ? 'yes' : 'no',
823 'onboarding' => array(),
824 'adminUrl' => admin_url(),
825 'hasFileSystem' => WP_Filesystem(),
826 'themesURL' => admin_url( 'themes.php' ),
827 'themeAction' => $this->get_theme_action(),
828 'brandedTheme' => $this->get_whitelabel_name(),
829 'hideStarterSites' => $this->is_starter_sites_disabled(),
830 'hideMyLibrary' => $this->is_library_disabled(),
831 'fontParings' => $this->font_pairs_neve,
832 'endpoint' => ( defined( 'TPC_TEMPLATES_CLOUD_ENDPOINT' ) ) ? TPC_TEMPLATES_CLOUD_ENDPOINT : self::get_templates_cloud_endpoint(),
833 'params' => array(
834 'site_url' => get_site_url(),
835 'license_id' => License::get_license_data()->key,
836 ),
837 'upsellNotifications' => $this->get_upsell_notifications(),
838 'isValidLicense' => $this->has_valid_addons(),
839 'licenseTIOB' => License::get_license_data(),
840 'onboardingShowProNoticeText' => $this->should_show_business_agency_promo_text(),
841 'emailSubscribe' => array(
842 'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
843 'nonce' => wp_create_nonce( 'skip_subscribe_nonce' ),
844 'skipStatus' => $this->get_skip_subscribe_status() ? 'yes' : 'no',
845 'email' => ( ! empty( $user->user_email ) ) ? $user->user_email : '',
846 ),
847 'onboardingDone' => array(
848 'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
849 'nonce' => wp_create_nonce( 'onboarding_done_nonce' ),
850 ),
851 'feedback' => array(
852 'count' => get_option( self::IMPORTED_TEMPLATES_COUNT_OPT, 0 ),
853 'dismissed' => get_option( self::FEEDBACK_DISMISSED_OPT, false ),
854 ),
855 'onboardingUpsell' => array(
856 'dashboard' => tsdk_translate_link( tsdk_utmify( 'https://store.themeisle.com/', 'onboarding_upsell' ), 'query' ),
857 'contact' => tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/contact/', 'onboarding_upsell' ), 'query' ),
858 'upgrade' => tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'onboarding_upsell' ), 'query' ),
859 'upgradeToast' => tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'onboarding_toast' ), 'query' ),
860 ),
861 'onboardingAllowed' => $this->should_load_onboarding(),
862 'onboardingRedirect' => admin_url( 'admin.php?page=neve-onboarding' ),
863 'tiobSettings' => admin_url( 'admin.php?page=tiob-plugin#settings' ),
864 'links' => array(
865 array(
866 'label' => __( 'Support', 'templates-patterns-collection' ),
867 'is_external' => true,
868 'url' => tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/contact/', 'settings_page' ), 'query' ),
869 ),
870 array(
871 'label' => __( 'Feature request', 'templates-patterns-collection' ),
872 'target' => '_self',
873 'url' => admin_url( 'admin.php?page=tiob-plugin&tab=feedback#settings' ),
874 ),
875 array(
876 'label' => __( 'Leave a review', 'templates-patterns-collection' ),
877 'is_external' => true,
878 'url' => 'https://wordpress.org/support/plugin/templates-patterns-collection/reviews/#new-post',
879 ),
880 array(
881 'label' => __( 'Documentation', 'templates-patterns-collection' ),
882 'url' => tsdk_utmify( 'https://docs.themeisle.com/article/1354-neve-template-cloud-library', 'settings_page' ),
883 'is_button' => true,
884 ),
885 ),
886 'isFSETheme' => self::is_fse_theme(),
887 'newTCNotice' => array(
888 'show' => get_option( self::TC_NEW_NOTICE_DISMISSED, 'no' ) !== 'yes' && self::has_legacy_template_cloud(),
889 'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
890 'nonce' => wp_create_nonce( 'dismiss_new_tc_notice' ),
891 ),
892 'onboardingPluginCompatibility' => array(
893 'hyve-lite' => is_php_version_compatible( '8.1' ),
894 ),
895 );
896 }
897
898 /**
899 * Check if the current theme is a FSE theme,
900 *
901 * @return bool
902 */
903 public static function is_fse_theme() {
904 if ( function_exists( 'wp_is_block_theme' ) ) {
905 return (bool) wp_is_block_theme();
906 }
907 if ( function_exists( 'gutenberg_is_fse_theme' ) ) {
908 return (bool) gutenberg_is_fse_theme();
909 }
910
911 return false;
912 }
913
914 /**
915 * Neve Pro upsells.
916 * @return array
917 */
918 private function get_upsell_notifications() {
919
920 $notifications['upsell_1'] = array(
921 // We use these strings in Neve already so lets reuse the translations here.
922 'text' => esc_html__( 'Purchase the Business plan or higher to get instant access to all Premium Starter Site Templates — including Expert Sites — and much more.', 'neve' ), //phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
923 'cta' => __( 'Get Neve Business', 'neve' ), //phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
924 'url' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', '<builder_name>notice', 'nevedashboard' ),
925 );
926
927 return $notifications;
928
929 }
930
931 /**
932 * Gets theme action.
933 */
934 private function get_theme_action() {
935 if ( defined( 'NEVE_VERSION' ) ) {
936 return false;
937 }
938
939 $themes = wp_get_themes();
940 foreach ( $themes as $theme_slug => $args ) {
941 $theme = wp_get_theme( $theme_slug );
942 if ( $theme->get( 'TextDomain' ) === 'neve' ) {
943 return array(
944 'action' => 'activate',
945 'slug' => $theme_slug,
946 'nonce' => wp_create_nonce( 'switch-theme_' . $theme_slug ),
947 );
948 }
949 }
950
951 return array(
952 'action' => 'install',
953 'slug' => 'neve',
954 'nonce' => wp_create_nonce( 'switch-theme_neve' ),
955 );
956 }
957
958 /**
959 * Check if we can use the font pair to check for Google fonts.
960 *
961 * @param array $font_pair The font pair.
962 * @param string $key The key to check.
963 *
964 * @return bool
965 */
966 private function font_array_key_is_defined( $font_pair, $key = 'bodyFont' ) {
967 return isset( $font_pair[ $key ] ) && isset( $font_pair[ $key ]['fontSource'] ) && isset( $font_pair[ $key ]['font'] );
968 }
969
970 /**
971 * Check if the font pair is `Prata` and `Hanken Grotesk`.
972 *
973 * @param $font_pair
974 *
975 * @return bool
976 */
977 private function is_font_prata_and_hanke( $font_pair ) {
978 return $this->font_array_key_is_defined( $font_pair, 'bodyFont' ) && $this->font_array_key_is_defined( $font_pair, 'headingFont' ) && 'Prata' === $font_pair['headingFont']['font'] && 'Hanken Grotesk' === $font_pair['bodyFont']['font'];
979 }
980
981 /**
982 * Get the slug from the font pair.
983 *
984 * @param array $font_pair The font pair.
985 *
986 * @return string
987 */
988 private function get_slug_from_font_pair( $font_pair ) {
989 return strtolower( str_replace( ' ', '', $font_pair['headingFont']['font'] ) ) . '-' . strtolower( str_replace( ' ', '', $font_pair['bodyFont']['font'] ) );
990 }
991
992 /**
993 * Get font parings
994 */
995 private function get_font_parings() {
996 $font_pair_neve = array(
997 array(
998 'headingFont' => array(
999 'font' => 'Inter',
1000 'fontSource' => 'Google',
1001 'previewSize' => '25px',
1002 ),
1003 'bodyFont' => array(
1004 'font' => 'Inter',
1005 'fontSource' => 'Google',
1006 ),
1007 ),
1008 array(
1009 'headingFont' => array(
1010 'font' => 'Playfair Display',
1011 'fontSource' => 'Google',
1012 'previewSize' => '27px',
1013 ),
1014 'bodyFont' => array(
1015 'font' => 'Source Sans Pro',
1016 'fontSource' => 'Google',
1017 'previewSize' => '18px',
1018 ),
1019 ),
1020 array(
1021 'headingFont' => array(
1022 'font' => 'Montserrat',
1023 'fontSource' => 'Google',
1024 ),
1025 'bodyFont' => array(
1026 'font' => 'Open Sans',
1027 'fontSource' => 'Google',
1028 ),
1029 ),
1030 array(
1031 'headingFont' => array(
1032 'font' => 'Nunito',
1033 'fontSource' => 'Google',
1034 ),
1035 'bodyFont' => array(
1036 'font' => 'Lora',
1037 'fontSource' => 'Google',
1038 ),
1039 ),
1040 array(
1041 'headingFont' => array(
1042 'font' => 'Lato',
1043 'fontSource' => 'Google',
1044 ),
1045 'bodyFont' => array(
1046 'font' => 'Karla',
1047 'fontSource' => 'Google',
1048 ),
1049 ),
1050 array(
1051 'headingFont' => array(
1052 'font' => 'Outfit',
1053 'fontSource' => 'Google',
1054 'previewSize' => '25px',
1055 ),
1056 'bodyFont' => array(
1057 'font' => 'Spline Sans',
1058 'fontSource' => 'Google',
1059 ),
1060 ),
1061 array(
1062 'headingFont' => array(
1063 'font' => 'Lora',
1064 'fontSource' => 'Google',
1065 'previewSize' => '25px',
1066 ),
1067 'bodyFont' => array(
1068 'font' => 'Ubuntu',
1069 'fontSource' => 'Google',
1070 ),
1071 ),
1072 array(
1073 'headingFont' => array(
1074 'font' => 'Prata',
1075 'fontSource' => 'Google',
1076 'previewSize' => '25px',
1077 ),
1078 'bodyFont' => array(
1079 'font' => 'Hanken Grotesk',
1080 'fontSource' => 'Google',
1081 'previewSize' => '17px',
1082 ),
1083 ),
1084 array(
1085 'headingFont' => array(
1086 'font' => 'Albert Sans',
1087 'fontSource' => 'Google',
1088 'previewSize' => '25px',
1089 ),
1090 'bodyFont' => array(
1091 'font' => 'Albert Sans',
1092 'fontSource' => 'Google',
1093 'previewSize' => '17px',
1094 ),
1095 ),
1096 array(
1097 'headingFont' => array(
1098 'font' => 'Fraunces',
1099 'fontSource' => 'Google',
1100 'previewSize' => '25px',
1101 ),
1102 'bodyFont' => array(
1103 'font' => 'Hanken Grotesk',
1104 'fontSource' => 'Google',
1105 'previewSize' => '17px',
1106 ),
1107 ),
1108 );
1109
1110 if ( class_exists( '\Neve\Core\Settings\Mods', false ) ) {
1111 $font_pair_neve = apply_filters(
1112 'neve_font_pairings',
1113 \Neve\Core\Settings\Mods::get( \Neve\Core\Settings\Config::MODS_TPOGRAPHY_FONT_PAIRS, \Neve\Core\Settings\Config::$typography_default_pairs )
1114 );
1115 }
1116
1117 $index = 0;
1118 foreach ( $font_pair_neve as $font_pair ) {
1119 // limit the number of font pairs to first 5 and `Prata` and `Hanken Grotesk`.
1120 if ( $index > 4 && ! $this->is_font_prata_and_hanke( $font_pair ) ) {
1121 continue;
1122 }
1123 $slug = $this->get_slug_from_font_pair( $font_pair ) . '-' . $index;
1124 $this->font_pairs_neve[ $slug ] = $font_pair;
1125
1126 if ( $this->font_array_key_is_defined( $font_pair, 'bodyFont' ) && 'Google' === $font_pair['bodyFont']['fontSource'] && ! in_array( $font_pair['bodyFont']['font'], $this->google_fonts, true ) ) {
1127 $this->google_fonts[] = $font_pair['bodyFont']['font'];
1128 }
1129
1130 if ( $this->font_array_key_is_defined( $font_pair, 'headingFont' ) && 'Google' === $font_pair['headingFont']['fontSource'] && ! in_array( $font_pair['headingFont']['font'], $this->google_fonts, true ) ) {
1131 $this->google_fonts[] = $font_pair['headingFont']['font'];
1132 }
1133
1134 $index++;
1135 }
1136 }
1137
1138 /**
1139 * Memorize the previous theme to later display the import template for it.
1140 */
1141 public function get_previous_theme() {
1142 $previous_theme = strtolower( get_option( 'theme_switched' ) );
1143 set_theme_mod( 'ti_prev_theme', $previous_theme );
1144 }
1145
1146 /**
1147 * Add our onboarding query var.
1148 *
1149 * @param array $vars_array the registered query vars.
1150 *
1151 * @return array
1152 */
1153 public function add_onboarding_query_var( $vars_array ) {
1154 array_push( $vars_array, 'onboarding' );
1155
1156 return $vars_array;
1157 }
1158
1159 /**
1160 * Localize the sites library.
1161 *
1162 * @param array $array the about page array.
1163 *
1164 * @return array
1165 */
1166 public function localize_sites_library( $array ) {
1167 $api = array(
1168 'sites' => $this->get_sites_data(),
1169 'root' => esc_url_raw( rest_url( Main::API_ROOT ) ),
1170 'nonce' => wp_create_nonce( 'wp_rest' ),
1171 'homeUrl' => esc_url( home_url() ),
1172 'i18n' => $this->get_strings(),
1173 'onboarding' => false,
1174 'logUrl' => Logger::get_instance()->get_log_url(),
1175 );
1176
1177 $is_onboarding = isset( $_GET['onboarding'] ) && $_GET['onboarding'] === 'yes';
1178 if ( $is_onboarding ) {
1179 $api['onboarding'] = true;
1180 }
1181
1182 $array['onboarding'] = $api;
1183
1184 return $array;
1185 }
1186
1187 /**
1188 * Get all the sites data.
1189 *
1190 * @return array
1191 */
1192 public function get_sites_data() {
1193 $theme_support = get_theme_support( 'themeisle-demo-import' );
1194 if ( empty( $theme_support[0] ) || ! is_array( $theme_support[0] ) ) {
1195 return array();
1196 }
1197 $theme_support = $theme_support[0];
1198 $sites = isset( $theme_support['remote'] ) ? $theme_support['remote'] : null;
1199
1200 foreach ( $sites as $builder => $sites_for_builder ) {
1201 foreach ( $sites_for_builder as $slug => $data ) {
1202 $sites[ $builder ][ $slug ]['slug'] = $slug;
1203 if ( defined( 'TPC_REPLACE_API_SRC' ) && TPC_REPLACE_API_SRC === true ) {
1204 $api_src = defined( 'TPC_API_SRC' ) && ! empty( TPC_API_SRC ) ? TPC_API_SRC : self::API;
1205
1206 if ( isset( $sites[ $builder ][ $slug ]['remote_url'] ) ) {
1207 $sites[ $builder ][ $slug ]['remote_url'] = str_replace( self::API, $api_src, $sites[ $builder ][ $slug ]['remote_url'] );
1208 }
1209 $sites[ $builder ][ $slug ]['screenshot'] = str_replace( self::API, $api_src, $sites[ $builder ][ $slug ]['screenshot'] );
1210 }
1211 if ( ! isset( $data['upsell'] ) || $data['upsell'] !== true ) {
1212 continue;
1213 }
1214 $sites[ $builder ][ $slug ]['utmOutboundLink'] = add_query_arg(
1215 apply_filters(
1216 'ti_onboarding_outbound_query_args',
1217 array(
1218 'utm_medium' => 'about-' . get_template(),
1219 'utm_source' => 'wpadmin',
1220 'utm_content' => 'neve',
1221 'utm_campaign' => $slug,
1222 )
1223 ),
1224 $theme_support['pro_link']
1225 );
1226 }
1227 }
1228
1229 return array(
1230 'sites' => $sites,
1231 'migration' => $this->get_migrateable( $theme_support ),
1232 );
1233 }
1234
1235 /**
1236 * Get migratable data.
1237 *
1238 * This is used if we can ensure migration from a previous theme to a template.
1239 *
1240 * @param array $theme_support the theme support array.
1241 *
1242 * @return array|null
1243 */
1244 private function get_migrateable( $theme_support ) {
1245 if ( ! isset( $theme_support['can_migrate'] ) ) {
1246 return null;
1247 }
1248
1249 $data = $theme_support['can_migrate'];
1250 $old_theme = get_theme_mod( 'ti_prev_theme', 'ti_onboarding_undefined' );
1251 $folder_name = $old_theme;
1252 $previous_theme_slug = $this->get_parent_theme( $old_theme );
1253
1254 if ( ! empty( $previous_theme_slug ) ) {
1255 $folder_name = $previous_theme_slug;
1256 $old_theme = $previous_theme_slug;
1257 }
1258
1259 if ( ! array_key_exists( $old_theme, $data ) ) {
1260 return null;
1261 }
1262
1263 $content_imported = get_theme_mod( $data[ $old_theme ]['theme_mod_check'], 'not-imported' );
1264 if ( $content_imported === 'yes' ) {
1265 return null;
1266 }
1267
1268 if ( in_array( $old_theme, array( 'zerif-lite', 'zerif-pro' ), true ) ) {
1269 $folder_name = 'zelle';
1270 }
1271
1272 $options = array(
1273 'theme_name' => ! empty( $data[ $old_theme ]['theme_name'] ) ? esc_html( $data[ $old_theme ]['theme_name'] ) : '',
1274 'screenshot' => TIOB_URL . 'migration/' . $folder_name . '/' . $data[ $old_theme ]['template'] . '.png',
1275 'template' => TIOB_PATH . 'migration/' . $folder_name . '/' . $data[ $old_theme ]['template'] . '.json',
1276 'template_name' => $data[ $old_theme ]['template'],
1277 'heading' => $data[ $old_theme ]['heading'],
1278 'description' => $data[ $old_theme ]['description'],
1279 'theme_mod' => $data[ $old_theme ]['theme_mod_check'],
1280 'mandatory_plugins' => isset( $data[ $old_theme ]['mandatory_plugins'] ) ? $data[ $old_theme ]['mandatory_plugins'] : array(),
1281 'recommended_plugins' => isset( $data[ $old_theme ]['recommended_plugins'] ) ? $data[ $old_theme ]['recommended_plugins'] : array(),
1282 );
1283
1284 if ( ! empty( $previous_theme_slug ) ) {
1285 $options['description'] = __( 'Hi! We\'ve noticed you were using a child theme of Zelle before. To make your transition easier, we can help you keep the same homepage settings you had before but in original Zelle\'s style, by converting it into an Elementor template.', 'templates-patterns-collection' );
1286 }
1287
1288 return $options;
1289 }
1290
1291 /**
1292 * Get previous theme parent if it's a child theme.
1293 *
1294 * @param string $previous_theme Previous theme slug.
1295 *
1296 * @return string|bool
1297 */
1298 private function get_parent_theme( $previous_theme ) {
1299 $available_themes = wp_get_themes();
1300 if ( ! array_key_exists( $previous_theme, $available_themes ) ) {
1301 return false;
1302 }
1303 $theme_object = $available_themes[ $previous_theme ];
1304
1305 return $theme_object->get( 'Template' );
1306 }
1307
1308 /**
1309 * Get strings.
1310 *
1311 * @return array
1312 */
1313 private function get_strings() {
1314 return array(
1315 'preview_btn' => __( 'Preview', 'templates-patterns-collection' ),
1316 'import_btn' => __( 'Import', 'templates-patterns-collection' ),
1317 'pro_btn' => __( 'Get the PRO version!', 'templates-patterns-collection' ),
1318 'importing' => __( 'Importing', 'templates-patterns-collection' ),
1319 'cancel_btn' => __( 'Cancel', 'templates-patterns-collection' ),
1320 'loading' => __( 'Loading', 'templates-patterns-collection' ),
1321 'go_to_site' => __( 'View Website', 'templates-patterns-collection' ),
1322 'edit_template' => __( 'Add your own content', 'templates-patterns-collection' ),
1323 'back' => __( 'Back to Sites Library', 'templates-patterns-collection' ),
1324 'note' => __( 'Note', 'templates-patterns-collection' ),
1325 'advanced_options' => __( 'Advanced Options', 'templates-patterns-collection' ),
1326 'plugins' => __( 'Plugins', 'templates-patterns-collection' ),
1327 'general' => __( 'General', 'templates-patterns-collection' ),
1328 'later' => __( 'Keep current layout', 'templates-patterns-collection' ),
1329 'search' => __( 'Search', 'templates-patterns-collection' ),
1330 'content' => __( 'Content', 'templates-patterns-collection' ),
1331 'customizer' => __( 'Customizer', 'templates-patterns-collection' ),
1332 'widgets' => __( 'Widgets', 'templates-patterns-collection' ),
1333 'backup_disclaimer' => __( 'We recommend you backup your website content before attempting a full site import.', 'templates-patterns-collection' ),
1334 'placeholders_disclaimer' => __( 'Due to copyright issues, some of the demo images will not be imported and will be replaced by placeholder images.', 'templates-patterns-collection' ),
1335 'placeholders_disclaimer_new' => __( 'Some of the demo images will not be imported and will be replaced by placeholder images.', 'templates-patterns-collection' ),
1336 'unsplash_gallery_link' => __( 'Here is our own collection of related images you can use for your site.', 'templates-patterns-collection' ),
1337 'import_done' => __( 'Content was successfully imported. Enjoy your new site!', 'templates-patterns-collection' ),
1338 'pro_demo' => __( 'Available in the PRO version', 'templates-patterns-collection' ),
1339 'copy_error_code' => __( 'Copy error code', 'templates-patterns-collection' ),
1340 'download_error_log' => __( 'Download error log', 'templates-patterns-collection' ),
1341 'external_plugins_notice' => __( 'To import this demo you have to install the following plugins:', 'templates-patterns-collection' ),
1342 'rest_not_working' => sprintf(
1343 /* translators: 1 - 'here'. */
1344 __( 'It seems that Rest API is not working properly on your website. Read about how you can fix it %1$s.', 'templates-patterns-collection' ),
1345 sprintf( '<a href="https://docs.themeisle.com/article/1157-starter-sites-library-import-is-not-working#rest-api" target="_blank" rel="external noreferrer noopener">%1$s<i class="dashicons dashicons-external"></i></a>', __( 'here', 'templates-patterns-collection' ) )
1346 ),
1347 'error_report' => sprintf(
1348 /* translators: 1 - 'get in touch'. */
1349 __( 'Hi! It seems there is a configuration issue with your server that\'s causing the import to fail. Please %1$s with us with the error code below, so we can help you fix this.', 'templates-patterns-collection' ),
1350 sprintf( '<a href="https://themeisle.com/contact" target="_blank" rel="external noreferrer noopener">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'get in touch', 'templates-patterns-collection' ) )
1351 ),
1352 'troubleshooting' => sprintf(
1353 /* translators: 1 - 'troubleshooting guide'. */
1354 __( 'Hi! It seems there is a configuration issue with your server that\'s causing the import to fail. Take a look at our %1$s to see if any of the proposed solutions work.', 'templates-patterns-collection' ),
1355 sprintf( '<a href="https://docs.themeisle.com/article/1157-starter-sites-library-import-is-not-working" target="_blank" rel="external noreferrer noopener">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'troubleshooting guide', 'templates-patterns-collection' ) )
1356 ),
1357 'support' => sprintf(
1358 /* translators: 1 - 'get in touch'. */
1359 __( 'If none of the solutions in the guide work, please %1$s with us with the error code below, so we can help you fix this.', 'templates-patterns-collection' ),
1360 sprintf( '<a href="https://themeisle.com/contact" target="_blank" rel="external noreferrer noopener">%1$s <i class="dashicons dashicons-external"></i></a>', __( 'get in touch', 'templates-patterns-collection' ) )
1361 ),
1362 'fsDown' => sprintf(
1363 /* translators: %s - 'WP_Filesystem'. */
1364 __( 'It seems that %s is not available. You can contact your site administrator or hosting provider to help you enable it.', 'templates-patterns-collection' ),
1365 sprintf( '<code>WP_Filesystem</code>' )
1366 ),
1367 );
1368 }
1369
1370 /**
1371 * Check validity of addons plugin.
1372 *
1373 * @return bool
1374 */
1375 private function has_valid_addons() {
1376 if ( ! defined( 'NEVE_PRO_BASEFILE' ) ) {
1377 return false;
1378 }
1379
1380 $option_name = basename( dirname( NEVE_PRO_BASEFILE ) );
1381 $option_name = str_replace( '-', '_', strtolower( trim( $option_name ) ) );
1382 $status = get_option( $option_name . '_license_data' );
1383
1384 if ( ! $status ) {
1385 return false;
1386 }
1387
1388 if ( ! isset( $status->license ) ) {
1389 return false;
1390 }
1391
1392 if ( $status->license === 'not_active' || $status->license === 'invalid' ) {
1393 return false;
1394 }
1395
1396 return true;
1397 }
1398
1399 /**
1400 * Get logs from transient via ajax.
1401 */
1402 public function external_get_logs() {
1403
1404 $nonce = $_POST['nonce'];
1405
1406 if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
1407 wp_die( __( 'Nonce verification failed', 'templates-patterns-collection' ) );
1408 }
1409
1410 $data = get_transient( Logger::$log_transient_name );
1411
1412 if ( ! empty( $data ) ) {
1413 echo $data;
1414 wp_die();
1415 }
1416
1417 wp_die( __( 'No logs found', 'templates-patterns-collection' ) );
1418 }
1419
1420 private function get_prefix_for_menu_item() {
1421 $style = 'display:inline-block;';
1422
1423 if ( ! is_rtl() ) {
1424 $style .= 'transform:scaleX(-1);margin-right:5px;';
1425 } else {
1426 $style .= 'margin-left:5px;';
1427 }
1428
1429 $prefix = defined( 'NEVE_VERSION' ) ? '<span style="' . esc_attr( $style ) . '">&crarr;</span>' : '';
1430
1431 return $prefix;
1432 }
1433
1434 /**
1435 * Add Black Friday data.
1436 *
1437 * @param array $configs The configuration array for the loaded products.
1438 *
1439 * @return array
1440 */
1441 public function add_black_friday_data( $configs ) {
1442 $config = $configs['default'];
1443
1444 // translators: %1$s - plugin name, %2$s - HTML tag, %3$s - discount, %4$s - HTML tag, %5$s - company name.
1445 $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.', 'templates-patterns-collection' );
1446
1447 $config['message'] = sprintf( $message_template, 'Starter Sites & Templates by Neve', '<strong>', '70%', '</strong>', '<strong>Themeisle</strong>' );
1448 $config['sale_url'] = add_query_arg(
1449 array(
1450 'utm_term' => 'free',
1451 ),
1452 tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/all-bf', 'bfcm', 'templates-patterns-collection' ) )
1453 );
1454
1455 $configs[ TIOB_BASENAME ] = $config;
1456
1457 return $configs;
1458 }
1459 }
1460