PluginProbe ʕ •ᴥ•ʔ
SEOPress – AI SEO Plugin & On-site SEO / 9.3.0.3
SEOPress – AI SEO Plugin & On-site SEO v9.3.0.3
9.9.2 9.9.1 9.9 9.8.5 9.8.4 9.8.3 9.8.2 9.8.1 trunk 7.0 7.0.1 7.0.2 7.0.3 7.1 7.1.1 7.1.2 7.2 7.3 7.3.1 7.3.2 7.4 7.5 7.5.0.1 7.5.0.2 7.5.0.3 7.5.1 7.5.2 7.5.2.1 7.6 7.6.1 7.7 7.7.1 7.7.2 7.8 7.9 7.9.1 7.9.2 8.0 8.0.1 8.1 8.1.1 8.2 8.3 8.3.1 8.4 8.4.1 8.5 8.5.0.2 8.5.1 8.5.1.1 8.6 8.6.1 8.7 8.7.0.1 8.7.0.2 8.8 8.8.1 8.9 8.9.0.1 8.9.0.2 9.0 9.0.1 9.1 9.2 9.3 9.3.0.1 9.3.0.2 9.3.0.3 9.3.0.4 9.4 9.4.1 9.5 9.6 9.7 9.7.1 9.7.2 9.7.3 9.7.4 9.8
wp-seopress / seopress-functions.php
wp-seopress Last commit date
assets 7 months ago inc 7 months ago languages 7 months ago public 7 months ago src 7 months ago templates 7 months ago vendor 7 months ago contributors.txt 7 months ago readme.txt 7 months ago seopress-autoload.php 7 months ago seopress-functions.php 7 months ago seopress.php 7 months ago uninstall.php 7 months ago wpml-config.xml 7 months ago
seopress-functions.php
821 lines
1 <?php
2
3 /**
4 * Functions file
5 *
6 * @package SEOPress
7 */
8
9 defined( 'ABSPATH' ) || exit( 'Please don&rsquo;t call the plugin directly. Thanks :)' );
10
11 use SEOPress\Core\Kernel;
12
13 /**
14 * Get a service.
15 *
16 * @param string $service
17 *
18 * @return object
19 */
20 function seopress_get_service( $service ) {
21 return Kernel::getContainer()->getServiceByName( $service );
22 }
23
24 if ( ! function_exists( 'array_key_last' ) ) {
25 /**
26 * Get last key of an array if PHP < 7.3
27 *
28 * @param array $arr
29 *
30 * @return string
31 */
32 function array_key_last( array $arr ) {
33 end( $arr );
34 $key = key( $arr );
35
36 return $key;
37 }
38 }
39
40 if ( ! function_exists( 'array_key_first' ) ) {
41 /**
42 * Get first key of an array if PHP < 7.3
43 *
44 * @param array $arr
45 *
46 * @return string
47 */
48 function array_key_first( array $arr ) {
49 foreach ( $arr as $key => $unused ) {
50 return $key;
51 }
52
53 return null;
54 }
55 }
56
57 /**
58 * Remove default WordPress Canonical
59 */
60 remove_action( 'wp_head', 'rel_canonical' );
61
62 /**
63 * Remove WP default meta robots (added in WP 5.7)
64 */
65 remove_filter( 'wp_robots', 'wp_robots_max_image_preview_large' );
66
67 /**
68 * Remove WC default meta robots (added in WP 5.7)
69 *
70 * @param array $robots
71 *
72 * @todo use wp_robots API
73 */
74 function seopress_robots_wc_pages( $robots ) {
75 include_once ABSPATH . 'wp-admin/includes/plugin.php';
76 if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
77 if ( function_exists( 'wc_get_page_id' ) ) {
78 if ( is_page( wc_get_page_id( 'cart' ) ) || is_page( wc_get_page_id( 'checkout' ) ) || is_page( wc_get_page_id( 'myaccount' ) ) ) {
79 if ( '0' === get_option( 'blog_public' ) ) {
80 return $robots;
81 } else {
82 unset( $robots );
83 $robots = array();
84
85 return $robots;
86 }
87 }
88 }
89 }
90 // Remove noindex on search archive pages.
91 if ( is_search() ) {
92 if ( '0' === get_option( 'blog_public' ) ) {
93 return $robots;
94 } else {
95 unset( $robots );
96 $robots = array();
97
98 return $robots;
99 }
100 }
101
102 return $robots;
103 }
104 add_filter( 'wp_robots', 'seopress_robots_wc_pages', 20 );
105
106 /**
107 * Remove default WC meta robots (useful for WooCommerce < 5.7).
108 */
109 function seopress_compatibility_woocommerce() {
110 if ( ! is_admin() && function_exists( 'is_plugin_active' ) && is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
111 remove_action( 'wp_head', 'wc_page_noindex' );
112 }
113 }
114 add_action( 'wp_head', 'seopress_compatibility_woocommerce', 0 );
115
116 /**
117 * Remove Elementor description meta tag.
118 */
119 function seopress_compatibility_hello_elementor() {
120 remove_action( 'wp_head', 'hello_elementor_add_description_meta_tag' );
121 }
122 add_action( 'after_setup_theme', 'seopress_compatibility_hello_elementor' );
123
124 if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'sg-cachepress/sg-cachepress.php' ) ) {
125 /**
126 * Filter the xml sitemap URL used by SiteGround Optimizer for preheating.
127 *
128 * @param string $url URL to be preheated.
129 */
130 function sp_sg_file_caching_preheat_xml( $url ) {
131 $url = get_home_url() . '/sitemaps.xml';
132
133 return $url;
134 }
135 add_filter( 'sg_file_caching_preheat_xml', 'sp_sg_file_caching_preheat_xml' );
136 }
137
138 /**
139 * Remove WPML home url filter.
140 *
141 * @param mixed $home_url
142 * @param mixed $url
143 * @param mixed $path
144 * @param string $orig_scheme
145 * @param int $blog_id
146 */
147 function seopress_remove_wpml_home_url_filter( $home_url, $url, $path, $orig_scheme, $blog_id ) {
148 return $url;
149 }
150
151 /**
152 * Remove third-parties metaboxes on our CPT
153 */
154 add_action( 'do_meta_boxes', 'seopress_remove_metaboxes', 10 );
155 function seopress_remove_metaboxes() {
156 // Oxygen Builder.
157 remove_meta_box( 'ct_views_cpt', 'seopress_404', 'normal' );
158 remove_meta_box( 'ct_views_cpt', 'seopress_schemas', 'normal' );
159 remove_meta_box( 'ct_views_cpt', 'seopress_bot', 'normal' );
160 }
161
162 /**
163 * Get all custom fields (limit: 250).
164 *
165 * @return array custom field keys
166 */
167 function seopress_get_custom_fields() {
168 $cf_keys = wp_cache_get( 'seopress_get_custom_fields' );
169
170 if ( false === $cf_keys ) {
171 global $wpdb;
172
173 $limit = (int) apply_filters( 'postmeta_form_limit', 250 );
174 $cf_keys = $wpdb->get_col(
175 $wpdb->prepare(
176 "
177 SELECT DISTINCT meta_key
178 FROM $wpdb->postmeta
179 GROUP BY meta_key
180 HAVING meta_key NOT LIKE '\_%%'
181 ORDER BY meta_key
182 LIMIT %d",
183 $limit
184 )
185 );
186
187 if ( is_plugin_active( 'types/wpcf.php' ) ) {
188 $wpcf_fields = get_option( 'wpcf-fields' );
189
190 if ( ! empty( $wpcf_fields ) ) {
191 foreach ( $wpcf_fields as $key => $value ) {
192 $cf_keys[] = $value['meta_key'];
193 }
194 }
195 }
196
197 $cf_keys = apply_filters( 'seopress_get_custom_fields', $cf_keys );
198
199 if ( $cf_keys ) {
200 natcasesort( $cf_keys );
201 }
202 wp_cache_set( 'seopress_get_custom_fields', $cf_keys );
203 }
204
205 return $cf_keys;
206 }
207
208 /**
209 * Check SSL for schema.org.
210 *
211 * @return string correct protocol
212 */
213 function seopress_check_ssl() {
214 if ( is_ssl() ) {
215 return 'https://';
216 } else {
217 return 'http://';
218 }
219 }
220
221 /**
222 * Check if a string is base64 encoded
223 *
224 * @param string $str The string to check
225 * @return bool Returns true if the string is base64 encoded, false otherwise
226 */
227 function seopress_is_base64_string( $str ) {
228 // Check if the string is empty or not a string.
229 if ( empty( $str ) || ! is_string( $str ) ) {
230 return false;
231 }
232
233 // Decode the string and check if it decodes properly.
234 $decoded = base64_decode( $str, true );
235 if ( $decoded === false ) {
236 return false;
237 }
238
239 // Encode the decoded string and compare with the original string.
240 return base64_encode( $decoded ) === $str;
241 }
242
243 /**
244 * Disable Query Monitor for CA.
245 *
246 * @return array
247 *
248 * @param mixed $url
249 * @param mixed $allcaps
250 * @param mixed $caps
251 * @param mixed $args
252 */
253 function seopress_disable_qm( $allcaps, $caps, $args ) {
254 $allcaps['view_query_monitor'] = false;
255
256 return $allcaps;
257 }
258 /**
259 * Clear content for CA.
260 */
261 function seopress_clean_content_analysis() {
262 // Check if 'no_admin_bar' is set and equals '1'; sanitize input.
263 if ( ! isset( $_GET['no_admin_bar'] ) || '1' !== sanitize_text_field( wp_unslash( $_GET['no_admin_bar'] ) ) ) {
264 return;
265 }
266
267 // Check if the user is logged in and has the necessary capability.
268 if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
269 return;
270 }
271
272 // Remove admin bar.
273 add_filter( 'show_admin_bar', '__return_false' );
274
275 // Disable Query Monitor.
276 add_filter( 'user_has_cap', 'seopress_disable_qm', 10, 3 );
277
278 // Disable wptexturize.
279 add_filter( 'run_wptexturize', '__return_false' );
280
281 // Remove Edit nofollow links from TablePress.
282 add_filter( 'tablepress_edit_link_below_table', '__return_false' );
283
284 // Allow user to run custom action to clean content.
285 do_action( 'seopress_content_analysis_cleaning' );
286 }
287 add_action( 'plugins_loaded', 'seopress_clean_content_analysis' );
288
289 /**
290 * Test if a URL is in absolute.
291 *
292 * @return bool true if absolute
293 *
294 * @param mixed $url
295 */
296 function seopress_is_absolute( $url ) {
297 $pattern = "%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu";
298
299 return (bool) preg_match( $pattern, $url );
300 }
301
302 /**
303 * Manage localized links.
304 *
305 * @return string locale for documentation links
306 */
307 function seopress_get_locale() {
308 switch ( get_user_locale( get_current_user_id() ) ) {
309 case 'fr_FR':
310 case 'fr_BE':
311 case 'fr_CA':
312 case 'fr_LU':
313 case 'fr_MC':
314 case 'fr_CH':
315 $locale_link = 'fr';
316 break;
317 default:
318 $locale_link = '';
319 break;
320 }
321
322 return $locale_link;
323 }
324
325 /**
326 * Extract correct locale in ISO format from get_locale().
327 *
328 * @return string locale
329 */
330 function seopress_normalized_locale( $current_locale ) {
331 if ( ! function_exists( 'locale_get_primary_language' ) ) {
332 return $current_locale;
333 }
334
335 // Extract primary language and region.
336 $primary_language = locale_get_primary_language( $current_locale );
337 $region = locale_get_region( $current_locale );
338
339 // Check if region is available, if not, return only the primary language.
340 $normalized_locale = $primary_language . ( $region ? '_' . $region : '' );
341
342 return $normalized_locale;
343 }
344
345 /**
346 * Returns the language code by supporting multilingual plugins
347 *
348 * @return string language code
349 */
350 function seopress_get_current_lang() {
351 // Default.
352 $lang = seopress_normalized_locale( get_locale() );
353
354 // Polylang.
355 if ( function_exists( 'pll_current_language' ) ) {
356 $lang = pll_current_language( 'locale' );
357 }
358
359 // WPML.
360 if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
361 $lang = apply_filters( 'wpml_current_language', null );
362 }
363
364 return $lang;
365 }
366
367 /**
368 * Check empty global title template.
369 *
370 * @param string $type
371 * @param string $metadata
372 * @param bool $notice
373 *
374 * @return string notice with list of empty cpt titles
375 */
376 function seopress_get_empty_templates( $type, $metadata, $notice = true ) {
377 $cpt_titles_empty = array();
378 $templates = '';
379 $data = '';
380 $html = '';
381 $list = '';
382
383 if ( 'cpt' === $type ) {
384 $templates = $postTypes = seopress_get_service( 'WordPressData' )->getPostTypes();
385 $notice_i18n = __( 'Custom Post Types', 'wp-seopress' );
386 }
387 if ( 'tax' === $type ) {
388 $templates = seopress_get_service( 'WordPressData' )->getTaxonomies();
389 $notice_i18n = __( 'Custom Taxonomies', 'wp-seopress' );
390 }
391 foreach ( $templates as $key => $value ) {
392 $options = get_option( 'seopress_titles_option_name' );
393
394 if ( ! empty( $options ) ) {
395 if ( 'cpt' === $type ) {
396 if ( ! empty( $options['seopress_titles_single_titles'] ) ) {
397 if ( ! array_key_exists( $key, $options['seopress_titles_single_titles'] ) ) {
398 $cpt_titles_empty[] = $key;
399 } else {
400 $data = isset( $options['seopress_titles_single_titles'][ $key ][ $metadata ] ) ? $options['seopress_titles_single_titles'][ $key ][ $metadata ] : '';
401 }
402 }
403 }
404 if ( 'tax' === $type ) {
405 if ( ! empty( $options['seopress_titles_tax_titles'] ) ) {
406 if ( ! array_key_exists( $key, $options['seopress_titles_tax_titles'] ) ) {
407 $cpt_titles_empty[] = $key;
408 } else {
409 $data = isset( $options['seopress_titles_tax_titles'][ $key ][ $metadata ] ) ? $options['seopress_titles_tax_titles'][ $key ][ $metadata ] : '';
410 }
411 }
412 }
413 }
414
415 if ( empty( $data ) ) {
416 if ( seopress_get_service( 'TitleOption' )->getSingleCptEnable( $key ) !== '1' && seopress_get_service( 'TitleOption' )->getTaxEnable( $key ) !== '1' ) {
417 $cpt_titles_empty[] = $key;
418 }
419 }
420 }
421
422 if ( ! empty( $cpt_titles_empty ) ) {
423 $list .= '<ul>';
424 foreach ( $cpt_titles_empty as $cpt ) {
425 $list .= '<li>' . $cpt . '</li>';
426 }
427 $list .= '</ul>';
428
429 if ( false === $notice ) {
430 return $list;
431 } else {
432 $html .= '<div class="seopress-notice is-warning">
433 <p>';
434 /* translators: %1$s: "Custom Post Types" or "Custom Taxonomies", %2$s: "title" or "description" */
435 $html .= wp_kses_post( sprintf( __( 'Some <strong>%1$s</strong> have no <strong>meta %2$s</strong> set! We strongly encourage you to add one by filling in the fields below.', 'wp-seopress' ), esc_attr( $notice_i18n ), esc_attr( $metadata ) ) );
436 $html .= '</p>';
437 $html .= $list;
438 $html .= '</div>';
439
440 return $html;
441 }
442 }
443 }
444
445 /**
446 * Generate Permalink notice to prevent users from changing the permastructure on a live site.
447 *
448 * @return void
449 */
450 function seopress_notice_permalinks() {
451 $pagenow = isset( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : '';
452
453 if ( 'options-permalink.php' !== $pagenow ) {
454 return;
455 }
456
457 $class = 'notice notice-warning';
458 $message = sprintf(
459 '<p><strong>%s</strong></p><p>%s</p>',
460 __( 'WARNING', 'wp-seopress' ),
461 __( 'Do NOT change your permalink structure on a production site. Changing URLs can severely damage your SEO.', 'wp-seopress' )
462 );
463
464 printf( '<div class="%1$s">%2$s</div>', esc_attr( $class ), wp_kses_post( $message ) );
465 }
466 add_action( 'admin_notices', 'seopress_notice_permalinks' );
467
468 /**
469 * Generate a notice on permalink settings screen if URL rewriting is disabled.
470 *
471 * @return void
472 */
473 function seopress_notice_no_rewrite_url() {
474 $pagenow = isset( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : '';
475
476 // Check we are on the Permalink settings page.
477 if ( 'options-permalink.php' !== $pagenow ) {
478 return;
479 }
480
481 // Check permalink structure.
482 if ( '' !== get_option( 'permalink_structure' ) ) {
483 return;
484 }
485
486 // Display the notice.
487 $class = 'notice notice-warning';
488 $message = sprintf(
489 '<p><strong>%s</strong></p><p>%s</p>',
490 __( 'WARNING', 'wp-seopress' ),
491 __( 'URL rewriting is NOT enabled on your site. Select a permalink structure that is optimized for SEO (NOT Plain).', 'wp-seopress' )
492 );
493
494 printf( '<div class="%1$s">%2$s</div>', esc_attr( $class ), wp_kses_post( $message ) );
495 }
496 add_action( 'admin_notices', 'seopress_notice_no_rewrite_url' );
497
498 /**
499 * Generate Tooltip.
500 *
501 * @param string $tooltip_title, $tooltip_desc, $tooltip_code
502 * @param mixed $tooltip_desc
503 * @param mixed $tooltip_code
504 *
505 * @return string tooltip title, tooltip description, tooltip url
506 */
507 function seopress_tooltip( $tooltip_title, $tooltip_desc, $tooltip_code ) {
508 $html =
509 '<button type="button" class="sp-tooltip"><span class="dashicons dashicons-editor-help"></span>
510 <span class="sp-tooltiptext" role="tooltip" tabindex="0">
511 <span class="sp-tooltip-headings">' . $tooltip_title . '</span>
512 <span class="sp-tooltip-desc">' . $tooltip_desc . '</span>
513 <span class="sp-tooltip-code">' . $tooltip_code . '</span>
514 </span></button>';
515
516 return $html;
517 }
518
519 /**
520 * Generate Tooltip (alternative version).
521 *
522 * @param string $tooltip_title, $tooltip_desc, $tooltip_code
523 * @param mixed $tooltip_anchor
524 * @param mixed $tooltip_desc
525 *
526 * @return string tooltip title, tooltip description, tooltip url
527 */
528 function seopress_tooltip_alt( $tooltip_anchor, $tooltip_desc ) {
529 $html =
530 '<button type="button" class="sp-tooltip alt">' . $tooltip_anchor . '
531 <span class="sp-tooltiptext" role="tooltip" tabindex="0">
532 <span class="sp-tooltip-desc">' . $tooltip_desc . '</span>
533 </span>
534 </button>';
535
536 return $html;
537 }
538
539 /**
540 * Generate Tooltip link.
541 *
542 * @param string $tooltip_title, $tooltip_desc, $tooltip_code
543 * @param mixed $tooltip_anchor
544 * @param mixed $tooltip_desc
545 *
546 * @return string tooltip title, tooltip description, tooltip url
547 */
548 function seopress_tooltip_link( $tooltip_anchor, $tooltip_desc ) {
549 $html = '<a href="' . $tooltip_anchor . '"
550 target="_blank" class="seopress-doc">
551 <span class="dashicons dashicons-editor-help"></span>
552 <span class="screen-reader-text">
553 ' . $tooltip_desc . '
554 </span>
555 </a>';
556
557 return $html;
558 }
559
560 /**
561 * Remove BOM.
562 *
563 * @param mixed $text
564 *
565 * @return mixed $text
566 */
567 function seopress_remove_utf8_bom( $text ) {
568 $bom = pack( 'H*', 'EFBBBF' );
569 $text = preg_replace( "/^$bom/", '', $text );
570
571 return $text;
572 }
573
574 /**
575 * Filter the capability to allow other roles to use the plugin.
576 *
577 * @return string
578 *
579 * @param mixed $cap
580 * @param mixed $context
581 */
582 function seopress_capability( $cap, $context = '' ) {
583 $newcap = apply_filters( 'seopress_capability', $cap, $context );
584
585 if ( ! current_user_can( $newcap ) ) {
586 return $cap;
587 }
588
589 return $newcap;
590 }
591
592 /**
593 * Check if the page is one of ours.
594 *
595 * @return bool
596 */
597 function is_seopress_page() {
598 if ( ! is_admin() ) {
599 return false;
600 }
601
602 $page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : null;
603 $post_type = isset( $_REQUEST['post_type'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) ) : null;
604
605 if ( $page ) {
606 return strpos( $page, 'seopress' ) === 0;
607 }
608
609 if ( $post_type ) {
610 if ( is_array( $post_type ) && ! empty( $post_type ) ) {
611 return strpos( $post_type[0], 'seopress' ) === 0;
612 }
613 return strpos( $post_type, 'seopress' ) === 0;
614 }
615
616 return false;
617 }
618
619 /**
620 * Only add our notices on our pages.
621 *
622 * @since 3.8.2
623 *
624 * @return bool
625 */
626 function seopress_remove_other_notices() {
627 if ( is_seopress_page() ) {
628 remove_all_actions( 'network_admin_notices' );
629 remove_all_actions( 'admin_notices' );
630 remove_all_actions( 'user_admin_notices' );
631 remove_all_actions( 'all_admin_notices' );
632 add_action( 'admin_notices', 'seopress_admin_notices' );
633 if ( is_plugin_active( 'wp-seopress-pro/seopress-pro.php' ) ) {
634 if ( version_compare( SEOPRESS_PRO_VERSION, '6.4', '>=' ) ) {
635 add_action( 'admin_notices', 'seopress_pro_admin_notices' );
636 }
637 }
638 if ( is_plugin_active( 'wp-seopress-insights/seopress-insights.php' ) ) {
639 if ( version_compare( SEOPRESS_INSIGHTS_VERSION, '1.8.1', '>=' ) ) {
640 add_action( 'admin_notices', 'seopress_insights_notices' );
641 }
642 }
643 }
644 }
645 add_action( 'in_admin_header', 'seopress_remove_other_notices', 1000 ); // Keep this value high to remove other notices.
646
647 /**
648 * Only add our notices on our pages.
649 *
650 * @since 8.2.0
651 *
652 * @return bool
653 */
654 function seopress_remove_other_plugin_notices() {
655 if ( is_seopress_page() ) {
656 // SEOKEY plugin doesn't hook properly, we have to make a specific case.
657 remove_all_filters( 'seokey_filter_admin_notices_launch', 10 );
658 }
659 }
660 add_action( 'admin_init', 'seopress_remove_other_plugin_notices' );
661
662 /**
663 * We replace the WP action by ours.
664 *
665 * @since 3.8.2
666 *
667 * @return bool
668 */
669 function seopress_admin_notices() {
670 do_action( 'seopress_admin_notices' );
671 }
672
673 /**
674 * Check if a key exists in a multidimensional array.
675 *
676 * @since 3.8.2
677 *
678 * @return bool
679 *
680 * @param mixed $key
681 */
682 function seopress_if_key_exists( array $arr, $key ) {
683 // is in base array?
684 if ( array_key_exists( $key, $arr ) ) {
685 return true;
686 }
687
688 // Check arrays contained in this array.
689 foreach ( $arr as $element ) {
690 if ( is_array( $element ) ) {
691 if ( seopress_if_key_exists( $element, $key ) ) {
692 return true;
693 }
694 }
695 }
696
697 return false;
698 }
699
700 /**
701 * Output submit button.
702 *
703 * @since 5.0
704 *
705 * @param mixed $value
706 * @param mixed $classes
707 * @param mixed $type
708 */
709 function sp_submit_button( $value = '', $classes = 'btn btnPrimary', $type = 'submit' ) {
710 if ( '' === $value ) {
711 $value = __( 'Save changes', 'wp-seopress' );
712 }
713
714 // Use esc_attr_e to escape attributes in the output.
715 $html = '<p class="submit"><input id="submit" name="submit" type="' . esc_attr( $type ) . '" class="' . esc_attr( $classes ) . '" value="' . esc_attr( $value ) . '"/></p>';
716
717 echo $html;
718 }
719
720
721 /**
722 * Generate HTML buttons classes
723 *
724 * @since 5.0
725 *
726 * @return
727 */
728 function seopress_btn_secondary_classes() {
729 // Classic Editor compatibility.
730 global $pagenow;
731 if ( function_exists( 'get_current_screen' ) && method_exists( get_current_screen(), 'is_block_editor' ) && true === get_current_screen()->is_block_editor() ) {
732 $btn_classes_secondary = 'components-button is-secondary';
733 } elseif ( isset( $pagenow ) && ( $pagenow === 'term.php' || $pagenow === 'post.php' || $pagenow === 'post-new.php' ) ) {
734 $btn_classes_secondary = 'button button-secondary';
735 } else {
736 $btn_classes_secondary = 'btn btnSecondary';
737 }
738
739 return $btn_classes_secondary;
740 }
741
742 /**
743 * Global check.
744 *
745 * @since 3.8
746 *
747 * @param string $feature Feature name to check.
748 *
749 * @return string|null Toggle option value if exists, null otherwise.
750 */
751 function seopress_get_toggle_option( $feature ) {
752 $seopress_get_toggle_option = get_option( 'seopress_toggle' );
753 if ( ! empty( $seopress_get_toggle_option ) ) {
754 foreach ( $seopress_get_toggle_option as $key => $seopress_get_toggle_value ) {
755 $options[ $key ] = $seopress_get_toggle_value;
756 if ( isset( $seopress_get_toggle_option[ 'toggle-' . $feature ] ) ) {
757 return $seopress_get_toggle_option[ 'toggle-' . $feature ];
758 }
759 }
760 }
761 }
762
763 /**
764 * Disable Add to cart GA tracking code on archive page / related products for Elementor PRO to avoid a JS conflict.
765 *
766 * @since 5.3
767 * @return empty string
768 */
769 require_once ABSPATH . 'wp-admin/includes/plugin.php';
770 if ( is_plugin_active( 'elementor-pro/elementor-pro.php' ) ) {
771 add_filter( 'seopress_gtag_ec_add_to_cart_archive_ev', 'sp_elementor_gtag_ec_add_to_cart_archive_ev' );
772 function sp_elementor_gtag_ec_add_to_cart_archive_ev( $js ) {
773 return '';
774 }
775 }
776
777 /**
778 * Helper function needed for PHP 8.1 compatibility with "current" function
779 * Get mangled object vars.
780 *
781 * @since 6.2.0
782 */
783 function seopress_maybe_mangled_object_vars( $data ) {
784 if ( ! function_exists( 'get_mangled_object_vars' ) ) {
785 return $data;
786 }
787
788 if ( ! is_object( $data ) ) {
789 return $data;
790 }
791
792 return get_mangled_object_vars( $data );
793 }
794
795 /**
796 * Generate dynamically the Instant Indexing API key
797 *
798 * @since 8.6.0
799 *
800 * @param bool $init
801 *
802 * @return void
803 */
804 function seopress_instant_indexing_generate_api_key_fn( $init = false ) {
805 $options = get_option( 'seopress_instant_indexing_option_name' ) ? get_option( 'seopress_instant_indexing_option_name' ) : array();
806
807 $api_key = wp_generate_uuid4();
808 $api_key = preg_replace( '[-]', '', $api_key );
809 $options['seopress_instant_indexing_bing_api_key'] = base64_encode( $api_key );
810
811 if ( true === $init ) {
812 $options['seopress_instant_indexing_automate_submission'] = '1';
813 }
814
815 update_option( 'seopress_instant_indexing_option_name', $options );
816
817 if ( false === $init ) {
818 wp_send_json_success();
819 }
820 }
821