PluginProbe
Parse.ly / 3.8.4
Parse.ly v3.8.4
3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 3.20.3 All 105 releases
← All changes | src/UI/class-settings-page.php +208 -612 3.16.4 → 3.8.4 View file →
@@ -9,12 +9,9 @@
9 9 declare(strict_types=1);
10 10
11 11 namespace Parsely\UI;
12 12
13 -use Parsely\Content_Helper\Excerpt_Generator;
14 13 use Parsely\Parsely;
15 -use Parsely\Permissions;
16 -use Parsely\Validator;
17 14
18 15 use function Parsely\Utils\get_asset_info;
19 16
20 17 use const Parsely\PARSELY_FILE;
@@ -26,10 +23,8 @@
26 23 *
27 24 * @phpstan-import-type Parsely_Options from Parsely
28 25 *
29 26 * @phpstan-type Setting_Arguments array{
30 - * add_fieldset?: bool,
31 - * legend?: string,
32 27 * option_key: string,
33 28 * label_for: string,
34 29 * title?: string,
35 30 * help_text?: string,
@@ -58,32 +53,17 @@
58 53 * disable_amp?: bool,
59 54 * track_post_types_as?: array<string, string>,
60 55 * track_post_types: string[],
61 56 * track_page_types: string[],
62 - * full_metadata_in_non_posts: ?bool,
63 57 * content_id_prefix?: string,
64 58 * use_top_level_cats?:bool|string,
65 59 * custom_taxonomy_section?: string,
66 60 * cats_as_tags?: bool|string,
67 - * content_helper: Parsely_Settings_Options_Content_Helper,
68 61 * lowercase_tags?: bool,
69 62 * force_https_canonicals?: bool,
70 63 * disable_autotrack?: bool|string,
64 + * parsely_wipe_metadata_cache: bool,
71 65 * }
72 - *
73 - * @phpstan-type Parsely_Settings_Options_Content_Helper array{
74 - * ai_features_enabled?: bool,
75 - * smart_linking?: Parsely_Settings_Options_Content_Helper_Feature,
76 - * title_suggestions?: Parsely_Settings_Options_Content_Helper_Feature,
77 - * excerpt_suggestions?: Parsely_Settings_Options_Content_Helper_Feature,
78 - * }
79 - *
80 - * @phpstan-type Parsely_Settings_Options_Content_Helper_Feature array{
81 - * enabled?: bool,
82 - * allowed_user_roles?: array<string, string>|array<string, bool>
83 - * }
84 - *
85 - * @phpstan-import-type Parsely_Options from Parsely
86 66 */
87 67 final class Settings_Page {
88 68 /**
89 69 * Instance of Parsely class.
@@ -101,30 +81,8 @@
101 81 */
102 82 private $hook_suffix;
103 83
104 84 /**
105 - * Options for badges that are displayed for managed options.
106 - *
107 - * @since 3.9.0
108 - *
109 - * @var array<string, mixed>
110 - */
111 - private $managed_options_badge = array();
112 -
113 - /**
114 - * The Content Helper features that can be configured in the settings page.
115 - *
116 - * @since 3.16.0
117 - *
118 - * @var string[]
119 - */
120 - private $configurable_pch_features = array(
121 - 'smart_linking',
122 - 'title_suggestions',
123 - 'excerpt_suggestions',
124 - );
125 -
126 - /**
127 85 * Constructor.
128 86 *
129 87 * @param Parsely $parsely Instance of Parsely class.
130 88 */
@@ -129,20 +87,8 @@
129 87 * @param Parsely $parsely Instance of Parsely class.
130 88 */
131 89 public function __construct( Parsely $parsely ) {
132 90 $this->parsely = $parsely;
133 -
134 - $managed_options_badge = apply_filters(
135 - 'wp_parsely_managed_options_badge',
136 - array(
137 - 'text' => __( 'Upgrade', 'wp-parsely' ),
138 - 'url' => 'https://www.parse.ly/getdemo/',
139 - )
140 - );
141 -
142 - if ( is_array( $managed_options_badge ) ) {
143 - $this->managed_options_badge = $managed_options_badge;
144 - }
145 91 }
146 92
147 93 /**
148 94 * Registers settings page.
@@ -157,35 +103,33 @@
157 103
158 104 /**
159 105 * Enqueues all needed scripts and styles for Parse.ly plugin settings page.
160 106 *
161 - * @param string|null $hook_suffix The current page being loaded.
107 + * @param string $hook_suffix The current page being loaded.
162 108 */
163 - public function enqueue_settings_assets( ?string $hook_suffix ): void {
164 - if ( ! is_string( $hook_suffix ) || 'settings_page_parsely' !== $hook_suffix ) {
165 - return;
166 - }
109 + public function enqueue_settings_assets( string $hook_suffix ): void {
110 + if ( 'settings_page_parsely' === $hook_suffix ) {
111 + add_filter( 'media_library_months_with_files', '__return_empty_array' );
112 + wp_enqueue_media();
167 113
168 - add_filter( 'media_library_months_with_files', '__return_empty_array' );
169 - wp_enqueue_media();
114 + $admin_settings_asset = get_asset_info( 'build/admin-settings.asset.php' );
115 + $built_assets_url = plugin_dir_url( PARSELY_FILE ) . '/build/';
170 116
171 - $admin_settings_asset = get_asset_info( 'build/admin-settings.asset.php' );
172 - $built_assets_url = plugin_dir_url( PARSELY_FILE ) . '/build/';
117 + wp_enqueue_script(
118 + 'parsely-admin-settings',
119 + $built_assets_url . 'admin-settings.js',
120 + $admin_settings_asset['dependencies'],
121 + $admin_settings_asset['version'],
122 + true
123 + );
173 124
174 - wp_enqueue_script(
175 - 'parsely-admin-settings',
176 - $built_assets_url . 'admin-settings.js',
177 - $admin_settings_asset['dependencies'],
178 - $admin_settings_asset['version'],
179 - true
180 - );
181 -
182 - wp_enqueue_style(
183 - 'parsely-admin-settings',
184 - $built_assets_url . 'admin-settings.css',
185 - $admin_settings_asset['dependencies'],
186 - $admin_settings_asset['version']
187 - );
125 + wp_enqueue_style(
126 + 'parsely-admin-settings',
127 + $built_assets_url . 'admin-settings.css',
128 + $admin_settings_asset['dependencies'],
129 + $admin_settings_asset['version']
130 + );
131 + }
188 132 }
189 133
190 134 /**
191 135 * Adds the Parse.ly settings page in WordPress settings menu.
@@ -193,9 +137,9 @@
193 137 public function add_settings_sub_menu(): void {
194 138 $suffix = add_options_page(
195 139 __( 'Parse.ly Settings', 'wp-parsely' ),
196 140 __( 'Parse.ly', 'wp-parsely' ),
197 - Parsely::CAPABILITY, // phpcs:ignore WordPress.WP.Capabilities.Undetermined
141 + Parsely::CAPABILITY,
198 142 Parsely::MENU_SLUG,
199 143 array( $this, 'display_settings' )
200 144 );
201 145
@@ -231,9 +175,8 @@
231 175 /**
232 176 * Displays the Parse.ly settings screen (options-general.php?page=[SLUG]).
233 177 */
234 178 public function display_settings(): void {
235 - // phpcs:ignore WordPress.WP.Capabilities.Undetermined
236 179 if ( ! current_user_can( Parsely::CAPABILITY ) ) {
237 180 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-parsely' ) );
238 181 }
239 182
@@ -243,25 +186,16 @@
243 186 /**
244 187 * Initializes the settings for Parse.ly.
245 188 */
246 189 public function initialize_settings(): void {
247 - // Add the option first, to prevent double sanitization of the uninitialized option as reported
248 - // in https://core.trac.wordpress.org/ticket/21989.
249 - // The option will be initialized with the default values.
250 - add_option( Parsely::OPTIONS_KEY, $this->parsely->get_options() );
251 -
252 190 // All our options are actually stored in one single array to reduce DB queries.
253 191 register_setting(
254 192 Parsely::OPTIONS_KEY,
255 193 Parsely::OPTIONS_KEY,
256 - array(
257 - 'type' => 'array',
258 - 'sanitize_callback' => array( $this, 'validate_options' ),
259 - )
194 + array( $this, 'validate_options' )
260 195 );
261 196
262 197 $this->initialize_basic_section();
263 - $this->initialize_content_helper_section();
264 198 $this->initialize_recrawl_section();
265 199 $this->initialize_advanced_section();
266 200 }
267 201
@@ -270,10 +204,9 @@
270 204 *
271 205 * @since 3.2.0
272 206 */
273 207 private function initialize_basic_section(): void {
274 - $are_credentials_managed = $this->parsely->are_credentials_managed;
275 - $section_key = 'basic-section';
208 + $section_key = 'basic-section';
276 209
277 210 add_settings_section(
278 211 $section_key,
279 212 __( 'Basic', 'wp-parsely' ),
@@ -289,15 +222,14 @@
289 222 'label_for' => $field_id,
290 223 'optional_args' => array(
291 224 'required' => 'required',
292 225 'placeholder' => 'mydomain.com',
293 - 'disabled' => $are_credentials_managed,
294 226 ),
295 227
296 228 );
297 229 add_settings_field(
298 230 $field_id,
299 - __( 'Site ID <em>(required)</em>', 'wp-parsely' ),
231 + __( 'Parse.ly Site ID <em>(required)</em>', 'wp-parsely' ),
300 232 array( $this, 'print_text_tag' ),
301 233 Parsely::MENU_SLUG,
302 234 $section_key,
303 235 $field_args
@@ -302,36 +234,54 @@
302 234 $section_key,
303 235 $field_args
304 236 );
305 237
306 - if ( ! $are_credentials_managed ) {
307 - // API Secret.
308 - $field_id = 'api_secret';
309 - $field_args = array(
310 - 'option_key' => $field_id,
311 - 'help_text' => __( 'Your API secret is your secret code to <a href="https://docs.parse.ly/the-parsely-api/">access our API</a>. It can be found at <code>dash.parsely.com/<var>yoursitedomain</var>/settings/api</code> (replace <var>yoursitedomain</var> with your domain name, e.g. <samp>mydomain.com</samp>).<br />If you haven\'t purchased access to the API and would like to do so, email your account manager or <a href="mailto:[email protected]">[email protected]</a>.', 'wp-parsely' ),
312 - 'label_for' => $field_id,
313 - 'optional_args' => array(
314 - 'type' => 'password',
315 - 'is_obfuscated_value' => true,
316 - ),
317 - );
318 - add_settings_field(
319 - $field_id,
320 - __( 'API Secret', 'wp-parsely' ),
321 - array( $this, 'print_text_tag' ),
322 - Parsely::MENU_SLUG,
323 - $section_key,
324 - $field_args
325 - );
326 - }
238 + // API Secret.
239 + $field_id = 'api_secret';
240 + $field_args = array(
241 + 'option_key' => $field_id,
242 + 'help_text' => __( 'Your API secret is your secret code to <a href="https://www.parse.ly/help/api/analytics/">access our API</a>. It can be found at <code>dash.parsely.com/<var>yoursitedomain</var>/settings/api</code> (replace <var>yoursitedomain</var> with your domain name, e.g. <samp>mydomain.com</samp>).<br />If you haven\'t purchased access to the API and would like to do so, email your account manager or <a href="mailto:[email protected]">[email protected]</a>.', 'wp-parsely' ),
243 + 'label_for' => $field_id,
244 + 'optional_args' => array(
245 + 'type' => 'password',
246 + 'is_obfuscated_value' => true,
247 + ),
248 + );
249 + add_settings_field(
250 + $field_id,
251 + __( 'Parse.ly API Secret', 'wp-parsely' ),
252 + array( $this, 'print_text_tag' ),
253 + Parsely::MENU_SLUG,
254 + $section_key,
255 + $field_args
256 + );
327 257
258 + // Metadata Secret.
259 + $field_id = 'metadata_secret';
260 + $field_args = array(
261 + 'option_key' => $field_id,
262 + 'help_text' => __( 'Your metadata secret is given to you by Parse.ly support. DO NOT enter anything here unless given to you by Parse.ly support!', 'wp-parsely' ),
263 + 'label_for' => $field_id,
264 + 'optional_args' => array(
265 + 'type' => 'password',
266 + 'is_obfuscated_value' => true,
267 + ),
268 + );
269 + add_settings_field(
270 + $field_id,
271 + __( 'Parse.ly Metadata Secret', 'wp-parsely' ),
272 + array( $this, 'print_text_tag' ),
273 + Parsely::MENU_SLUG,
274 + $section_key,
275 + $field_args
276 + );
277 +
328 278 // Metadata Format.
329 279 $field_id = 'meta_type';
330 280 $field_args = array(
331 281 'title' => __( 'Metadata Format', 'wp-parsely' ),
332 282 'option_key' => $field_id,
333 - 'help_text' => __( 'Choose the metadata format for our crawlers to access. Most publishers are fine with <a href="https://docs.parse.ly/metadata-jsonld/">JSON-LD</a>, but if you prefer to use our proprietary metadata format then you can do so here.', 'wp-parsely' ),
283 + 'help_text' => __( 'Choose the metadata format for our crawlers to access. Most publishers are fine with <a href="https://www.parse.ly/help/integration/jsonld/">JSON-LD</a>, but if you prefer to use our proprietary metadata format then you can do so here.', 'wp-parsely' ),
334 284 'radio_options' => array(
335 285 'json_ld' => 'json_ld',
336 286 'repeated_metas' => 'repeated_metas',
337 287 ),
@@ -339,9 +289,9 @@
339 289 'filter' => 'wp_parsely_metadata',
340 290 );
341 291 add_settings_field(
342 292 $field_id,
343 - $this->set_field_label_contents( __( 'Metadata Format', 'wp-parsely' ), $field_id ),
293 + __( 'Metadata Format', 'wp-parsely' ),
344 294 array( $this, 'print_radio_tags' ),
345 295 Parsely::MENU_SLUG,
346 296 $section_key,
347 297 $field_args
@@ -351,9 +301,9 @@
351 301 $field_help = __( 'Here you can specify your logo\'s URL by using the "Browse" button or typing the URL manually.', 'wp-parsely' );
352 302 $field_id = 'logo';
353 303 add_settings_field(
354 304 $field_id,
355 - $this->set_field_label_contents( __( 'Logo', 'wp-parsely' ), $field_id ),
305 + __( 'Logo', 'wp-parsely' ),
356 306 array( $this, 'print_media_single_image' ),
357 307 Parsely::MENU_SLUG,
358 308 $section_key,
359 309 array(
@@ -364,18 +314,17 @@
364 314 )
365 315 );
366 316
367 317 // Track logged-in users.
368 - $field_id = 'track_authenticated_users';
369 318 add_settings_field(
370 - $field_id,
371 - $this->set_field_label_contents( __( 'Track Logged-in Users', 'wp-parsely' ), $field_id ),
319 + 'track_authenticated_users',
320 + __( 'Track Logged-in Users', 'wp-parsely' ),
372 321 array( $this, 'print_radio_tags' ),
373 322 Parsely::MENU_SLUG,
374 323 $section_key,
375 324 array(
376 325 'title' => __( 'Track Logged-in Users', 'wp-parsely' ), // Passed for legend element.
377 - 'option_key' => $field_id,
326 + 'option_key' => 'track_authenticated_users',
378 327 'radio_options' => array(
379 328 'true' => __( 'Yes, track logged-in users.', 'wp-parsely' ),
380 329 'false' => __( 'No, do not track logged-in users. I do not want to see the Parse.ly tracking code on my site when browsing while logged in.', 'wp-parsely' ),
381 330 ),
@@ -387,23 +336,22 @@
387 336 )
388 337 );
389 338
390 339 // Disable JavaScript.
391 - $field_id = 'disable_javascript';
392 340 add_settings_field(
393 - $field_id,
394 - $this->set_field_label_contents( __( 'Disable JavaScript', 'wp-parsely' ), $field_id ),
341 + 'disable_javascript',
342 + __( 'Disable JavaScript', 'wp-parsely' ),
395 343 array( $this, 'print_radio_tags' ),
396 344 Parsely::MENU_SLUG,
397 345 $section_key,
398 346 array(
399 347 'title' => __( 'Disable JavaScript', 'wp-parsely' ), // Passed for legend element.
400 - 'option_key' => $field_id,
348 + 'option_key' => 'disable_javascript',
401 349 'radio_options' => array(
402 350 'true' => __( 'Yes, disable JavaScript tracking. I want to use a separate system for tracking instead of the Parse.ly plugin.', 'wp-parsely' ),
403 351 'false' => __( 'No, do not disable JavaScript tracking. I want the Parse.ly plugin to load the tracker.', 'wp-parsely' ),
404 352 ),
405 - 'help_text' => __( '<span style="color:#d63638">WARNING:</span> Changing this setting to "Yes" will prevent the plugin from injecting the Parse.ly tracker. Only do so if you are setting the tracker elsewhere (e.g. hardcoded, GTM, another tag manager, etc.).', 'wp-parsely' ),
353 + 'help_text' => __( '<span style="color:#d63638">WARNING:</span> We highly recommend choosing "No." Disabling the JavaScript tracker will also disable the "Personalize Results" section of the recommendation widget.', 'wp-parsely' ),
406 354 'filter' => 'wp_parsely_load_js_tracker',
407 355 )
408 356 );
409 357
@@ -408,18 +356,17 @@
408 356 );
409 357
410 358 if ( defined( 'AMP__VERSION' ) ) {
411 359 // Disable AMP tracking.
412 - $field_id = 'disable_amp';
413 360 add_settings_field(
414 - $field_id,
415 - $this->set_field_label_contents( __( 'Disable AMP Tracking', 'wp-parsely' ), $field_id ),
361 + 'disable_amp',
362 + __( 'Disable AMP Tracking', 'wp-parsely' ),
416 363 array( $this, 'print_radio_tags' ),
417 364 Parsely::MENU_SLUG,
418 365 $section_key,
419 366 array(
420 367 'title' => __( 'Disable AMP Tracking', 'wp-parsely' ), // Passed for legend element.
421 - 'option_key' => $field_id,
368 + 'option_key' => 'disable_amp',
422 369 'radio_options' => array(
423 370 'true' => __( 'Yes, disable Parse.ly tracking on AMP pages. I use a different system for JavaScript tracking on AMP pages.', 'wp-parsely' ),
424 371 'false' => __( 'No, do not disable Parse.ly tracking on AMP pages.', 'wp-parsely' ),
425 372 ),
@@ -428,91 +375,8 @@
428 375 }
429 376 }
430 377
431 378 /**
432 - * Registers the Content Helper section and its settings.
433 - *
434 - * @since 3.16.0
435 - */
436 - private function initialize_content_helper_section(): void {
437 - $section_key = 'content-helper-section';
438 -
439 - add_settings_section(
440 - $section_key,
441 - __( 'Content Helper', 'wp-parsely' ),
442 - '__return_null',
443 - Parsely::MENU_SLUG
444 - );
445 -
446 - // AI Features.
447 - $field_id = 'content_helper[ai_features_enabled]';
448 - $field_args = array(
449 - 'option_key' => $field_id,
450 - 'label_for' => $field_id,
451 - 'yes_text' => __( 'Enabled', 'wp-parsely' ),
452 - 'add_fieldset' => true,
453 - 'legend' => __( 'AI Features', 'wp-parsely' ),
454 - );
455 - add_settings_field(
456 - $field_id,
457 - __( 'AI Features', 'wp-parsely' ),
458 - array( $this, 'print_checkbox_tag' ),
459 - Parsely::MENU_SLUG,
460 - $section_key,
461 - $field_args
462 - );
463 -
464 - // Smart Linking.
465 - $field_id = 'content_helper[smart_linking]';
466 - $field_args = array(
467 - 'option_key' => $field_id,
468 - 'label_for' => $field_id,
469 - 'legend' => __( 'Smart Linking', 'wp-parsely' ),
470 - );
471 - add_settings_field(
472 - $field_id,
473 - __( 'Smart Linking', 'wp-parsely' ),
474 - array( $this, 'print_content_helper_ai_feature_section' ),
475 - Parsely::MENU_SLUG,
476 - $section_key,
477 - $field_args
478 - );
479 -
480 - // Title Suggestions.
481 - $field_id = 'content_helper[title_suggestions]';
482 - $field_args = array(
483 - 'option_key' => $field_id,
484 - 'label_for' => $field_id,
485 - 'legend' => __( 'Title Suggestions', 'wp-parsely' ),
486 - );
487 - add_settings_field(
488 - $field_id,
489 - __( 'Title Suggestions', 'wp-parsely' ),
490 - array( $this, 'print_content_helper_ai_feature_section' ),
491 - Parsely::MENU_SLUG,
492 - $section_key,
493 - $field_args
494 - );
495 -
496 - // Excerpt Suggestions.
497 - $field_id = 'content_helper[excerpt_suggestions]';
498 - $field_args = array(
499 - 'option_key' => $field_id,
500 - 'label_for' => $field_id,
501 - 'legend' => __( 'Excerpt Suggestions', 'wp-parsely' ),
502 - 'filter' => Excerpt_Generator::get_feature_filter_name(),
503 - );
504 - add_settings_field(
505 - $field_id,
506 - __( 'Excerpt Suggestions', 'wp-parsely' ),
507 - array( $this, 'print_content_helper_ai_feature_section' ),
508 - Parsely::MENU_SLUG,
509 - $section_key,
510 - $field_args
511 - );
512 - }
513 -
514 - /**
515 379 * Registers section and settings for Recrawl section.
516 380 *
517 381 * @since 3.2.0
518 382 */
@@ -549,27 +413,8 @@
549 413 'filter' => 'wp_parsely_trackable_statuses',
550 414 )
551 415 );
552 416
553 - // Use full metadata in non-posts.
554 - $field_id = 'full_metadata_in_non_posts';
555 - add_settings_field(
556 - $field_id,
557 - $this->set_field_label_contents( __( 'Use Full Metadata in Non-Posts', 'wp-parsely' ), $field_id ),
558 - array( $this, 'print_radio_tags' ),
559 - Parsely::MENU_SLUG,
560 - $section_key,
561 - array(
562 - 'title' => __( 'Use Full Metadata in Non-Posts', 'wp-parsely' ), // Passed for legend element.
563 - 'option_key' => $field_id,
564 - 'radio_options' => array(
565 - 'true' => __( 'Yes, add full metadata to Post Types being tracked as Non-Posts.', 'wp-parsely' ),
566 - 'false' => __( 'No, we have code that modifies metadata and that has not been tested for compatibility yet.', 'wp-parsely' ),
567 - ),
568 - 'help_text' => __( '<strong><span style="color:#d63638">Important: This setting will be removed in the future, force-enabling this behavior.</span></strong> If you\'re using any code that modifies metadata in a way that conflicts with this setting when it is enabled, please apply any needed fixes.', 'wp-parsely' ),
569 - )
570 - );
571 -
572 417 // Content ID Prefix.
573 418 $field_id = 'content_id_prefix';
574 419 $field_args = array(
575 420 'option_key' => $field_id,
@@ -580,9 +425,9 @@
580 425 'label_for' => $field_id,
581 426 );
582 427 add_settings_field(
583 428 $field_id,
584 - $this->set_field_label_contents( __( 'Content ID Prefix', 'wp-parsely' ), $field_id ),
429 + __( 'Content ID Prefix', 'wp-parsely' ),
585 430 array( $this, 'print_text_tag' ),
586 431 Parsely::MENU_SLUG,
587 432 $section_key,
588 433 $field_args
@@ -588,18 +433,17 @@
588 433 $field_args
589 434 );
590 435
591 436 // Use top-level categories.
592 - $field_id = 'use_top_level_cats';
593 437 add_settings_field(
594 - $field_id,
595 - $this->set_field_label_contents( __( 'Use Top-Level Categories for Section', 'wp-parsely' ), $field_id ),
438 + 'use_top_level_cats',
439 + __( 'Use Top-Level Categories for Section', 'wp-parsely' ),
596 440 array( $this, 'print_radio_tags' ),
597 441 Parsely::MENU_SLUG,
598 442 $section_key,
599 443 array(
600 444 'title' => __( 'Use Top-Level Categories for Section', 'wp-parsely' ), // Passed for legend element.
601 - 'option_key' => $field_id,
445 + 'option_key' => 'use_top_level_cats',
602 446 'radio_options' => array(
603 447 'true' => __( 'Yes, use the first category assigned to a post as the section name.', 'wp-parsely' ),
604 448 'false' => __( 'No, do not use the first category assigned to a post as the section name.', 'wp-parsely' ),
605 449 ),
@@ -611,14 +455,24 @@
611 455 $field_id = 'custom_taxonomy_section';
612 456 $field_args = array(
613 457 'option_key' => $field_id,
614 458 'help_text' => __( 'By default, the section value in your Parse.ly dashboard maps to a post\'s category. You can optionally choose a custom taxonomy, if you\'ve created one, to populate the section value instead.', 'wp-parsely' ),
615 - 'select_options' => self::get_section_taxonomies(),
459 + // filter WordPress taxonomies under the hood that should not appear in dropdown.
460 + 'select_options' => array_diff(
461 + get_taxonomies(),
462 + array(
463 + 'post_tag',
464 + 'nav_menu',
465 + 'author',
466 + 'link_category',
467 + 'post_format',
468 + )
469 + ),
616 470 'label_for' => Parsely::OPTIONS_KEY . "[$field_id]",
617 471 );
618 472 add_settings_field(
619 473 $field_id,
620 - $this->set_field_label_contents( __( 'Use Custom Taxonomy for Section', 'wp-parsely' ), $field_id ),
474 + __( 'Use Custom Taxonomy for Section', 'wp-parsely' ),
621 475 array( $this, 'print_select_tag' ),
622 476 Parsely::MENU_SLUG,
623 477 $section_key,
624 478 $field_args
@@ -624,18 +478,17 @@
624 478 $field_args
625 479 );
626 480
627 481 // Use categories and custom taxonomies as tags.
628 - $field_id = 'cats_as_tags';
629 482 add_settings_field(
630 - $field_id,
631 - $this->set_field_label_contents( __( 'Add Categories to Tags', 'wp-parsely' ), $field_id ),
483 + 'cats_as_tags',
484 + __( 'Add Categories to Tags', 'wp-parsely' ),
632 485 array( $this, 'print_radio_tags' ),
633 486 Parsely::MENU_SLUG,
634 487 $section_key,
635 488 array(
636 489 'title' => __( 'Add Categories to Tags', 'wp-parsely' ), // Passed for legend element.
637 - 'option_key' => $field_id,
490 + 'option_key' => 'cats_as_tags',
638 491 'radio_options' => array(
639 492 'true' => __( 'Yes, add all assigned categories and taxonomies to my tags.', 'wp-parsely' ),
640 493 'false' => __( 'No, do not add all assigned categories and taxonomies to my tags.', 'wp-parsely' ),
641 494 ),
@@ -643,18 +496,17 @@
643 496 )
644 497 );
645 498
646 499 // Lowercase all tags.
647 - $field_id = 'lowercase_tags';
648 500 add_settings_field(
649 - $field_id,
650 - $this->set_field_label_contents( __( 'Lowercase All Tags', 'wp-parsely' ), $field_id ),
501 + 'lowercase_tags',
502 + __( 'Lowercase All Tags', 'wp-parsely' ),
651 503 array( $this, 'print_radio_tags' ),
652 504 Parsely::MENU_SLUG,
653 505 $section_key,
654 506 array(
655 507 'title' => __( 'Lowercase All Tags', 'wp-parsely' ), // Passed for legend element.
656 - 'option_key' => $field_id,
508 + 'option_key' => 'lowercase_tags',
657 509 'radio_options' => array(
658 510 'true' => __( 'Yes, use lowercase versions of my tags to correct for potential misspellings.', 'wp-parsely' ),
659 511 'false' => __( 'No, do not use lowercase versions of my tags to correct for potential misspellings.', 'wp-parsely' ),
660 512 ),
@@ -660,18 +512,17 @@
660 512 ),
661 513 )
662 514 );
663 515
664 - $field_id = 'force_https_canonicals';
665 516 add_settings_field(
666 - $field_id,
667 - $this->set_field_label_contents( __( 'Force HTTPS Canonicals', 'wp-parsely' ), $field_id ),
517 + 'force_https_canonicals',
518 + __( 'Force HTTPS Canonicals', 'wp-parsely' ),
668 519 array( $this, 'print_radio_tags' ),
669 520 Parsely::MENU_SLUG,
670 521 $section_key,
671 522 array(
672 523 'title' => __( 'Force HTTPS Canonicals', 'wp-parsely' ), // Passed for legend element.
673 - 'option_key' => $field_id,
524 + 'option_key' => 'force_https_canonicals',
674 525 'radio_options' => array(
675 526 'true' => __( 'Yes, force <code>https</code> canonical URLs by default.', 'wp-parsely' ),
676 527 'false' => __( 'No, I want to use <code>http</code>.', 'wp-parsely' ),
677 528 ),
@@ -685,10 +536,9 @@
685 536 *
686 537 * @since 3.2.0
687 538 */
688 539 private function initialize_advanced_section(): void {
689 - $are_credentials_managed = $this->parsely->are_credentials_managed;
690 - $section_key = 'advanced-section';
540 + $section_key = 'advanced-section';
691 541
692 542 add_settings_section(
693 543 $section_key,
694 544 __( 'Advanced', 'wp-parsely' ),
@@ -695,41 +545,18 @@
695 545 '__return_null',
696 546 Parsely::MENU_SLUG
697 547 );
698 548
699 - if ( ! $are_credentials_managed ) {
700 - // Metadata Secret.
701 - $field_id = 'metadata_secret';
702 - $field_args = array(
703 - 'option_key' => $field_id,
704 - 'help_text' => __( 'Your metadata secret is given to you by Parse.ly support. DO NOT enter anything here unless given to you by Parse.ly support!', 'wp-parsely' ),
705 - 'label_for' => $field_id,
706 - 'optional_args' => array(
707 - 'type' => 'password',
708 - 'is_obfuscated_value' => true,
709 - ),
710 - );
711 - add_settings_field(
712 - $field_id,
713 - __( 'Metadata Secret', 'wp-parsely' ),
714 - array( $this, 'print_text_tag' ),
715 - Parsely::MENU_SLUG,
716 - $section_key,
717 - $field_args
718 - );
719 - }
720 -
721 549 // Disable autotrack.
722 - $field_id = 'disable_autotrack';
723 550 add_settings_field(
724 - $field_id,
725 - $this->set_field_label_contents( __( 'Disable Autotracking', 'wp-parsely' ), $field_id ),
551 + 'disable_autotrack',
552 + __( 'Disable Autotracking', 'wp-parsely' ),
726 553 array( $this, 'print_radio_tags' ),
727 554 Parsely::MENU_SLUG,
728 555 $section_key,
729 556 array(
730 557 'title' => __( 'Disable Autotracking', 'wp-parsely' ), // Passed for legend element.
731 - 'option_key' => $field_id,
558 + 'option_key' => 'disable_autotrack',
732 559 'radio_options' => array(
733 560 'true' => __( 'Yes, disable autotracking. I do not want the tracking code to report an event as soon as the script has finished loading. I plan to implement Dynamic Tracking myself.', 'wp-parsely' ),
734 561 'false' => __( 'No, do not disable autotracking. I want to make sure the default behavior of the tracking code is in place. The tracking code should report an event as soon as the script has finished loading.', 'wp-parsely' ),
735 562 ),
@@ -734,8 +561,22 @@
734 561 'false' => __( 'No, do not disable autotracking. I want to make sure the default behavior of the tracking code is in place. The tracking code should report an event as soon as the script has finished loading.', 'wp-parsely' ),
735 562 ),
736 563 )
737 564 );
565 +
566 + // Clear metadata.
567 + add_settings_field(
568 + 'parsely_wipe_metadata_cache',
569 + __( 'Wipe Parse.ly Metadata Info', 'wp-parsely' ),
570 + array( $this, 'print_checkbox_tag' ),
571 + Parsely::MENU_SLUG,
572 + $section_key,
573 + array(
574 + 'option_key' => 'parsely_wipe_metadata_cache',
575 + 'yes_text' => __( 'Yes, clear all metadata information for Parse.ly posts and re-send all metadata to Parse.ly.', 'wp-parsely' ),
576 + 'help_text' => __( '<span style="color:#d63638">WARNING:</span> Do not do this unless explicitly instructed by Parse.ly Staff!', 'wp-parsely' ),
577 + )
578 + );
738 579 }
739 580
740 581 /**
741 582 * Shows setting tabs.
@@ -832,14 +673,12 @@
832 673 $id = esc_attr( $name );
833 674 $name = Parsely::OPTIONS_KEY . "[$id]";
834 675 $is_obfuscated_value = $optional_args['is_obfuscated_value'] ?? false;
835 676 $value = $is_obfuscated_value ? $this->get_obfuscated_value( $value ) : esc_attr( $value );
836 - $accepted_args = array( 'placeholder', 'required', 'disabled' );
677 + $accepted_args = array( 'placeholder', 'required' );
837 678 $type = $optional_args['type'] ?? 'text';
838 679
839 - $is_managed = key_exists( $id, $this->parsely->managed_options );
840 - echo '<fieldset', $is_managed ? ' disabled>' : '>';
841 - printf( "<input type='%s' name='%s' id='%s' value='%s'", esc_attr( $type ), esc_attr( $name ), esc_attr( $id ), esc_attr( $value ) );
680 + echo sprintf( "<input type='%s' name='%s' id='%s' value='%s'", esc_attr( $type ), esc_attr( $name ), esc_attr( $id ), esc_attr( $value ) );
842 681
843 682 if ( isset( $args['help_text'] ) ) {
844 683 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
845 684 }
@@ -844,148 +683,41 @@
844 683 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
845 684 }
846 685
847 686 foreach ( $optional_args as $key => $val ) {
848 - if ( \in_array( $key, $accepted_args, true ) && false !== $val ) {
849 - // Don't add a placeholder to managed option fields.
850 - if ( $is_managed && 'placeholder' === $key ) {
851 - continue;
852 - }
853 -
854 - // Support attributes without values.
855 - echo ' ' . esc_attr( $key );
856 - if ( true !== $val ) {
857 - echo '="' . esc_attr( $val ) . '"';
858 - }
687 + if ( \in_array( $key, $accepted_args, true ) ) {
688 + echo ' ' . esc_attr( $key ) . '="' . esc_attr( (string) $val ) . '"';
859 689 }
860 690 }
861 - echo ' /></fieldset>';
691 + echo ' />';
862 692
863 693 $this->print_description_text( $args );
864 694 }
865 695
866 696 /**
867 - * Prints a checkbox tag.
697 + * Prints a checkbox tag in the settings page.
868 698 *
869 - * @since 3.16.0
870 - *
871 - * @param Setting_Arguments $args Arguments for the checkbox tag.
872 - * @param Parsely_Options|null $options The options to use.
699 + * @param Setting_Arguments $args Arguments to print to checkbox tag.
873 700 */
874 - public function print_checkbox_tag( $args, $options = null ): void {
875 - $options = $options ?? $this->parsely->get_options();
876 - $name = $args['option_key'];
877 - $has_fieldset = isset( $args['add_fieldset'] ) && true === $args['add_fieldset'];
878 - $html_id = rtrim( str_replace( array( '[', ']', '__' ), '_', $name ), '_' );
879 - $html_name = str_replace(
880 - 'content_helper',
881 - '[content_helper]',
882 - Parsely::OPTIONS_KEY . esc_attr( $name )
883 - );
884 - $yes_text = $args['yes_text'] ?? '';
701 + public function print_checkbox_tag( $args ): void {
702 + $options = $this->parsely->get_options();
703 + $name = $args['option_key'];
704 + $value = $options[ $name ];
705 + $id = esc_attr( $name );
706 + $name = Parsely::OPTIONS_KEY . "[$id]";
707 + $yes_text = $args['yes_text'] ?? '';
885 708
886 - // Get option value.
887 - if ( false === strpos( $name, '[' ) ) {
888 - $value = $options[ $name ];
889 - } else {
890 - $value = Parsely::get_nested_option_value( $name, $options );
891 - }
892 -
893 - // Fieldset start.
894 - if ( $has_fieldset ) {
895 - echo '<fieldset>';
896 - if ( isset( $args['legend'] ) ) {
897 - echo '<legend class="screen-reader-text"><span>';
898 - echo esc_html( $args['legend'] ) . '</span></legend>';
899 - }
900 - }
901 -
902 - // Label and contained checkbox.
903 - printf( '<label for="%s">', esc_attr( $html_id ) );
904 - printf(
905 - '<input type="checkbox" name="%s" id="%s" value="true" ',
906 - esc_attr( $html_name ),
907 - esc_attr( $html_id )
908 - );
709 + echo sprintf( "<input type='checkbox' name='%s' id='%s_true' value='true' ", esc_attr( $name ), esc_attr( $id ) );
909 710 if ( isset( $args['help_text'] ) ) {
910 - echo ' aria-describedby="' . esc_attr( $html_id ) . '-description"';
711 + echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
911 712 }
912 - checked( true === $value, true );
913 - printf( ' /> %s</label>', esc_html( $yes_text ) );
713 + echo checked( true === $value, true, false );
714 + echo sprintf( " /> <label for='%s_true'>%s</label>", esc_attr( $id ), esc_html( $yes_text ) );
914 715
915 - // Fieldset end.
916 - if ( $has_fieldset ) {
917 - echo '</fieldset>';
918 - }
919 -
920 716 $this->print_description_text( $args );
921 717 }
922 718
923 719 /**
924 - * Prints a Content Helper AI feature section.
925 - *
926 - * @since 3.16.0
927 - *
928 - * @param Setting_Arguments $args The arguments for the section.
929 - */
930 - public function print_content_helper_ai_feature_section( $args ): void {
931 - $options = $this->parsely->get_options();
932 - $feature_id = str_replace(
933 - array( 'content_helper[', ']' ),
934 - '',
935 - $args['option_key']
936 - );
937 -
938 - // Convert user role settings to make them work in the settings page.
939 - $option = &$options['content_helper'][ $feature_id ];
940 - if ( isset( $option['allowed_user_roles'] ) ) {
941 - foreach ( $option['allowed_user_roles'] as $role ) {
942 - $option['allowed_user_roles'][ $role ] = true;
943 - }
944 - }
945 -
946 - // Feature "Enabled" checkbox.
947 - $enabled_args = array(
948 - 'option_key' => $args['option_key'] . '[enabled]',
949 - 'label_for' => $args['option_key'] . '[enabled]',
950 - 'yes_text' => __( 'Enabled', 'wp-parsely' ),
951 - 'add_fieldset' => true,
952 - );
953 - if ( isset( $args['legend'] ) ) {
954 - $enabled_args['legend'] = $args['legend'];
955 - }
956 - $this->print_checkbox_tag( $enabled_args, $options );
957 -
958 - // User role permissions fieldset.
959 - echo '<p>' . esc_html__( 'User Permissions', 'wp-parsely' ) . '</p>';
960 - echo '<fieldset class="user-role-permissions">';
961 - echo '<legend class="screen-reader-text"><span>';
962 - printf(
963 - /* translators: %s: Feature name */
964 - esc_html__( '%s User Permissions', 'wp-parsely' ),
965 - esc_html( $args['legend'] ?? __( 'Feature', 'wp-parsely' ) )
966 - );
967 - echo '</span></legend>';
968 -
969 - // User role checkboxes.
970 - $user_roles = Permissions::get_user_roles_with_edit_posts_cap();
971 - foreach ( $user_roles as $key => $name ) {
972 - $option_key = $args['option_key'] . '[allowed_user_roles][' . $key . ']';
973 - $role_args = array(
974 - 'option_key' => $option_key,
975 - 'label_for' => $option_key,
976 - 'yes_text' => translate_user_role( $name ),
977 - );
978 -
979 - $this->print_checkbox_tag( $role_args, $options );
980 - }
981 -
982 - echo '</fieldset>';
983 -
984 - $this->print_filter_text( $args );
985 - }
986 -
987 - /**
988 720 * Prints out the select tags
989 721 *
990 722 * @param Setting_Arguments $args The arguments for the select dropdowns.
991 723 */
@@ -996,11 +728,9 @@
996 728 $selected = $options[ $name ] ?? null;
997 729 $id = esc_attr( $name );
998 730 $name = Parsely::OPTIONS_KEY . "[$id]";
999 731
1000 - $is_managed = key_exists( $id, $this->parsely->managed_options );
1001 - echo '<fieldset', $is_managed ? ' disabled>' : '>';
1002 - printf( "<select name='%s' id='%s'", esc_attr( $name ), esc_attr( $name ) );
732 + echo sprintf( "<select name='%s' id='%s'", esc_attr( $name ), esc_attr( $name ) );
1003 733 if ( isset( $args['help_text'] ) ) {
1004 734 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
1005 735 }
1006 736 echo '>';
@@ -1010,9 +740,9 @@
1010 740 echo selected( $selected, $key, false ) . '>';
1011 741 echo esc_html( $val );
1012 742 echo '</option>';
1013 743 }
1014 - echo '</select></fieldset>';
744 + echo '</select>';
1015 745
1016 746 $this->print_filter_text( $args );
1017 747 $this->print_description_text( $args );
1018 748 }
@@ -1033,11 +763,10 @@
1033 763 // Converting boolean to string so that we have string type keys for all cases.
1034 764 $selected = $selected ? 'true' : 'false';
1035 765 }
1036 766
1037 - $is_managed = key_exists( $name, $this->parsely->managed_options );
1038 767 ?>
1039 - <fieldset <?php echo $is_managed ? 'disabled' : ''; ?>>
768 + <fieldset>
1040 769 <legend class="screen-reader-text"><span><?php echo esc_html( $title ); ?></span></legend>
1041 770 <p>
1042 771 <?php foreach ( $radio_options as $value => $text ) { ?>
1043 772 <label for="<?php echo esc_attr( "{$id}_{$value}" ); ?>">
@@ -1075,13 +804,11 @@
1075 804 */
1076 805 $input_value = $this->parsely->get_options()[ $key ];
1077 806 $input_name = Parsely::OPTIONS_KEY . "[$key]";
1078 807 $button_text = __( 'Browse', 'wp-parsely' );
1079 -
1080 - $is_managed = key_exists( $key, $this->parsely->managed_options );
1081 808 ?>
1082 809
1083 - <fieldset class="media-single-image" id="media-single-image-<?php echo esc_attr( $key ); ?>"<?php echo $is_managed ? ' disabled' : ''; ?>>
810 + <fieldset class="media-single-image" id="media-single-image-<?php echo esc_attr( $key ); ?>">
1084 811 <legend class="screen-reader-text"><span><?php echo esc_html( $title ); ?></span></legend>
1085 812 <input class="file-path" type="text" name="<?php echo esc_attr( $input_name ); ?>" id="logo" value="<?php echo esc_attr( $input_value ); ?>" />
1086 813 <button data-option="<?php echo esc_attr( $key ); ?>" class="browse button" type="button"><?php echo esc_html( $button_text ); ?></button>
1087 814 </fieldset>
@@ -1183,13 +910,13 @@
1183 910 /**
1184 911 * Validates the options provided by the user.
1185 912 *
1186 913 * @param ParselySettingOptions $input Options from the settings page.
914 + *
1187 915 * @return ParselySettingOptions
1188 916 */
1189 917 public function validate_options( $input ) {
1190 918 $input = $this->validate_basic_section( $input );
1191 - $input = $this->validate_content_helper_section( $input );
1192 919 $input = $this->validate_recrawl_section( $input );
1193 920 $input = $this->validate_advanced_section( $input );
1194 921
1195 922 return $input;
@@ -1198,43 +925,50 @@
1198 925 /**
1199 926 * Validates fields of Basic Section.
1200 927 *
1201 928 * @param ParselySettingOptions $input Options from the settings page.
929 + *
1202 930 * @return ParselySettingOptions Validated inputs.
1203 931 */
1204 932 private function validate_basic_section( $input ) {
1205 - $are_credentials_managed = $this->parsely->are_credentials_managed;
1206 - $options = $this->parsely->get_options();
933 + $options = $this->parsely->get_options();
1207 934
1208 - if ( $are_credentials_managed ) {
1209 - $input['apikey'] = '';
1210 - $input['api_secret'] = '';
935 + if ( '' === $input['apikey'] ) {
936 + add_settings_error(
937 + Parsely::OPTIONS_KEY,
938 + 'apikey',
939 + __( 'Please specify the Site ID', 'wp-parsely' )
940 + );
1211 941 } else {
1212 - $site_id = $this->sanitize_site_id( $input['apikey'] );
1213 - $api_secret = $this->get_unobfuscated_value( $input['api_secret'], $this->parsely->get_api_secret() );
942 + $site_id = $this->sanitize_site_id( $input['apikey'] );
943 + if ( false === $this->validate_site_id( $site_id ) ) {
944 + add_settings_error(
945 + Parsely::OPTIONS_KEY,
946 + 'apikey',
947 + __( 'Your Parse.ly Site ID looks incorrect, it should look like "example.com".', 'wp-parsely' )
948 + );
949 + } else {
950 + $input['apikey'] = $site_id;
951 + }
952 + }
1214 953
1215 - $valid_credentials = Validator::validate_api_credentials( $this->parsely, $site_id, $api_secret );
954 + $input['api_secret'] = $this->get_unobfuscated_value( $input['api_secret'], $this->parsely->get_api_secret() );
1216 955
1217 - // When running e2e tests, we need to update the API keys without validating them, as they will be invalid.
1218 - // phpcs:ignore WordPress.Security.NonceVerification.Missing
1219 - if ( isset( $_POST['e2e_parsely_skip_api_validate'] ) && 'y' === $_POST['e2e_parsely_skip_api_validate'] ) {
1220 - $valid_credentials = true;
1221 - }
1222 -
1223 - if ( is_wp_error( $valid_credentials ) && Validator::INVALID_API_CREDENTIALS === $valid_credentials->get_error_code() ) {
956 + $input['metadata_secret'] = $this->get_unobfuscated_value( $input['metadata_secret'], $this->parsely->get_options()['metadata_secret'] );
957 + if ( '' !== $input['metadata_secret'] ) {
958 + if ( strlen( $input['metadata_secret'] ) !== 10 ) {
1224 959 add_settings_error(
1225 960 Parsely::OPTIONS_KEY,
1226 - 'api_secret',
1227 - __( 'The Site ID and API Secret weren\'t saved as they failed to authenticate with the Parse.ly API. Try again with different credentials or contact Parse.ly support', 'wp-parsely' )
961 + 'metadata_secret',
962 + __( 'Metadata secret is incorrect. Please contact Parse.ly support!', 'wp-parsely' )
1228 963 );
1229 - $input['apikey'] = $options['apikey'];
1230 - $input['api_secret'] = $options['api_secret'];
1231 - }
964 + } elseif (
965 + isset( $input['parsely_wipe_metadata_cache'] ) && 'true' === $input['parsely_wipe_metadata_cache'] // @phpstan-ignore-line
966 + ) {
967 + delete_post_meta_by_key( 'parsely_metadata_last_updated' );
1232 968
1233 - // Since the API secret is obfuscated, we need to make sure that the value
1234 - // is not changed when the credentials are valid.
1235 - if ( true === $valid_credentials && $input['api_secret'] !== $api_secret ) {
1236 - $input['api_secret'] = $api_secret;
969 + wp_schedule_event( time() + 100, 'everytenminutes', 'parsely_bulk_metas_update' );
970 + $input['parsely_wipe_metadata_cache'] = false;
1237 971 }
1238 972 }
1239 973
1240 974 if ( ! isset( $input['meta_type'] ) ) {
@@ -1290,92 +1024,12 @@
1290 1024 return $input;
1291 1025 }
1292 1026
1293 1027 /**
1294 - * Validates the fields of the Content Helper section.
1295 - *
1296 - * @since 3.16.0
1297 - *
1298 - * @param ParselySettingOptions $input The settings page options.
1299 - * @return ParselySettingOptions The validated input.
1300 - */
1301 - private function validate_content_helper_section( $input ) {
1302 - /**
1303 - * Sanitizes the Content Helper data.
1304 - *
1305 - * @since 3.16.0
1306 - */
1307 - $sanitize = function ( $input ) use ( &$sanitize ) {
1308 - foreach ( $input as $key => $value ) {
1309 - if ( is_array( $value ) ) {
1310 - if ( 'allowed_user_roles' === $key && count( $input[ $key ] ) > 0 ) {
1311 - $passed_roles = array_keys( $input[ $key ] );
1312 - $valid_roles = array_keys(
1313 - Permissions::get_user_roles_with_edit_posts_cap()
1314 - );
1315 - $sanitized_roles = array();
1316 -
1317 - // Sanitize passed user roles and remove invalid ones.
1318 - foreach ( $passed_roles as $user_role ) {
1319 - if ( ! is_string( $user_role ) ) {
1320 - continue;
1321 - }
1322 -
1323 - $user_role = sanitize_text_field( $user_role );
1324 - if ( in_array( $user_role, $valid_roles, true ) ) {
1325 - $sanitized_roles[] = $user_role;
1326 - }
1327 - }
1328 -
1329 - $input[ $key ] = $sanitized_roles;
1330 - } else {
1331 - // Recurse when we have an array that's not user roles.
1332 - $input[ $key ] = $sanitize( $value );
1333 - }
1334 - } else {
1335 - // Enforce a boolean value.
1336 - $input[ $key ] = 'true' === $value || true === $value;
1337 - }
1338 - }
1339 -
1340 - return $input;
1341 - };
1342 -
1343 - // Add any missing data due to unchecked checkboxes.
1344 - if ( ! isset( $input['content_helper']['ai_features_enabled'] ) ) {
1345 - $input['content_helper']['ai_features_enabled'] = false;
1346 - }
1347 - foreach ( $this->configurable_pch_features as $feature_id ) {
1348 - if ( ! isset( $input['content_helper'][ $feature_id ] ) ) {
1349 - $input['content_helper'][ $feature_id ] = array(
1350 - 'enabled' => false,
1351 - 'allowed_user_roles' => array(),
1352 - );
1353 - } else {
1354 - if ( ! isset( $input['content_helper'][ $feature_id ]['enabled'] ) ) {
1355 - // @phpstan-ignore-next-line
1356 - $input['content_helper'][ $feature_id ]['enabled'] = false;
1357 - }
1358 - if ( ! isset( $input['content_helper'][ $feature_id ]['allowed_user_roles'] ) ) {
1359 - // @phpstan-ignore-next-line
1360 - $input['content_helper'][ $feature_id ]['allowed_user_roles'] = array();
1361 - }
1362 - }
1363 - }
1364 -
1365 - // Produce the final array.
1366 - $options = $this->parsely->get_options()['content_helper'];
1367 - $merged = array_merge( $options, $input['content_helper'] );
1368 -
1369 - $input['content_helper'] = $sanitize( $merged );
1370 -
1371 - return $input;
1372 - }
1373 -
1374 - /**
1375 1028 * Validates fields of Recrawl Section.
1376 1029 *
1377 1030 * @param ParselySettingOptions $input Options from the settings page.
1031 + *
1378 1032 * @return ParselySettingOptions Validated inputs.
1379 1033 */
1380 1034 private function validate_recrawl_section( $input ) {
1381 1035 $options = $this->parsely->get_options();
@@ -1388,16 +1042,8 @@
1388 1042 } else {
1389 1043 $input['content_id_prefix'] = sanitize_text_field( $input['content_id_prefix'] );
1390 1044 }
1391 1045
1392 - // Full metadata in non-posts.
1393 - if ( ! isset( $input['full_metadata_in_non_posts'] ) ) {
1394 - $input['full_metadata_in_non_posts'] = true;
1395 - } else {
1396 - // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
1397 - $input['full_metadata_in_non_posts'] = 'true' == $input['full_metadata_in_non_posts'];
1398 - }
1399 -
1400 1046 // Allow for Top-level categories setting to be conditionally included on the page.
1401 1047 // If it's not shown, then set the value as what was previously saved.
1402 1048 if ( ! isset( $input['use_top_level_cats'] ) ) {
1403 1049 $input['use_top_level_cats'] = 'true';
@@ -1489,30 +1135,14 @@
1489 1135 /**
1490 1136 * Validates fields of Advanced Section.
1491 1137 *
1492 1138 * @param ParselySettingOptions $input Options from the settings page.
1139 + *
1493 1140 * @return ParselySettingOptions Validated inputs.
1494 1141 */
1495 1142 private function validate_advanced_section( $input ) {
1496 - $are_credentials_managed = $this->parsely->are_credentials_managed;
1497 - $options = $this->parsely->get_options();
1143 + $options = $this->parsely->get_options();
1498 1144
1499 - if ( $are_credentials_managed ) {
1500 - $input['metadata_secret'] = '';
1501 - } else {
1502 - $input['metadata_secret'] = $this->get_unobfuscated_value( $input['metadata_secret'], $this->parsely->get_options()['metadata_secret'] );
1503 - $metadata_secret_length = strlen( $input['metadata_secret'] );
1504 - if ( $metadata_secret_length > 0 &&
1505 - false === Validator::validate_metadata_secret( $input['metadata_secret'] ) ) {
1506 - add_settings_error(
1507 - Parsely::OPTIONS_KEY,
1508 - 'metadata_secret',
1509 - __( 'The Metadata Secret was not saved because it is incorrect. Please contact Parse.ly support!', 'wp-parsely' )
1510 - );
1511 - $input['metadata_secret'] = $options['metadata_secret'];
1512 - }
1513 - }
1514 -
1515 1145 if ( ! isset( $input['disable_autotrack'] ) ) {
1516 1146 $input['disable_autotrack'] = $options['disable_autotrack'];
1517 1147 } elseif ( 'true' !== $input['disable_autotrack'] && 'false' !== $input['disable_autotrack'] ) {
1518 1148 add_settings_error(
@@ -1527,8 +1157,30 @@
1527 1157 return $input;
1528 1158 }
1529 1159
1530 1160 /**
1161 + * Validates the passed Site ID.
1162 + *
1163 + * Accepts a www prefix and up to 3 periods.
1164 + *
1165 + * Valid examples: 'test.com', 'www.test.com', 'subdomain.test.com',
1166 + * 'www.subdomain.test.com', 'subdomain.subdomain.test.com'.
1167 + *
1168 + * Invalid examples: 'test', 'test.com/', 'http://test.com', 'https://test.com',
1169 + * 'www.subdomain.subdomain.test.com'.
1170 + *
1171 + * @since 3.3.0
1172 + *
1173 + * @param string $site_id The Site ID to be validated.
1174 + * @return bool
1175 + */
1176 + private function validate_site_id( string $site_id ): bool {
1177 + $key_format = '/^((\w+)\.)?(([\w-]+)?)(\.[\w-]+){1,2}$/';
1178 +
1179 + return 1 === preg_match( $key_format, $site_id );
1180 + }
1181 +
1182 + /**
1531 1183 * Sanitizes the passed Site ID.
1532 1184 *
1533 1185 * @since 3.3.0
1534 1186 *
@@ -1612,18 +1264,17 @@
1612 1264
1613 1265 /**
1614 1266 * Sanitizes all elements in an option array.
1615 1267 *
1616 - * @param array<int, string> $options Array of options to be sanitized.
1268 + * @param array<int, string> $array Array of options to be sanitized.
1617 1269 * @return array<int, string>
1618 1270 */
1619 - private static function sanitize_option_array( array $options ): array {
1620 - $sanitized_options = $options;
1621 - foreach ( $options as $key => $val ) {
1622 - $sanitized_options[ $key ] = sanitize_text_field( $val );
1271 + private static function sanitize_option_array( array $array ): array {
1272 + $new_array = $array;
1273 + foreach ( $array as $key => $val ) {
1274 + $new_array[ $key ] = sanitize_text_field( $val );
1623 1275 }
1624 -
1625 - return $sanitized_options;
1276 + return $new_array;
1626 1277 }
1627 1278
1628 1279 /**
1629 1280 * Gets obfuscated value.
@@ -1628,8 +1279,9 @@
1628 1279 /**
1629 1280 * Gets obfuscated value.
1630 1281 *
1631 1282 * @param string $current_value Current value of the field.
1283 + *
1632 1284 * @return string
1633 1285 */
1634 1286 private function get_obfuscated_value( $current_value ): string {
1635 1287 return str_repeat( '*', strlen( $current_value ) );
@@ -1640,8 +1292,9 @@
1640 1292 *
1641 1293 * @param string $current_value Current value of the field.
1642 1294 * @param string $previous_value Previous value of the field. If current
1643 1295 * value is obfuscated then we will use this.
1296 + *
1644 1297 * @return string
1645 1298 */
1646 1299 private function get_unobfuscated_value( $current_value, $previous_value ): string {
1647 1300 if ( $current_value === $this->get_obfuscated_value( $current_value ) ) {
@@ -1648,63 +1301,6 @@
1648 1301 return '' === $current_value ? $current_value : $previous_value;
1649 1302 }
1650 1303
1651 1304 return $current_value;
1652 - }
1653 -
1654 - /**
1655 - * Returns the field label's title. If the option is managed, a badge is
1656 - * also included.
1657 - *
1658 - * @since 3.9.0
1659 - *
1660 - * @param string $title The field's title.
1661 - * @param string $option_id The option's ID.
1662 - * @return string The resulting content.
1663 - */
1664 - public function set_field_label_contents( string $title, string $option_id ): string {
1665 - $is_managed = key_exists( $option_id, $this->parsely->managed_options );
1666 -
1667 - if ( $is_managed ) {
1668 - $text = $this->managed_options_badge['text'] ?? '';
1669 - if ( ! is_string( $text ) || '' === $text ) {
1670 - return $title;
1671 - }
1672 -
1673 - $url = filter_var( $this->managed_options_badge['url'] ?? '', FILTER_VALIDATE_URL );
1674 -
1675 - if ( false === $url ) {
1676 - $badge = '<span class="managed-option-badge">' . esc_html( $text ) . '</span>';
1677 - } else {
1678 - $badge = '<a class="managed-option-badge" href="' . esc_url( $url ) .
1679 - '" target="_blank" rel="noopener">' . esc_html( $text ) . '</a>';
1680 - }
1681 -
1682 - return "{$title}&nbsp;&nbsp;{$badge}";
1683 - }
1684 -
1685 - return $title;
1686 - }
1687 -
1688 - /**
1689 - * Returns the taxonomies allowed to be used as custom_taxonomy_section
1690 - * option values.
1691 - *
1692 - * @since 3.9.0
1693 - *
1694 - * @return array<string> Array of taxonomies.
1695 - */
1696 - public static function get_section_taxonomies(): array {
1697 - return array_diff(
1698 - get_taxonomies(),
1699 - array(
1700 - 'post_tag',
1701 - 'nav_menu',
1702 - 'author',
1703 - 'link_category',
1704 - 'post_format',
1705 - 'wp_theme',
1706 - 'wp_template_part_area',
1707 - )
1708 - );
1709 1305 }
1710 1306 }