• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 5118024680

pending completion
5118024680

push

github

mykola
Merge branch 'feature/html-parser' of github.com:Yoast/wordpress-seo into feature/html-parser

9582 of 23984 relevant lines covered (39.95%)

3.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.66
/src/integrations/settings-integration.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations;
4

5
use WP_Post_Type;
6
use WP_Taxonomy;
7
use WP_User;
8
use WPSEO_Admin_Asset_Manager;
9
use WPSEO_Admin_Editor_Specific_Replace_Vars;
10
use WPSEO_Admin_Recommended_Replace_Vars;
11
use WPSEO_Option_Titles;
12
use WPSEO_Options;
13
use WPSEO_Replace_Vars;
14
use WPSEO_Shortlinker;
15
use WPSEO_Sitemaps_Router;
16
use Yoast\WP\SEO\Conditionals\Settings_Conditional;
17
use Yoast\WP\SEO\Config\Schema_Types;
18
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
19
use Yoast\WP\SEO\Helpers\Language_Helper;
20
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
21
use Yoast\WP\SEO\Helpers\Product_Helper;
22
use Yoast\WP\SEO\Helpers\Schema\Article_Helper;
23
use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
24
use Yoast\WP\SEO\Helpers\User_Helper;
25
use Yoast\WP\SEO\Helpers\Woocommerce_Helper;
26
use Yoast_Notification_Center;
27

28
/**
29
 * Class Settings_Integration.
30
 */
31
class Settings_Integration implements Integration_Interface {
32

33
        const PAGE = 'wpseo_page_settings';
34

35
        /**
36
         * Holds the included WordPress options.
37
         *
38
         * @var string[]
39
         */
40
        const WP_OPTIONS = [ 'blogdescription' ];
41

42
        /**
43
         * Holds the allowed option groups.
44
         *
45
         * @var array
46
         */
47
        const ALLOWED_OPTION_GROUPS = [ 'wpseo', 'wpseo_titles', 'wpseo_social' ];
48

49
        /**
50
         * Holds the disallowed settings, per option group.
51
         *
52
         * @var array
53
         */
54
        const DISALLOWED_SETTINGS = [
55
                'wpseo'        => [
56
                        'myyoast-oauth',
57
                        'semrush_tokens',
58
                        'custom_taxonomy_slugs',
59
                        'zapier_subscription',
60
                        'import_cursors',
61
                        'workouts_data',
62
                        'configuration_finished_steps',
63
                        'importing_completed',
64
                        'wincher_tokens',
65
                        'least_readability_ignore_list',
66
                        'least_seo_score_ignore_list',
67
                        'most_linked_ignore_list',
68
                        'least_linked_ignore_list',
69
                        'indexables_page_reading_list',
70
                ],
71
                'wpseo_titles' => [
72
                        'company_logo_meta',
73
                        'person_logo_meta',
74
                ],
75
        ];
76

77
        /**
78
         * Holds the disabled on multisite settings, per option group.
79
         *
80
         * @var array
81
         */
82
        const DISABLED_ON_MULTISITE_SETTINGS = [
83
                'wpseo' => [
84
                        'deny_search_crawling',
85
                        'deny_wp_json_crawling',
86
                        'deny_adsbot_crawling',
87
                ],
88
        ];
89

90
        /**
91
         * Holds the WPSEO_Admin_Asset_Manager.
92
         *
93
         * @var WPSEO_Admin_Asset_Manager
94
         */
95
        protected $asset_manager;
96

97
        /**
98
         * Holds the WPSEO_Replace_Vars.
99
         *
100
         * @var WPSEO_Replace_Vars
101
         */
102
        protected $replace_vars;
103

104
        /**
105
         * Holds the Schema_Types.
106
         *
107
         * @var Schema_Types
108
         */
109
        protected $schema_types;
110

111
        /**
112
         * Holds the Current_Page_Helper.
113
         *
114
         * @var Current_Page_Helper
115
         */
116
        protected $current_page_helper;
117

118
        /**
119
         * Holds the Post_Type_Helper.
120
         *
121
         * @var Post_Type_Helper
122
         */
123
        protected $post_type_helper;
124

125
        /**
126
         * Holds the Language_Helper.
127
         *
128
         * @var Language_Helper
129
         */
130
        protected $language_helper;
131

132
        /**
133
         * Holds the Taxonomy_Helper.
134
         *
135
         * @var Taxonomy_Helper
136
         */
137
        protected $taxonomy_helper;
138

139
        /**
140
         * Holds the Product_Helper.
141
         *
142
         * @var Product_Helper
143
         */
144
        protected $product_helper;
145

146
        /**
147
         * Holds the Woocommerce_Helper.
148
         *
149
         * @var Woocommerce_Helper
150
         */
151
        protected $woocommerce_helper;
152

153
        /**
154
         * Holds the Article_Helper.
155
         *
156
         * @var Article_Helper
157
         */
158
        protected $article_helper;
159

160
        /**
161
         * Holds the User_Helper.
162
         *
163
         * @var User_Helper
164
         */
165
        protected $user_helper;
166

167
        /**
168
         * Constructs Settings_Integration.
169
         *
170
         * @param WPSEO_Admin_Asset_Manager $asset_manager       The WPSEO_Admin_Asset_Manager.
171
         * @param WPSEO_Replace_Vars        $replace_vars        The WPSEO_Replace_Vars.
172
         * @param Schema_Types              $schema_types        The Schema_Types.
173
         * @param Current_Page_Helper       $current_page_helper The Current_Page_Helper.
174
         * @param Post_Type_Helper          $post_type_helper    The Post_Type_Helper.
175
         * @param Language_Helper           $language_helper     The Language_Helper.
176
         * @param Taxonomy_Helper           $taxonomy_helper     The Taxonomy_Helper.
177
         * @param Product_Helper            $product_helper      The Product_Helper.
178
         * @param Woocommerce_Helper        $woocommerce_helper  The Woocommerce_Helper.
179
         * @param Article_Helper            $article_helper      The Article_Helper.
180
         * @param User_Helper               $user_helper         The User_Helper.
181
         */
182
        public function __construct(
183
                WPSEO_Admin_Asset_Manager $asset_manager,
184
                WPSEO_Replace_Vars $replace_vars,
185
                Schema_Types $schema_types,
186
                Current_Page_Helper $current_page_helper,
187
                Post_Type_Helper $post_type_helper,
188
                Language_Helper $language_helper,
189
                Taxonomy_Helper $taxonomy_helper,
190
                Product_Helper $product_helper,
191
                Woocommerce_Helper $woocommerce_helper,
192
                Article_Helper $article_helper,
193
                User_Helper $user_helper
194
        ) {
195
                $this->asset_manager       = $asset_manager;
×
196
                $this->replace_vars        = $replace_vars;
×
197
                $this->schema_types        = $schema_types;
×
198
                $this->current_page_helper = $current_page_helper;
×
199
                $this->taxonomy_helper     = $taxonomy_helper;
×
200
                $this->post_type_helper    = $post_type_helper;
×
201
                $this->language_helper     = $language_helper;
×
202
                $this->product_helper      = $product_helper;
×
203
                $this->woocommerce_helper  = $woocommerce_helper;
×
204
                $this->article_helper      = $article_helper;
×
205
                $this->user_helper         = $user_helper;
×
206
        }
207

208
        /**
209
         * Returns the conditionals based on which this loadable should be active.
210
         *
211
         * @return array
212
         */
213
        public static function get_conditionals() {
214
                return [ Settings_Conditional::class ];
2✔
215
        }
216

217
        /**
218
         * Initializes the integration.
219
         *
220
         * This is the place to register hooks and filters.
221
         *
222
         * @return void
223
         */
224
        public function register_hooks() {
225
                // Add page.
226
                \add_filter( 'wpseo_submenu_pages', [ $this, 'add_page' ] );
×
227
                \add_filter( 'admin_menu', [ $this, 'add_settings_saved_page' ] );
×
228

229
                // Are we saving the settings?
230
                if ( $this->current_page_helper->get_current_admin_page() === 'options.php' ) {
×
231
                        // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged -- This deprecation will be addressed later.
232
                        $post_action = \filter_input( \INPUT_POST, 'action', @\FILTER_SANITIZE_STRING );
×
233
                        $option_page = \filter_input( \INPUT_POST, 'option_page', @\FILTER_SANITIZE_STRING );
×
234
                        // phpcs:enable
235

236
                        if ( $post_action === 'update' && $option_page === self::PAGE ) {
×
237
                                \add_action( 'admin_init', [ $this, 'register_setting' ] );
×
238
                                \add_action( 'in_admin_header', [ $this, 'remove_notices' ], \PHP_INT_MAX );
×
239
                        }
240

241
                        return;
×
242
                }
243

244
                // Are we on the settings page?
245
                if ( $this->current_page_helper->get_current_yoast_seo_page() === self::PAGE ) {
×
246
                        \add_action( 'admin_init', [ $this, 'register_setting' ] );
×
247
                        \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
×
248
                        \add_action( 'in_admin_header', [ $this, 'remove_notices' ], \PHP_INT_MAX );
×
249

250
                        // Remove the post types and taxonomies made public notifications (if any).
251
                        $this->remove_post_types_made_public_notification();
×
252
                        $this->remove_taxonomies_made_public_notification();
×
253
                }
254
        }
255

256
        /**
257
         * Registers the different options under the setting.
258
         *
259
         * @return void
260
         */
261
        public function register_setting() {
262
                foreach ( WPSEO_Options::$options as $name => $instance ) {
×
263
                        if ( \in_array( $name, self::ALLOWED_OPTION_GROUPS, true ) ) {
×
264
                                \register_setting( self::PAGE, $name );
×
265
                        }
266
                }
267
                // Only register WP options when the user is allowed to manage them.
268
                if ( \current_user_can( 'manage_options' ) ) {
×
269
                        foreach ( self::WP_OPTIONS as $name ) {
×
270
                                \register_setting( self::PAGE, $name );
×
271
                        }
272
                }
273
        }
274

275
        /**
276
         * Adds the page.
277
         *
278
         * @param array $pages The pages.
279
         *
280
         * @return array The pages.
281
         */
282
        public function add_page( $pages ) {
283
                \array_splice(
×
284
                        $pages,
×
285
                        1,
×
286
                        0,
×
287
                        [
288
                                [
289
                                        'wpseo_dashboard',
×
290
                                        '',
×
291
                                        \__( 'Settings', 'wordpress-seo' ),
×
292
                                        'wpseo_manage_options',
×
293
                                        self::PAGE,
×
294
                                        [ $this, 'display_page' ],
×
295
                                ],
296
                        ]
297
                );
298

299
                return $pages;
×
300
        }
301

302
        /**
303
         * Adds a dummy page.
304
         *
305
         * Because the options route NEEDS to redirect to something.
306
         *
307
         * @param array $pages The pages.
308
         *
309
         * @return array The pages.
310
         */
311
        public function add_settings_saved_page( $pages ) {
312
                \add_submenu_page(
2✔
313
                        '',
2✔
314
                        '',
2✔
315
                        '',
2✔
316
                        'wpseo_manage_options',
2✔
317
                        self::PAGE . '_saved',
2✔
318
                        static function () {
1✔
319
                                // Add success indication to HTML response.
320
                                $success = empty( \get_settings_errors() ) ? 'true' : 'false';
×
321
                                echo \esc_html( "{{ yoast-success: $success }}" );
×
322
                        }
2✔
323
                );
1✔
324

325
                return $pages;
2✔
326
        }
327

328
        /**
329
         * Displays the page.
330
         */
331
        public function display_page() {
332
                echo '<div id="yoast-seo-settings"></div>';
×
333
        }
334

335
        /**
336
         * Enqueues the assets.
337
         *
338
         * @return void
339
         */
340
        public function enqueue_assets() {
341
                // Remove the emoji script as it is incompatible with both React and any contenteditable fields.
342
                \remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
×
343
                \wp_enqueue_media();
×
344
                $this->asset_manager->enqueue_script( 'new-settings' );
×
345
                $this->asset_manager->enqueue_style( 'new-settings' );
×
346
                $this->asset_manager->localize_script( 'new-settings', 'wpseoScriptData', $this->get_script_data() );
×
347
        }
348

349
        /**
350
         * Removes all current WP notices.
351
         *
352
         * @return void
353
         */
354
        public function remove_notices() {
355
                \remove_all_actions( 'admin_notices' );
×
356
                \remove_all_actions( 'user_admin_notices' );
×
357
                \remove_all_actions( 'network_admin_notices' );
×
358
                \remove_all_actions( 'all_admin_notices' );
×
359
        }
360

361
        /**
362
         * Creates the script data.
363
         *
364
         * @return array The script data.
365
         */
366
        protected function get_script_data() {
367
                $default_setting_values = $this->get_default_setting_values();
×
368
                $settings               = $this->get_settings( $default_setting_values );
×
369
                $post_types             = $this->post_type_helper->get_indexable_post_type_objects();
×
370
                $taxonomies             = $this->taxonomy_helper->get_indexable_taxonomy_objects();
×
371

372
                // Check if attachments are included in indexation.
373
                if ( ! \array_key_exists( 'attachment', $post_types ) ) {
×
374
                        // Always include attachments in the settings, to let the user enable them again.
375
                        $attachment_object = \get_post_type_object( 'attachment' );
×
376
                        if ( ! empty( $attachment_object ) ) {
×
377
                                $post_types['attachment'] = $attachment_object;
×
378
                        }
379
                }
380
                // Check if post formats are included in indexation.
381
                if ( ! \array_key_exists( 'post_format', $taxonomies ) ) {
×
382
                        // Always include post_format in the settings, to let the user enable them again.
383
                        $post_format_object = \get_taxonomy( 'post_format' );
×
384
                        if ( ! empty( $post_format_object ) ) {
×
385
                                $taxonomies['post_format'] = $post_format_object;
×
386
                        }
387
                }
388

389
                $transformed_post_types = $this->transform_post_types( $post_types );
×
390
                $transformed_taxonomies = $this->transform_taxonomies( $taxonomies, \array_keys( $transformed_post_types ) );
×
391

392
                return [
393
                        'settings'             => $this->transform_settings( $settings ),
×
394
                        'defaultSettingValues' => $default_setting_values,
×
395
                        'disabledSettings'     => $this->get_disabled_settings( $settings ),
×
396
                        'endpoint'             => \admin_url( 'options.php' ),
×
397
                        'nonce'                => \wp_create_nonce( self::PAGE . '-options' ),
×
398
                        'separators'           => WPSEO_Option_Titles::get_instance()->get_separator_options_for_display(),
×
399
                        'replacementVariables' => $this->get_replacement_variables(),
×
400
                        'schema'               => $this->get_schema( $transformed_post_types ),
×
401
                        'preferences'          => $this->get_preferences( $settings ),
×
402
                        'linkParams'           => WPSEO_Shortlinker::get_query_params(),
×
403
                        'postTypes'            => $transformed_post_types,
×
404
                        'taxonomies'           => $transformed_taxonomies,
×
405
                        'fallbacks'            => $this->get_fallbacks(),
×
406
                ];
407
        }
408

409
        /**
410
         * Retrieves the preferences.
411
         *
412
         * @param array $settings The settings.
413
         *
414
         * @return array The preferences.
415
         */
416
        protected function get_preferences( $settings ) {
417
                $shop_page_id             = $this->woocommerce_helper->get_shop_page_id();
×
418
                $homepage_is_latest_posts = \get_option( 'show_on_front' ) === 'posts';
×
419
                $page_on_front            = \get_option( 'page_on_front' );
×
420
                $page_for_posts           = \get_option( 'page_for_posts' );
×
421

422
                if ( empty( $page_on_front ) ) {
×
423
                        $page_on_front = $page_for_posts;
×
424
                }
425

426
                return [
427
                        'isPremium'                     => $this->product_helper->is_premium(),
×
428
                        'isRtl'                         => \is_rtl(),
×
429
                        'isNetworkAdmin'                => \is_network_admin(),
×
430
                        'isMainSite'                    => \is_main_site(),
×
431
                        'isWooCommerceActive'           => $this->woocommerce_helper->is_active(),
×
432
                        'isLocalSeoActive'              => \defined( 'WPSEO_LOCAL_FILE' ),
×
433
                        'isNewsSeoActive'               => \defined( 'WPSEO_NEWS_FILE' ),
×
434
                        'siteUrl'                       => \get_bloginfo( 'url' ),
×
435
                        'siteTitle'                     => \get_bloginfo( 'name' ),
×
436
                        'sitemapUrl'                    => WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' ),
×
437
                        'hasWooCommerceShopPage'        => $shop_page_id !== -1,
438
                        'editWooCommerceShopPageUrl'    => \get_edit_post_link( $shop_page_id, 'js' ),
×
439
                        'wooCommerceShopPageSettingUrl' => \get_admin_url( null, 'admin.php?page=wc-settings&tab=products' ),
×
440
                        'homepageIsLatestPosts'         => $homepage_is_latest_posts,
×
441
                        'homepagePageEditUrl'           => \get_edit_post_link( $page_on_front, 'js' ),
×
442
                        'homepagePostsEditUrl'          => \get_edit_post_link( $page_for_posts, 'js' ),
×
443
                        'createUserUrl'                 => \admin_url( 'user-new.php' ),
×
444
                        'editUserUrl'                   => \admin_url( 'user-edit.php' ),
×
445
                        'editTaxonomyUrl'               => \admin_url( 'edit-tags.php' ),
×
446
                        'generalSettingsUrl'            => \admin_url( 'options-general.php' ),
×
447
                        'companyOrPersonMessage'        => \apply_filters( 'wpseo_knowledge_graph_setting_msg', '' ),
×
448
                        'currentUserId'                 => \get_current_user_id(),
×
449
                        'canCreateUsers'                => \current_user_can( 'create_users' ),
×
450
                        'canEditUsers'                  => \current_user_can( 'edit_users' ),
×
451
                        'canManageOptions'              => \current_user_can( 'manage_options' ),
×
452
                        'userLocale'                    => \str_replace( '_', '-', \get_user_locale() ),
×
453
                        'pluginUrl'                     => \plugins_url( '', \WPSEO_FILE ),
×
454
                        'showForceRewriteTitlesSetting' => ! \current_theme_supports( 'title-tag' ) && ! ( \function_exists( 'wp_is_block_theme' ) && \wp_is_block_theme() ),
×
455
                        'upsellSettings'                => $this->get_upsell_settings(),
×
456
                        'siteRepresentsPerson'          => $this->get_site_represents_person( $settings ),
×
457
                ];
458
        }
459

460
        /**
461
         * Retrieves the currently represented person.
462
         *
463
         * @param array $settings The settings.
464
         *
465
         * @return array The currently represented person's ID and name.
466
         */
467
        protected function get_site_represents_person( $settings ) {
468
                $person = [
469
                        'id'   => false,
×
470
                        'name' => '',
471
                ];
472

473
                if ( isset( $settings['wpseo_titles']['company_or_person_user_id'] ) ) {
×
474
                        $person['id'] = $settings['wpseo_titles']['company_or_person_user_id'];
×
475
                        $user         = \get_userdata( $person['id'] );
×
476
                        if ( $user instanceof WP_User ) {
×
477
                                $person['name'] = $user->get( 'display_name' );
×
478
                        }
479
                }
480

481
                return $person;
×
482
        }
483

484
        /**
485
         * Returns settings for the Call to Buy (CTB) buttons.
486
         *
487
         * @return string[] The array of CTB settings.
488
         */
489
        public function get_upsell_settings() {
490
                return [
491
                        'actionId'     => 'load-nfd-ctb',
×
492
                        'premiumCtbId' => 'f6a84663-465f-4cb5-8ba5-f7a6d72224b2',
493
                ];
494
        }
495

496
        /**
497
         * Retrieves the default setting values.
498
         *
499
         * These default values are currently being used in the UI for dummy fields.
500
         * Dummy fields should not expose or reflect the actual data.
501
         *
502
         * @return array The default setting values.
503
         */
504
        protected function get_default_setting_values() {
505
                $defaults = [];
×
506

507
                // Add Yoast settings.
508
                foreach ( WPSEO_Options::$options as $option_name => $instance ) {
×
509
                        if ( \in_array( $option_name, self::ALLOWED_OPTION_GROUPS, true ) ) {
×
510
                                $option_instance          = WPSEO_Options::get_option_instance( $option_name );
×
511
                                $defaults[ $option_name ] = ( $option_instance ) ? $option_instance->get_defaults() : [];
×
512
                        }
513
                }
514
                // Add WP settings.
515
                foreach ( self::WP_OPTIONS as $option_name ) {
×
516
                        $defaults[ $option_name ] = '';
×
517
                }
518

519
                // Remove disallowed settings.
520
                foreach ( self::DISALLOWED_SETTINGS as $option_name => $disallowed_settings ) {
×
521
                        foreach ( $disallowed_settings as $disallowed_setting ) {
×
522
                                unset( $defaults[ $option_name ][ $disallowed_setting ] );
×
523
                        }
524
                }
525

526
                return $defaults;
×
527
        }
528

529
        /**
530
         * Retrieves the settings and their values.
531
         *
532
         * @param array $default_setting_values The default setting values.
533
         *
534
         * @return array The settings.
535
         */
536
        protected function get_settings( $default_setting_values ) {
537
                $settings = [];
×
538

539
                // Add Yoast settings.
540
                foreach ( WPSEO_Options::$options as $option_name => $instance ) {
×
541
                        if ( \in_array( $option_name, self::ALLOWED_OPTION_GROUPS, true ) ) {
×
542
                                $settings[ $option_name ] = \array_merge( $default_setting_values[ $option_name ], WPSEO_Options::get_option( $option_name ) );
×
543
                        }
544
                }
545
                // Add WP settings.
546
                foreach ( self::WP_OPTIONS as $option_name ) {
×
547
                        $settings[ $option_name ] = \get_option( $option_name );
×
548
                }
549

550
                // Remove disallowed settings.
551
                foreach ( self::DISALLOWED_SETTINGS as $option_name => $disallowed_settings ) {
×
552
                        foreach ( $disallowed_settings as $disallowed_setting ) {
×
553
                                unset( $settings[ $option_name ][ $disallowed_setting ] );
×
554
                        }
555
                }
556

557
                return $settings;
×
558
        }
559

560
        /**
561
         * Transforms setting values.
562
         *
563
         * @param array $settings The settings.
564
         *
565
         * @return array The settings.
566
         */
567
        protected function transform_settings( $settings ) {
568
                if ( isset( $settings['wpseo_titles']['breadcrumbs-sep'] ) ) {
×
569
                        /**
570
                         * The breadcrumbs separator default value is the HTML entity `&raquo;`.
571
                         * Which does not get decoded in our JS, while it did in our Yoast form. Decode it here as an exception.
572
                         */
573
                        $settings['wpseo_titles']['breadcrumbs-sep'] = \html_entity_decode(
×
574
                                $settings['wpseo_titles']['breadcrumbs-sep'],
×
575
                                ( \ENT_NOQUOTES | \ENT_HTML5 ),
×
576
                                'UTF-8'
×
577
                        );
578
                }
579

580
                /**
581
                 * Decode some WP options.
582
                 */
583
                $settings['blogdescription'] = \html_entity_decode(
×
584
                        $settings['blogdescription'],
×
585
                        ( \ENT_NOQUOTES | \ENT_HTML5 ),
×
586
                        'UTF-8'
×
587
                );
588

589
                return $settings;
×
590
        }
591

592
        /**
593
         * Retrieves the disabled settings.
594
         *
595
         * @param array $settings The settings.
596
         *
597
         * @return array The settings.
598
         */
599
        protected function get_disabled_settings( $settings ) {
600
                $disabled_settings = [];
×
601
                $site_language     = $this->language_helper->get_language();
×
602

603
                foreach ( WPSEO_Options::$options as $option_name => $instance ) {
×
604
                        if ( ! \in_array( $option_name, self::ALLOWED_OPTION_GROUPS, true ) ) {
×
605
                                continue;
×
606
                        }
607

608
                        $disabled_settings[ $option_name ] = [];
×
609
                        $option_instance                   = WPSEO_Options::get_option_instance( $option_name );
×
610
                        if ( $option_instance === false ) {
×
611
                                continue;
×
612
                        }
613
                        foreach ( $settings[ $option_name ] as $setting_name => $setting_value ) {
×
614
                                if ( $option_instance->is_disabled( $setting_name ) ) {
×
615
                                        $disabled_settings[ $option_name ][ $setting_name ] = 'network';
×
616
                                }
617
                        }
618
                }
619

620
                // Remove disabled on multisite settings.
621
                if ( \is_multisite() ) {
×
622
                        foreach ( self::DISABLED_ON_MULTISITE_SETTINGS as $option_name => $disabled_ms_settings ) {
×
623
                                if ( \array_key_exists( $option_name, $disabled_settings ) ) {
×
624
                                        foreach ( $disabled_ms_settings as $disabled_ms_setting ) {
×
625
                                                $disabled_settings[ $option_name ][ $disabled_ms_setting ] = 'multisite';
×
626
                                        }
627
                                }
628
                        }
629
                }
630

631
                if ( \array_key_exists( 'wpseo', $disabled_settings ) && ! $this->language_helper->has_inclusive_language_support( $site_language ) ) {
×
632
                        $disabled_settings['wpseo']['inclusive_language_analysis_active'] = 'language';
×
633
                }
634

635
                return $disabled_settings;
×
636
        }
637

638
        /**
639
         * Retrieves the replacement variables.
640
         *
641
         * @return array The replacement variables.
642
         */
643
        protected function get_replacement_variables() {
644
                $recommended_replace_vars = new WPSEO_Admin_Recommended_Replace_Vars();
×
645
                $specific_replace_vars    = new WPSEO_Admin_Editor_Specific_Replace_Vars();
×
646
                $replacement_variables    = $this->replace_vars->get_replacement_variables_with_labels();
×
647

648
                return [
649
                        'variables'   => $replacement_variables,
×
650
                        'recommended' => $recommended_replace_vars->get_recommended_replacevars(),
×
651
                        'specific'    => $specific_replace_vars->get(),
×
652
                        'shared'      => $specific_replace_vars->get_generic( $replacement_variables ),
×
653
                ];
654
        }
655

656
        /**
657
         * Retrieves the schema.
658
         *
659
         * @param array $post_types The post types.
660
         *
661
         * @return array The schema.
662
         */
663
        protected function get_schema( array $post_types ) {
664
                $schema = [];
×
665

666
                foreach ( $this->schema_types->get_article_type_options() as $article_type ) {
×
667
                        $schema['articleTypes'][ $article_type['value'] ] = [
×
668
                                'label' => $article_type['name'],
×
669
                                'value' => $article_type['value'],
×
670
                        ];
671
                }
672

673
                foreach ( $this->schema_types->get_page_type_options() as $page_type ) {
×
674
                        $schema['pageTypes'][ $page_type['value'] ] = [
×
675
                                'label' => $page_type['name'],
×
676
                                'value' => $page_type['value'],
×
677
                        ];
678
                }
679

680
                $schema['articleTypeDefaults'] = [];
×
681
                $schema['pageTypeDefaults']    = [];
×
682
                foreach ( $post_types as $name => $post_type ) {
×
683
                        $schema['articleTypeDefaults'][ $name ] = WPSEO_Options::get_default( 'wpseo_titles', "schema-article-type-$name" );
×
684
                        $schema['pageTypeDefaults'][ $name ]    = WPSEO_Options::get_default( 'wpseo_titles', "schema-page-type-$name" );
×
685
                }
686

687
                return $schema;
×
688
        }
689

690
        /**
691
         * Transforms the post types, to represent them.
692
         *
693
         * @param WP_Post_Type[] $post_types The WP_Post_Type array to transform.
694
         *
695
         * @return array The post types.
696
         */
697
        protected function transform_post_types( $post_types ) {
698
                $transformed = [];
×
699
                foreach ( $post_types as $post_type ) {
×
700
                        $transformed[ $post_type->name ] = [
×
701
                                'name'                 => $post_type->name,
×
702
                                'route'                => $this->get_route( $post_type->name, $post_type->rewrite, $post_type->rest_base ),
×
703
                                'label'                => $post_type->label,
×
704
                                'singularLabel'        => $post_type->labels->singular_name,
×
705
                                'hasArchive'           => $this->post_type_helper->has_archive( $post_type ),
×
706
                                'hasSchemaArticleType' => $this->article_helper->is_article_post_type( $post_type->name ),
×
707
                                'menuPosition'         => $post_type->menu_position,
×
708
                        ];
709
                }
710

711
                \uasort( $transformed, [ $this, 'compare_post_types' ] );
×
712

713
                return $transformed;
×
714
        }
715

716
        /**
717
         * Compares two post types.
718
         *
719
         * @param array $a The first post type.
720
         * @param array $b The second post type.
721
         *
722
         * @return int The order.
723
         */
724
        protected function compare_post_types( $a, $b ) {
725
                if ( $a['menuPosition'] === null && $b['menuPosition'] !== null ) {
×
726
                        return 1;
×
727
                }
728
                if ( $a['menuPosition'] !== null && $b['menuPosition'] === null ) {
×
729
                        return -1;
×
730
                }
731

732
                if ( $a['menuPosition'] === null && $b['menuPosition'] === null ) {
×
733
                        // No position specified, order alphabetically by label.
734
                        return \strnatcmp( $a['label'], $b['label'] );
×
735
                }
736

737
                return ( ( $a['menuPosition'] < $b['menuPosition'] ) ? -1 : 1 );
×
738
        }
739

740
        /**
741
         * Transforms the taxonomies, to represent them.
742
         *
743
         * @param WP_Taxonomy[] $taxonomies      The WP_Taxonomy array to transform.
744
         * @param string[]      $post_type_names The post type names.
745
         *
746
         * @return array The taxonomies.
747
         */
748
        protected function transform_taxonomies( $taxonomies, $post_type_names ) {
749
                $transformed = [];
×
750
                foreach ( $taxonomies as $taxonomy ) {
×
751
                        $transformed[ $taxonomy->name ] = [
×
752
                                'name'          => $taxonomy->name,
×
753
                                'route'         => $this->get_route( $taxonomy->name, $taxonomy->rewrite, $taxonomy->rest_base ),
×
754
                                'label'         => $taxonomy->label,
×
755
                                'showUi'        => $taxonomy->show_ui,
×
756
                                'singularLabel' => $taxonomy->labels->singular_name,
×
757
                                'postTypes'     => \array_filter(
×
758
                                        $taxonomy->object_type,
×
759
                                        static function ( $object_type ) use ( $post_type_names ) {
760
                                                return \in_array( $object_type, $post_type_names, true );
×
761
                                        }
762
                                ),
763
                        ];
764
                }
765

766
                \uasort(
×
767
                        $transformed,
×
768
                        static function ( $a, $b ) {
769
                                return \strnatcmp( $a['label'], $b['label'] );
770
                        }
771
                );
772

773
                return $transformed;
774
        }
775

776
        /**
777
         * Gets the route from a name, rewrite and rest_base.
778
         *
779
         * @param string $name      The name.
780
         * @param array  $rewrite   The rewrite data.
781
         * @param string $rest_base The rest base.
782
         *
783
         * @return string The route.
784
         */
785
        protected function get_route( $name, $rewrite, $rest_base ) {
786
                $route = $name;
×
787
                if ( isset( $rewrite['slug'] ) ) {
788
                        $route = $rewrite['slug'];
×
789
                }
790
                if ( ! empty( $rest_base ) ) {
791
                        $route = $rest_base;
792
                }
793
                // Always strip leading slashes.
794
                while ( \substr( $route, 0, 1 ) === '/' ) {
795
                        $route = \substr( $route, 1 );
796
                }
797

798
                return \rawurlencode( $route );
799
        }
800

801
        /**
802
         * Retrieves the fallbacks.
803
         *
804
         * @return array The fallbacks.
805
         */
806
        protected function get_fallbacks() {
807
                $site_logo_id = \get_option( 'site_logo' );
×
808
                if ( ! $site_logo_id ) {
809
                        $site_logo_id = \get_theme_mod( 'custom_logo' );
×
810
                }
811
                if ( ! $site_logo_id ) {
812
                        $site_logo_id = '0';
813
                }
814

815
                return [
816
                        'siteLogoId' => $site_logo_id,
817
                ];
818
        }
819

820
        /**
821
         * Removes the notification related to the post types which have been made public.
822
         *
823
         * @return void
824
         */
825
        private function remove_post_types_made_public_notification() {
826
                $notification_center = Yoast_Notification_Center::get();
×
827
                $notification_center->remove_notification_by_id( 'post-types-made-public' );
828
        }
829

830
        /**
831
         * Removes the notification related to the taxonomies which have been made public.
832
         *
833
         * @return void
834
         */
835
        private function remove_taxonomies_made_public_notification() {
836
                $notification_center = Yoast_Notification_Center::get();
×
837
                $notification_center->remove_notification_by_id( 'taxonomies-made-public' );
×
838
        }
839
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc