PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | admin/metabox/class-metabox.php +177 -125 18.2 → trunk View file →
@@ -4,11 +4,9 @@
4 4 *
5 5 * @package WPSEO\Admin
6 6 */
7 7
8 -use Yoast\WP\SEO\Conditionals\Admin\Estimated_Reading_Time_Conditional;
9 -use Yoast\WP\SEO\Conditionals\Admin\Post_Conditional;
10 -use Yoast\WP\SEO\Helpers\Input_Helper;
8 +use Yoast\WP\SEO\Editors\Application\Site\Website_Information_Repository;
11 9 use Yoast\WP\SEO\Presenters\Admin\Alert_Presenter;
12 10 use Yoast\WP\SEO\Presenters\Admin\Meta_Fields_Presenter;
13 11
14 12 /**
@@ -16,9 +14,9 @@
16 14 */
17 15 class WPSEO_Metabox extends WPSEO_Meta {
18 16
19 17 /**
20 - * Whether or not the social tab is enabled.
18 + * Whether the social tab is enabled.
21 19 *
22 20 * @var bool
23 21 */
24 22 private $social_is_enabled;
@@ -23,9 +21,9 @@
23 21 */
24 22 private $social_is_enabled;
25 23
26 24 /**
27 - * Helper to determine whether or not the SEO analysis is enabled.
25 + * Helper to determine whether the SEO analysis is enabled.
28 26 *
29 27 * @var WPSEO_Metabox_Analysis_SEO
30 28 */
31 29 protected $seo_analysis;
@@ -30,9 +28,9 @@
30 28 */
31 29 protected $seo_analysis;
32 30
33 31 /**
34 - * Helper to determine whether or not the readability analysis is enabled.
32 + * Helper to determine whether the readability analysis is enabled.
35 33 *
36 34 * @var WPSEO_Metabox_Analysis_Readability
37 35 */
38 36 protected $readability_analysis;
@@ -37,8 +35,15 @@
37 35 */
38 36 protected $readability_analysis;
39 37
40 38 /**
39 + * Helper to determine whether the inclusive language analysis is enabled.
40 + *
41 + * @var WPSEO_Metabox_Analysis_Inclusive_Language
42 + */
43 + protected $inclusive_language_analysis;
44 +
45 + /**
41 46 * The metabox editor object.
42 47 *
43 48 * @var WPSEO_Metabox_Editor
44 49 */
@@ -46,14 +51,14 @@
46 51
47 52 /**
48 53 * The Metabox post.
49 54 *
50 - * @var WP_Post
55 + * @var WP_Post|null
51 56 */
52 57 protected $post = null;
53 58
54 59 /**
55 - * Whether or not the advanced metadata is enabled.
60 + * Whether the advanced metadata is enabled.
56 61 *
57 62 * @var bool
58 63 */
59 64 protected $is_advanced_metadata_enabled;
@@ -58,20 +63,14 @@
58 63 */
59 64 protected $is_advanced_metadata_enabled;
60 65
61 66 /**
62 - * Represents the estimated_reading_time_conditional.
63 - *
64 - * @var Estimated_Reading_Time_Conditional
65 - */
66 - protected $estimated_reading_time_conditional;
67 -
68 - /**
69 67 * Class constructor.
70 68 */
71 69 public function __construct() {
72 70 if ( $this->is_internet_explorer() ) {
73 71 add_action( 'add_meta_boxes', [ $this, 'internet_explorer_metabox' ] );
72 +
74 73 return;
75 74 }
76 75
77 76 add_action( 'add_meta_boxes', [ $this, 'add_meta_box' ] );
@@ -78,23 +77,15 @@
78 77 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
79 78 add_action( 'wp_insert_post', [ $this, 'save_postdata' ] );
80 79 add_action( 'edit_attachment', [ $this, 'save_postdata' ] );
81 80 add_action( 'add_attachment', [ $this, 'save_postdata' ] );
82 - add_action( 'admin_init', [ $this, 'translate_meta_boxes' ] );
83 81
84 - $this->editor = new WPSEO_Metabox_Editor();
85 - $this->editor->register_hooks();
82 + $this->social_is_enabled = WPSEO_Options::get( 'opengraph', false, [ 'wpseo_social' ] ) || WPSEO_Options::get( 'twitter', false, [ 'wpseo_social' ] );
83 + $this->is_advanced_metadata_enabled = WPSEO_Capability_Utils::current_user_can( 'wpseo_edit_advanced_metadata' ) || WPSEO_Options::get( 'disableadvanced_meta', null, [ 'wpseo' ] ) === false;
86 84
87 - $this->social_is_enabled = WPSEO_Options::get( 'opengraph', false ) || WPSEO_Options::get( 'twitter', false );
88 - $this->is_advanced_metadata_enabled = WPSEO_Capability_Utils::current_user_can( 'wpseo_edit_advanced_metadata' ) || WPSEO_Options::get( 'disableadvanced_meta' ) === false;
89 -
90 - $this->estimated_reading_time_conditional = new Estimated_Reading_Time_Conditional(
91 - new Post_Conditional(),
92 - new Input_Helper()
93 - );
94 -
95 - $this->seo_analysis = new WPSEO_Metabox_Analysis_SEO();
96 - $this->readability_analysis = new WPSEO_Metabox_Analysis_Readability();
85 + $this->seo_analysis = new WPSEO_Metabox_Analysis_SEO();
86 + $this->readability_analysis = new WPSEO_Metabox_Analysis_Readability();
87 + $this->inclusive_language_analysis = new WPSEO_Metabox_Analysis_Inclusive_Language();
97 88 }
98 89
99 90 /**
100 91 * Checks whether the request comes from an IE 11 browser.
@@ -116,8 +107,10 @@
116 107 }
117 108
118 109 /**
119 110 * Adds an alternative metabox for internet explorer users.
111 + *
112 + * @return void
120 113 */
121 114 public function internet_explorer_metabox() {
122 115 $post_types = WPSEO_Post_Type::get_accessible_post_types();
123 116 $post_types = array_filter( $post_types, [ $this, 'display_metabox' ] );
@@ -137,9 +130,9 @@
137 130 [ $this, 'render_internet_explorer_notice' ],
138 131 $post_type,
139 132 'normal',
140 133 apply_filters( 'wpseo_metabox_prio', 'high' ),
141 - [ '__block_editor_compatible_meta_box' => true ]
134 + [ '__block_editor_compatible_meta_box' => true ],
142 135 );
143 136 }
144 137 }
145 138
@@ -154,9 +147,9 @@
154 147 esc_html__( 'The browser you are currently using is unfortunately rather dated. Since we strive to give you the best experience possible, we no longer support this browser. Instead, please use %1$sFirefox%4$s, %2$sChrome%4$s or %3$sMicrosoft Edge%4$s.', 'wordpress-seo' ),
155 148 '<a href="https://www.mozilla.org/firefox/new/">',
156 149 '<a href="https://www.google.com/chrome/">',
157 150 '<a href="https://www.microsoft.com/windows/microsoft-edge">',
158 - '</a>'
151 + '</a>',
159 152 );
160 153
161 154 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped above.
162 155 echo new Alert_Presenter( $content );
@@ -166,10 +159,17 @@
166 159 * Translates text strings for use in the meta box.
167 160 *
168 161 * IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to
169 162 * the main meta box definition array in the class WPSEO_Meta() as well!!!!
163 + *
164 + * @deprecated 23.5
165 + * @codeCoverageIgnore
166 + *
167 + * @return void
170 168 */
171 169 public static function translate_meta_boxes() {
170 + _deprecated_function( __METHOD__, 'Yoast SEO 23.5' );
171 +
172 172 WPSEO_Meta::$meta_fields['general']['title']['title'] = __( 'SEO title', 'wordpress-seo' );
173 173 WPSEO_Meta::$meta_fields['general']['metadesc']['title'] = __( 'Meta description', 'wordpress-seo' );
174 174
175 175 /* translators: %s expands to the post type name. */
@@ -201,15 +201,15 @@
201 201 WPSEO_Meta::$meta_fields['advanced']['canonical']['description'] = sprintf(
202 202 /* translators: 1: link open tag; 2: link close tag. */
203 203 __( 'The canonical URL that this page should point to. Leave empty to default to permalink. %1$sCross domain canonical%2$s supported too.', 'wordpress-seo' ),
204 204 '<a href="https://googlewebmastercentral.blogspot.com/2009/12/handling-legitimate-cross-domain.html" target="_blank" rel="noopener">',
205 - WPSEO_Admin_Utils::get_new_tab_message() . '</a>'
205 + WPSEO_Admin_Utils::get_new_tab_message() . '</a>',
206 206 );
207 207
208 208 WPSEO_Meta::$meta_fields['advanced']['redirect']['title'] = __( '301 Redirect', 'wordpress-seo' );
209 209 WPSEO_Meta::$meta_fields['advanced']['redirect']['description'] = __( 'The URL that this page should redirect to.', 'wordpress-seo' );
210 210
211 - do_action( 'wpseo_tab_translate' );
211 + do_action_deprecated( 'wpseo_tab_translate', [], 'Yoast SEO 23.5', '', 'WPSEO_Metabox::translate_meta_boxes is deprecated.' );
212 212 }
213 213
214 214 /**
215 215 * Determines whether the metabox should be shown for the passed identifier.
@@ -250,9 +250,9 @@
250 250 [ $this, 'meta_box' ],
251 251 $post_type,
252 252 'normal',
253 253 apply_filters( 'wpseo_metabox_prio', 'high' ),
254 - [ '__block_editor_compatible_meta_box' => true ]
254 + [ '__block_editor_compatible_meta_box' => true ],
255 255 );
256 256 }
257 257 }
258 258
@@ -258,11 +258,11 @@
258 258
259 259 /**
260 260 * Adds CSS classes to the meta box.
261 261 *
262 - * @param array $classes An array of postbox CSS classes.
262 + * @param string[] $classes An array of postbox CSS classes.
263 263 *
264 - * @return array List of classes that will be applied to the editbox container.
264 + * @return string[] List of classes that will be applied to the editbox container.
265 265 */
266 266 public function wpseo_metabox_class( $classes ) {
267 267 $classes[] = 'yoast wpseo-metabox';
268 268
@@ -271,24 +271,18 @@
271 271
272 272 /**
273 273 * Passes variables to js for use with the post-scraper.
274 274 *
275 - * @return array
275 + * @return array<string, string|array<string|int|bool>|bool|int>
276 276 */
277 277 public function get_metabox_script_data() {
278 - $permalink = '';
278 + $permalink = $this->get_permalink();
279 279
280 - if ( is_object( $this->get_metabox_post() ) ) {
281 - $permalink = get_sample_permalink( $this->get_metabox_post()->ID );
282 - $permalink = $permalink[0];
283 - }
284 -
285 280 $post_formatter = new WPSEO_Metabox_Formatter(
286 - new WPSEO_Post_Metabox_Formatter( $this->get_metabox_post(), [], $permalink )
281 + new WPSEO_Post_Metabox_Formatter( $this->get_metabox_post(), [], $permalink ),
287 282 );
288 283
289 284 $values = $post_formatter->get_values();
290 -
291 285 /** This filter is documented in admin/filters/class-cornerstone-filter.php. */
292 286 $post_types = apply_filters( 'wpseo_cornerstone_post_types', WPSEO_Post_Type::get_accessible_post_types() );
293 287 if ( $values['cornerstoneActive'] && ! in_array( $this->get_metabox_post()->post_type, $post_types, true ) ) {
294 288 $values['cornerstoneActive'] = false;
@@ -331,8 +325,10 @@
331 325 }
332 326
333 327 /**
334 328 * Outputs the meta box.
329 + *
330 + * @return void
335 331 */
336 332 public function meta_box() {
337 333 $this->render_hidden_fields();
338 334 $this->render_tabs();
@@ -361,12 +357,27 @@
361 357 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in class.
362 358 echo new Meta_Fields_Presenter( $this->get_metabox_post(), 'social' );
363 359 }
364 360
361 + $is_block_editor = YoastSEO()->helpers->current_page->is_block_editor();
362 + if ( $is_block_editor && $this->get_metabox_post()->post_type === 'post' ) {
363 + /**
364 + * Filter: 'wpseo_enable_ai_content_planner_inline_banner' - Allows hiding the AI Content Planner inline banner site-wide.
365 + *
366 + * Returning false stops the hidden meta inputs from being rendered, which the editor JS treats as "banner disabled".
367 + *
368 + * @param bool $enabled Whether the inline banner should be available in the editor. Default true.
369 + */
370 + if ( apply_filters( 'wpseo_enable_ai_content_planner_inline_banner', true ) ) {
371 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in class.
372 + echo new Meta_Fields_Presenter( $this->get_metabox_post(), 'content_planner' );
373 + }
374 + }
375 +
365 376 /**
366 377 * Filter: 'wpseo_content_meta_section_content' - Allow filtering the metabox content before outputting.
367 378 *
368 - * @api string $post_content The metabox content string.
379 + * @param string $post_content The metabox content string.
369 380 */
370 381 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output should be escaped in the filter.
371 382 echo apply_filters( 'wpseo_content_meta_section_content', '' );
372 383 }
@@ -417,13 +428,17 @@
417 428 if ( $this->readability_analysis->is_enabled() ) {
418 429 $tabs[] = new WPSEO_Metabox_Section_Readability();
419 430 }
420 431
432 + if ( $this->inclusive_language_analysis->is_enabled() ) {
433 + $tabs[] = new WPSEO_Metabox_Section_Inclusive_Language();
434 + }
435 +
421 436 if ( $this->is_advanced_metadata_enabled ) {
422 437 $tabs[] = new WPSEO_Metabox_Section_React(
423 438 'schema',
424 439 '<span class="wpseo-schema-icon"></span>' . __( 'Schema', 'wordpress-seo' ),
425 - ''
440 + '',
426 441 );
427 442 }
428 443
429 444 if ( $this->social_is_enabled ) {
@@ -432,9 +447,9 @@
432 447 '<span class="dashicons dashicons-share"></span>' . __( 'Social', 'wordpress-seo' ),
433 448 '',
434 449 [
435 450 'html_after' => '<div id="wpseo-section-social"></div>',
436 - ]
451 + ],
437 452 );
438 453 }
439 454
440 455 $tabs = array_merge( $tabs, $this->get_additional_tabs() );
@@ -483,9 +498,9 @@
483 498 $tabs[] = new WPSEO_Metabox_Section_Additional(
484 499 $tab['name'],
485 500 $tab['link_content'],
486 501 $tab['content'],
487 - $options
502 + $options,
488 503 );
489 504 }
490 505 }
491 506
@@ -494,16 +509,19 @@
494 509
495 510 /**
496 511 * Adds a line in the meta box.
497 512 *
498 - * @todo [JRF] Check if $class is added appropriately everywhere.
513 + * @deprecated 23.5
514 + * @codeCoverageIgnore
499 515 *
500 - * @param array $meta_field_def Contains the vars based on which output is generated.
501 - * @param string $key Internal key (without prefix).
516 + * @param string[] $meta_field_def Contains the vars based on which output is generated.
517 + * @param string $key Internal key (without prefix).
502 518 *
503 519 * @return string
504 520 */
505 521 public function do_meta_box( $meta_field_def, $key = '' ) {
522 + _deprecated_function( __METHOD__, 'Yoast SEO 23.5' );
523 +
506 524 $content = '';
507 525 $esc_form_key = esc_attr( WPSEO_Meta::$form_prefix . $key );
508 526 $meta_value = WPSEO_Meta::get_value( $key, $this->get_metabox_post()->ID );
509 527
@@ -591,9 +609,8 @@
591 609 }
592 610
593 611 $options_count = count( $meta_field_def['options'] );
594 612
595 - // This select now uses Select2.
596 613 $content .= '<select multiple="multiple" size="' . esc_attr( $options_count ) . '" name="' . $esc_form_key . '[]" id="' . $esc_form_key . '" class="yoast' . $class . '"' . $aria_describedby . '>';
597 614 foreach ( $meta_field_def['options'] as $val => $option ) {
598 615 $selected = '';
599 616 if ( in_array( $val, $selected_arr, true ) ) {
@@ -621,38 +638,13 @@
621 638 }
622 639 unset( $val, $option, $checked );
623 640 }
624 641 break;
625 -
626 - case 'upload':
627 - $content .= '<input' .
628 - ' id="' . $esc_form_key . '"' .
629 - ' type="text"' .
630 - ' size="36"' .
631 - ' class="' . $class . '"' .
632 - ' name="' . $esc_form_key . '"' .
633 - ' value="' . esc_attr( $meta_value ) . '"' . $aria_describedby .
634 - ' readonly="readonly"' .
635 - ' /> ';
636 - $content .= '<input' .
637 - ' id="' . esc_attr( $esc_form_key ) . '_button"' .
638 - ' class="wpseo_image_upload_button button"' .
639 - ' data-target="' . esc_attr( $esc_form_key ) . '"' .
640 - ' data-target-id="' . esc_attr( $esc_form_key ) . '-id"' .
641 - ' type="button"' .
642 - ' value="' . esc_attr__( 'Upload Image', 'wordpress-seo' ) . '"' .
643 - ' /> ';
644 - $content .= '<input' .
645 - ' class="wpseo_image_remove_button button"' .
646 - ' type="button"' .
647 - ' value="' . esc_attr__( 'Clear Image', 'wordpress-seo' ) . '"' .
648 - ' />';
649 - break;
650 642 }
651 643
652 644 $html = '';
653 645 if ( $content === '' ) {
654 - $content = apply_filters( 'wpseo_do_meta_box_field_' . $key, $content, $meta_value, $esc_form_key, $meta_field_def, $key );
646 + $content = apply_filters_deprecated( 'wpseo_do_meta_box_field_' . $key, [ $content, $meta_value, $esc_form_key, $meta_field_def, $key ], 'Yoast SEO 23.5', '', 'do_meta_box is deprecated' );
655 647 }
656 648
657 649 if ( $content !== '' ) {
658 650
@@ -710,9 +702,10 @@
710 702 if ( $post_id === null ) {
711 703 return false;
712 704 }
713 705
714 - if ( ! isset( $_POST['yoast_free_metabox_nonce'] ) || ! wp_verify_nonce( $_POST['yoast_free_metabox_nonce'], 'yoast_free_metabox' ) ) {
706 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in wp_verify_none.
707 + if ( ! isset( $_POST['yoast_free_metabox_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['yoast_free_metabox_nonce'] ), 'yoast_free_metabox' ) ) {
715 708 return false;
716 709 }
717 710
718 711 if ( wp_is_post_revision( $post_id ) ) {
@@ -747,11 +740,16 @@
747 740 $meta_boxes,
748 741 WPSEO_Meta::get_meta_field_defs( 'general', $post->post_type ),
749 742 WPSEO_Meta::get_meta_field_defs( 'advanced' ),
750 743 $social_fields,
751 - WPSEO_Meta::get_meta_field_defs( 'schema', $post->post_type )
744 + WPSEO_Meta::get_meta_field_defs( 'schema', $post->post_type ),
752 745 );
753 746
747 + // We can't detect in save_postdata whether the request is coming from the block editor, so we gate the content_planner fields on post type only.
748 + if ( $post->post_type === 'post' ) {
749 + $meta_boxes = array_merge( $meta_boxes, WPSEO_Meta::get_meta_field_defs( 'content_planner' ) );
750 + }
751 +
754 752 foreach ( $meta_boxes as $key => $meta_box ) {
755 753
756 754 // If analysis is disabled remove that analysis score value from the DB.
757 755 if ( $this->is_meta_value_disabled( $key ) ) {
@@ -801,9 +799,9 @@
801 799 *
802 800 * @return bool Whether the given meta value key is disabled.
803 801 */
804 802 public function is_meta_value_disabled( $key ) {
805 - if ( $key === 'linkdex' && ! $this->seo_analysis->is_enabled() ) {
803 + if ( in_array( $key, [ 'linkdex', 'seo_title_score', 'meta_description_score' ], true ) && ! $this->seo_analysis->is_enabled() ) {
806 804 return true;
807 805 }
808 806
809 807 if ( $key === 'content_score' && ! $this->readability_analysis->is_enabled() ) {
@@ -809,8 +807,12 @@
809 807 if ( $key === 'content_score' && ! $this->readability_analysis->is_enabled() ) {
810 808 return true;
811 809 }
812 810
811 + if ( $key === 'inclusive_language_score' && ! $this->inclusive_language_analysis->is_enabled() ) {
812 + return true;
813 + }
814 +
813 815 return false;
814 816 }
815 817
816 818 /**
@@ -816,31 +818,35 @@
816 818 /**
817 819 * Enqueues all the needed JS and CSS.
818 820 *
819 821 * @todo [JRF => whomever] Create css/metabox-mp6.css file and add it to the below allowed colors array when done.
822 + *
823 + * @return void
820 824 */
821 825 public function enqueue() {
822 826 global $pagenow;
823 827
828 + if ( $this->readability_analysis->is_enabled() ) {
829 + $this->editor = new WPSEO_Metabox_Editor();
830 + $this->editor->register_hooks();
831 + }
832 +
824 833 $asset_manager = new WPSEO_Admin_Asset_Manager();
825 834
826 - $is_editor = self::is_post_overview( $pagenow ) || self::is_post_edit( $pagenow );
827 -
828 835 if ( self::is_post_overview( $pagenow ) ) {
829 - $asset_manager->enqueue_style( 'edit-page' );
830 - $asset_manager->enqueue_script( 'edit-page' );
831 -
832 836 return;
833 837 }
834 838
835 839 /* Filter 'wpseo_always_register_metaboxes_on_admin' documented in wpseo-main.php */
836 - if ( ( $is_editor === false && apply_filters( 'wpseo_always_register_metaboxes_on_admin', false ) === false ) || $this->display_metabox() === false ) {
840 + if ( ( self::is_post_edit( $pagenow ) === false && apply_filters( 'wpseo_always_register_metaboxes_on_admin', false ) === false ) || $this->display_metabox() === false ) {
837 841 return;
838 842 }
839 843
840 844 $post_id = get_queried_object_id();
841 - if ( empty( $post_id ) && isset( $_GET['post'] ) ) {
842 - $post_id = sanitize_text_field( filter_input( INPUT_GET, 'post' ) );
845 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
846 + if ( empty( $post_id ) && isset( $_GET['post'] ) && is_string( $_GET['post'] ) ) {
847 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
848 + $post_id = sanitize_text_field( wp_unslash( $_GET['post'] ) );
843 849 }
844 850
845 851 if ( $post_id !== 0 ) {
846 852 // Enqueue files needed for upload functionality.
@@ -847,13 +853,16 @@
847 853 wp_enqueue_media( [ 'post' => $post_id ] );
848 854 }
849 855
850 856 $asset_manager->enqueue_style( 'metabox-css' );
851 - $asset_manager->enqueue_style( 'scoring' );
852 - $asset_manager->enqueue_style( 'select2' );
857 + if ( $this->readability_analysis->is_enabled() ) {
858 + $asset_manager->enqueue_style( 'scoring' );
859 + }
853 860 $asset_manager->enqueue_style( 'monorepo' );
861 + $asset_manager->enqueue_style( 'ai-generator' );
862 + $asset_manager->enqueue_style( 'ai-fix-assessments' );
854 863
855 - $is_block_editor = WP_Screen::get()->is_block_editor();
864 + $is_block_editor = YoastSEO()->helpers->current_page->is_block_editor();
856 865 $post_edit_handle = 'post-edit';
857 866 if ( ! $is_block_editor ) {
858 867 $post_edit_handle = 'post-edit-classic';
859 868 }
@@ -869,9 +878,8 @@
869 878 $asset_manager->localize_script( $post_edit_handle, 'wpseoAdminL10n', WPSEO_Utils::get_admin_l10n() );
870 879
871 880 $plugins_script_data = [
872 881 'replaceVars' => [
873 - 'no_parent_text' => __( '(no parent)', 'wordpress-seo' ),
874 882 'replace_vars' => $this->get_replace_vars(),
875 883 'hidden_replace_vars' => $this->get_hidden_replace_vars(),
876 884 'recommended_replace_vars' => $this->get_recommended_replace_vars(),
877 885 'scope' => $this->determine_scope(),
@@ -877,10 +885,10 @@
877 885 'scope' => $this->determine_scope(),
878 886 'has_taxonomies' => $this->current_post_type_has_taxonomies(),
879 887 ],
880 888 'shortcodes' => [
889 + 'wpseo_shortcode_tags' => $this->get_valid_shortcode_tags(),
881 890 'wpseo_filter_shortcodes_nonce' => wp_create_nonce( 'wpseo-filter-shortcodes' ),
882 - 'wpseo_shortcode_tags' => $this->get_valid_shortcode_tags(),
883 891 ],
884 892 ];
885 893
886 894 $worker_script_data = [
@@ -889,44 +897,49 @@
889 897 'keywords_assessment_url' => YoastSEO()->helpers->asset->get_asset_url( 'yoast-seo-used-keywords-assessment' ),
890 898 'log_level' => WPSEO_Utils::get_analysis_worker_log_level(),
891 899 ];
892 900
893 - $alert_dismissal_action = YoastSEO()->classes->get( \Yoast\WP\SEO\Actions\Alert_Dismissal_Action::class );
894 - $dismissed_alerts = $alert_dismissal_action->all_dismissed();
901 + $page_on_front = (int) get_option( 'page_on_front' );
902 + $homepage_is_page = get_option( 'show_on_front' ) === 'page';
903 + $is_front_page = $homepage_is_page && $page_on_front === (int) $post_id;
895 904
896 905 $script_data = [
897 - // @todo replace this translation with JavaScript translations.
898 - 'media' => [ 'choose_image' => __( 'Use Image', 'wordpress-seo' ) ],
899 - 'metabox' => $this->get_metabox_script_data(),
900 - 'userLanguageCode' => WPSEO_Language_Utils::get_language( \get_user_locale() ),
901 - 'isPost' => true,
902 - 'isBlockEditor' => $is_block_editor,
903 - 'postStatus' => get_post_status( $post_id ),
904 - 'analysis' => [
905 - 'plugins' => $plugins_script_data,
906 - 'worker' => $worker_script_data,
907 - 'estimatedReadingTimeEnabled' => $this->estimated_reading_time_conditional->is_met(),
906 + 'metabox' => $this->get_metabox_script_data(),
907 + 'isPost' => true,
908 + 'isBlockEditor' => $is_block_editor,
909 + 'postId' => $post_id,
910 + 'postStatus' => get_post_status( $post_id ),
911 + 'postType' => get_post_type( $post_id ),
912 + 'isPage' => get_post_type( $post_id ) === 'page',
913 + 'usedKeywordsNonce' => wp_create_nonce( 'wpseo-keyword-usage-and-post-types' ),
914 + 'analysis' => [
915 + 'plugins' => $plugins_script_data,
916 + 'worker' => $worker_script_data,
908 917 ],
909 - 'dismissedAlerts' => $dismissed_alerts,
918 + 'isFrontPage' => $is_front_page,
910 919 ];
911 920
912 - if ( post_type_supports( get_post_type(), 'thumbnail' ) ) {
921 + /**
922 + * The website information repository.
923 + *
924 + * @var Website_Information_Repository $repo
925 + */
926 + $repo = YoastSEO()->classes->get( Website_Information_Repository::class );
927 + $site_information = $repo->get_post_site_information();
928 + $site_information->set_permalink( $this->get_permalink() );
929 + $script_data = array_merge_recursive( $site_information->get_legacy_site_information(), $script_data );
930 +
931 + if ( ! $is_block_editor && post_type_supports( get_post_type(), 'thumbnail' ) ) {
913 932 $asset_manager->enqueue_style( 'featured-image' );
914 -
915 - // @todo replace this translation with JavaScript translations.
916 - $script_data['featuredImage'] = [
917 - 'featured_image_notice' => __( 'SEO issue: The featured image should be at least 200 by 200 pixels to be picked up by Facebook and other social media sites.', 'wordpress-seo' ),
918 - ];
919 933 }
920 934
921 935 $asset_manager->localize_script( $post_edit_handle, 'wpseoScriptData', $script_data );
922 - $asset_manager->enqueue_user_language_script();
923 936 }
924 937
925 938 /**
926 939 * Returns post in metabox context.
927 940 *
928 - * @return WP_Post|array
941 + * @return WP_Post|array<string|int|bool>
929 942 */
930 943 protected function get_metabox_post() {
931 944 if ( $this->post !== null ) {
932 945 return $this->post;
@@ -931,11 +944,12 @@
931 944 if ( $this->post !== null ) {
932 945 return $this->post;
933 946 }
934 947
935 - $post = filter_input( INPUT_GET, 'post' );
936 - if ( ! empty( $post ) ) {
937 - $post_id = (int) WPSEO_Utils::validate_int( $post );
948 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
949 + if ( isset( $_GET['post'] ) && is_string( $_GET['post'] ) ) {
950 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, Sanitization happens in the validate_int function.
951 + $post_id = (int) WPSEO_Utils::validate_int( wp_unslash( $_GET['post'] ) );
938 952
939 953 $this->post = get_post( $post_id );
940 954
941 955 return $this->post;
@@ -952,9 +966,9 @@
952 966
953 967 /**
954 968 * Returns an array with shortcode tags for all registered shortcodes.
955 969 *
956 - * @return array
970 + * @return string[]
957 971 */
958 972 private function get_valid_shortcode_tags() {
959 973 $shortcode_tags = [];
960 974
@@ -967,9 +981,9 @@
967 981
968 982 /**
969 983 * Prepares the replace vars for localization.
970 984 *
971 - * @return array Replace vars.
985 + * @return string[] Replace vars.
972 986 */
973 987 private function get_replace_vars() {
974 988 $cached_replacement_vars = [];
975 989
@@ -1016,9 +1030,9 @@
1016 1030
1017 1031 /**
1018 1032 * Prepares the recommended replace vars for localization.
1019 1033 *
1020 - * @return array Recommended replacement variables.
1034 + * @return array<string[]> Recommended replacement variables.
1021 1035 */
1022 1036 private function get_recommended_replace_vars() {
1023 1037 $recommended_replace_vars = new WPSEO_Admin_Recommended_Replace_Vars();
1024 1038
@@ -1032,9 +1046,9 @@
1032 1046 * Gets the custom replace variables for custom taxonomies and fields.
1033 1047 *
1034 1048 * @param WP_Post $post The post to check for custom taxonomies and fields.
1035 1049 *
1036 - * @return array Array containing all the replacement variables.
1050 + * @return array<string[]> Array containing all the replacement variables.
1037 1051 */
1038 1052 private function get_custom_replace_vars( $post ) {
1039 1053 return [
1040 1054 'custom_fields' => $this->get_custom_fields_replace_vars( $post ),
@@ -1046,9 +1060,9 @@
1046 1060 * Gets the custom replace variables for custom taxonomies.
1047 1061 *
1048 1062 * @param WP_Post $post The post to check for custom taxonomies.
1049 1063 *
1050 - * @return array Array containing all the replacement variables.
1064 + * @return array<string[]> Array containing all the replacement variables.
1051 1065 */
1052 1066 private function get_custom_taxonomies_replace_vars( $post ) {
1053 1067 $taxonomies = get_object_taxonomies( $post, 'objects' );
1054 1068 $custom_replace_vars = [];
@@ -1077,9 +1091,9 @@
1077 1091 * Gets the custom replace variables for custom fields.
1078 1092 *
1079 1093 * @param WP_Post $post The post to check for custom fields.
1080 1094 *
1081 - * @return array Array containing all the replacement variables.
1095 + * @return array<string[]> Array containing all the replacement variables.
1082 1096 */
1083 1097 private function get_custom_fields_replace_vars( $post ) {
1084 1098 $custom_replace_vars = [];
1085 1099
@@ -1094,8 +1108,25 @@
1094 1108 if ( ! is_array( $custom_fields ) ) {
1095 1109 return $custom_replace_vars;
1096 1110 }
1097 1111
1112 + $meta = YoastSEO()->meta->for_post( $post->ID );
1113 +
1114 + if ( ! $meta ) {
1115 + return $custom_replace_vars;
1116 + }
1117 +
1118 + // Simply concatenate all fields containing replace vars so we can handle them all with a single regex find.
1119 + $replace_vars_fields = implode(
1120 + ' ',
1121 + [
1122 + $meta->presentation->title,
1123 + $meta->presentation->meta_description,
1124 + ],
1125 + );
1126 +
1127 + preg_match_all( '/%%cf_([A-Za-z0-9_]+)%%/', $replace_vars_fields, $matches );
1128 + $fields_to_include = $matches[1];
1098 1129 foreach ( $custom_fields as $custom_field_name => $custom_field ) {
1099 1130 // Skip private custom fields.
1100 1131 if ( substr( $custom_field_name, 0, 1 ) === '_' ) {
1101 1132 continue;
@@ -1100,8 +1131,13 @@
1100 1131 if ( substr( $custom_field_name, 0, 1 ) === '_' ) {
1101 1132 continue;
1102 1133 }
1103 1134
1135 + // Skip custom fields that are not used, new ones will be fetched dynamically.
1136 + if ( ! in_array( $custom_field_name, $fields_to_include, true ) ) {
1137 + continue;
1138 + }
1139 +
1104 1140 // Skip custom field values that are serialized.
1105 1141 if ( is_serialized( $custom_field[0] ) ) {
1106 1142 continue;
1107 1143 }
@@ -1141,6 +1177,22 @@
1141 1177 * @return string The product title.
1142 1178 */
1143 1179 protected function get_product_title() {
1144 1180 return YoastSEO()->helpers->product->get_product_name();
1181 + }
1182 +
1183 + /**
1184 + * Gets the permalink.
1185 + *
1186 + * @return string
1187 + */
1188 + protected function get_permalink() {
1189 + $permalink = '';
1190 +
1191 + if ( is_object( $this->get_metabox_post() ) ) {
1192 + $permalink = get_sample_permalink( $this->get_metabox_post()->ID );
1193 + $permalink = $permalink[0];
1194 + }
1195 +
1196 + return $permalink;
1145 1197 }
1146 1198 }