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
wp-parsely / src / UI / class-settings-page.php

class-settings-page.php in Parse.ly 3.8.4, at src/UI/class-settings-page.php

1,307 lines 42.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * UI: Settings page class
4 *
5 * @package Parsely
6 * @since 3.0.0
7 */
8
9 declare(strict_types=1);
10
11 namespace Parsely\UI;
12
13 use Parsely\Parsely;
14
15 use function Parsely\Utils\get_asset_info;
16
17 use const Parsely\PARSELY_FILE;
18
19 /**
20 * Renders the wp-admin Parse.ly plugin settings page.
21 *
22 * @since 3.0.0
23 *
24 * @phpstan-import-type Parsely_Options from Parsely
25 *
26 * @phpstan-type Setting_Arguments array{
27 * option_key: string,
28 * label_for: string,
29 * title?: string,
30 * help_text?: string,
31 * yes_text?: string,
32 * filter?: string,
33 * optional_args?: Setting_Optional_Args,
34 * select_options?: array<string, string>,
35 * radio_options?: array<string, string>,
36 * }
37 *
38 * @phpstan-type Setting_Optional_Args array{
39 * type?: string,
40 * placeholder?: string,
41 * required?: string,
42 * is_obfuscated_value: bool,
43 * }
44 *
45 * @phpstan-type ParselySettingOptions array{
46 * apikey: string,
47 * api_secret: string,
48 * metadata_secret: string,
49 * meta_type?: string,
50 * logo: string,
51 * track_authenticated_users: bool|string,
52 * disable_javascript: bool|string,
53 * disable_amp?: bool,
54 * track_post_types_as?: array<string, string>,
55 * track_post_types: string[],
56 * track_page_types: string[],
57 * content_id_prefix?: string,
58 * use_top_level_cats?:bool|string,
59 * custom_taxonomy_section?: string,
60 * cats_as_tags?: bool|string,
61 * lowercase_tags?: bool,
62 * force_https_canonicals?: bool,
63 * disable_autotrack?: bool|string,
64 * parsely_wipe_metadata_cache: bool,
65 * }
66 */
67 final class Settings_Page {
68 /**
69 * Instance of Parsely class.
70 *
71 * @var Parsely
72 */
73 private $parsely;
74
75 /**
76 * Admin page name used for hook suffixes.
77 *
78 * @since 3.2.0
79 *
80 * @var string
81 */
82 private $hook_suffix;
83
84 /**
85 * Constructor.
86 *
87 * @param Parsely $parsely Instance of Parsely class.
88 */
89 public function __construct( Parsely $parsely ) {
90 $this->parsely = $parsely;
91 }
92
93 /**
94 * Registers settings page.
95 *
96 * @since 3.0.0
97 */
98 public function run(): void {
99 add_action( 'admin_menu', array( $this, 'add_settings_sub_menu' ) );
100 add_action( 'admin_init', array( $this, 'initialize_settings' ) );
101 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_settings_assets' ) );
102 }
103
104 /**
105 * Enqueues all needed scripts and styles for Parse.ly plugin settings page.
106 *
107 * @param string $hook_suffix The current page being loaded.
108 */
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();
113
114 $admin_settings_asset = get_asset_info( 'build/admin-settings.asset.php' );
115 $built_assets_url = plugin_dir_url( PARSELY_FILE ) . '/build/';
116
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 );
124
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 }
132 }
133
134 /**
135 * Adds the Parse.ly settings page in WordPress settings menu.
136 */
137 public function add_settings_sub_menu(): void {
138 $suffix = add_options_page(
139 __( 'Parse.ly Settings', 'wp-parsely' ),
140 __( 'Parse.ly', 'wp-parsely' ),
141 Parsely::CAPABILITY,
142 Parsely::MENU_SLUG,
143 array( $this, 'display_settings' )
144 );
145
146 if ( is_string( $suffix ) ) {
147 $this->hook_suffix = $suffix;
148
149 // Adds help text when admin page loads.
150 add_action( 'load-' . $this->hook_suffix, array( $this, 'add_help_text' ) );
151 }
152 }
153
154 /**
155 * Adds the help tab to the settings page.
156 *
157 * @since 3.1.0
158 */
159 public function add_help_text(): void {
160 $screen = get_current_screen();
161 if ( null === $screen ) {
162 return;
163 }
164
165 $screen->add_help_tab(
166 array(
167 'id' => 'overview',
168 'title' => __( 'Overview', 'wp-parsely' ),
169 'content' => '<p>' . __( 'The only required setting on this page is the Site ID. All of the other settings are optional.', 'wp-parsely' ) . '</p>' .
170 '<p>' . __( 'You must click the Save Changes button at the bottom of the screen for new settings to take effect.', 'wp-parsely' ) . '</p>',
171 )
172 );
173 }
174
175 /**
176 * Displays the Parse.ly settings screen (options-general.php?page=[SLUG]).
177 */
178 public function display_settings(): void {
179 if ( ! current_user_can( Parsely::CAPABILITY ) ) {
180 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-parsely' ) );
181 }
182
183 include_once plugin_dir_path( PARSELY_FILE ) . 'views/parsely-settings.php';
184 }
185
186 /**
187 * Initializes the settings for Parse.ly.
188 */
189 public function initialize_settings(): void {
190 // All our options are actually stored in one single array to reduce DB queries.
191 register_setting(
192 Parsely::OPTIONS_KEY,
193 Parsely::OPTIONS_KEY,
194 array( $this, 'validate_options' )
195 );
196
197 $this->initialize_basic_section();
198 $this->initialize_recrawl_section();
199 $this->initialize_advanced_section();
200 }
201
202 /**
203 * Registers section and settings for Basic section.
204 *
205 * @since 3.2.0
206 */
207 private function initialize_basic_section(): void {
208 $section_key = 'basic-section';
209
210 add_settings_section(
211 $section_key,
212 __( 'Basic', 'wp-parsely' ),
213 '__return_null',
214 Parsely::MENU_SLUG
215 );
216
217 // Site ID.
218 $field_id = 'apikey';
219 $field_args = array(
220 'option_key' => $field_id,
221 'help_text' => __( 'Your Site ID is typically your own site domain without <code>http(s)://</code> prefixes or trailing <code>/</code> (e.g. <code>mydomain.com</code>).', 'wp-parsely' ),
222 'label_for' => $field_id,
223 'optional_args' => array(
224 'required' => 'required',
225 'placeholder' => 'mydomain.com',
226 ),
227
228 );
229 add_settings_field(
230 $field_id,
231 __( 'Parse.ly Site ID <em>(required)</em>', 'wp-parsely' ),
232 array( $this, 'print_text_tag' ),
233 Parsely::MENU_SLUG,
234 $section_key,
235 $field_args
236 );
237
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:support@parsely.com">support@parsely.com</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 );
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
278 // Metadata Format.
279 $field_id = 'meta_type';
280 $field_args = array(
281 'title' => __( 'Metadata Format', 'wp-parsely' ),
282 'option_key' => $field_id,
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' ),
284 'radio_options' => array(
285 'json_ld' => 'json_ld',
286 'repeated_metas' => 'repeated_metas',
287 ),
288 'label_for' => Parsely::OPTIONS_KEY . "[$field_id]",
289 'filter' => 'wp_parsely_metadata',
290 );
291 add_settings_field(
292 $field_id,
293 __( 'Metadata Format', 'wp-parsely' ),
294 array( $this, 'print_radio_tags' ),
295 Parsely::MENU_SLUG,
296 $section_key,
297 $field_args
298 );
299
300 // Logo.
301 $field_help = __( 'Here you can specify your logo\'s URL by using the "Browse" button or typing the URL manually.', 'wp-parsely' );
302 $field_id = 'logo';
303 add_settings_field(
304 $field_id,
305 __( 'Logo', 'wp-parsely' ),
306 array( $this, 'print_media_single_image' ),
307 Parsely::MENU_SLUG,
308 $section_key,
309 array(
310 'title' => __( 'Logo', 'wp-parsely' ), // Passed for legend element.
311 'option_key' => $field_id,
312 'label_for' => $field_id,
313 'help_text' => $field_help,
314 )
315 );
316
317 // Track logged-in users.
318 add_settings_field(
319 'track_authenticated_users',
320 __( 'Track Logged-in Users', 'wp-parsely' ),
321 array( $this, 'print_radio_tags' ),
322 Parsely::MENU_SLUG,
323 $section_key,
324 array(
325 'title' => __( 'Track Logged-in Users', 'wp-parsely' ), // Passed for legend element.
326 'option_key' => 'track_authenticated_users',
327 'radio_options' => array(
328 'true' => __( 'Yes, track logged-in users.', 'wp-parsely' ),
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' ),
330 ),
331 'help_text' => (
332 is_multisite() ?
333 __( ' Note: For WordPress multisite, a user must be logged-in to the current site to be considered logged-in.', 'wp-parsely' ) :
334 null
335 ),
336 )
337 );
338
339 // Disable JavaScript.
340 add_settings_field(
341 'disable_javascript',
342 __( 'Disable JavaScript', 'wp-parsely' ),
343 array( $this, 'print_radio_tags' ),
344 Parsely::MENU_SLUG,
345 $section_key,
346 array(
347 'title' => __( 'Disable JavaScript', 'wp-parsely' ), // Passed for legend element.
348 'option_key' => 'disable_javascript',
349 'radio_options' => array(
350 'true' => __( 'Yes, disable JavaScript tracking. I want to use a separate system for tracking instead of the Parse.ly plugin.', 'wp-parsely' ),
351 'false' => __( 'No, do not disable JavaScript tracking. I want the Parse.ly plugin to load the tracker.', 'wp-parsely' ),
352 ),
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' ),
354 'filter' => 'wp_parsely_load_js_tracker',
355 )
356 );
357
358 if ( defined( 'AMP__VERSION' ) ) {
359 // Disable AMP tracking.
360 add_settings_field(
361 'disable_amp',
362 __( 'Disable AMP Tracking', 'wp-parsely' ),
363 array( $this, 'print_radio_tags' ),
364 Parsely::MENU_SLUG,
365 $section_key,
366 array(
367 'title' => __( 'Disable AMP Tracking', 'wp-parsely' ), // Passed for legend element.
368 'option_key' => 'disable_amp',
369 'radio_options' => array(
370 'true' => __( 'Yes, disable Parse.ly tracking on AMP pages. I use a different system for JavaScript tracking on AMP pages.', 'wp-parsely' ),
371 'false' => __( 'No, do not disable Parse.ly tracking on AMP pages.', 'wp-parsely' ),
372 ),
373 )
374 );
375 }
376 }
377
378 /**
379 * Registers section and settings for Recrawl section.
380 *
381 * @since 3.2.0
382 */
383 private function initialize_recrawl_section(): void {
384 $section_key = 'recrawl-section';
385
386 add_settings_section(
387 $section_key,
388 __( 'Recrawl', 'wp-parsely' ),
389 function (): void {
390 echo '<br /><strong>' . wp_kses_post( __( '<span style="color:#d63638">Important:</span> Changing any of these values below on a site currently tracked with Parse.ly will require reprocessing of your Parse.ly data.', 'wp-parsely' ) ) . '</strong><br />';
391 printf(
392 /* translators: Mailto link */
393 esc_html__( 'Once you have changed a value and saved, please contact %s to request a recrawl.', 'wp-parsely' ),
394 wp_kses_post( '<a href="mailto:support@parsely.com?subject=' . rawurlencode( 'Please reprocess ' . $this->parsely->get_site_id() ) . '">support@parsely.com</a>' )
395 );
396 },
397 Parsely::MENU_SLUG
398 );
399
400 // Allow use of custom taxonomy to populate articleSection in parselyPage; defaults to category.
401 $field_id = 'track_post_types_as';
402 $field_help = __( 'By default, Parse.ly only tracks posts and pages. If you want to track other post types, select how you want to track them here.', 'wp-parsely' );
403 add_settings_field(
404 $field_id,
405 __( 'Track Post Types as', 'wp-parsely' ),
406 array( $this, 'print_track_post_types_table' ),
407 Parsely::MENU_SLUG,
408 $section_key,
409 array(
410 'title' => __( 'Track Post Types as', 'wp-parsely' ),
411 'option_key' => $field_id,
412 'help_text' => $field_help,
413 'filter' => 'wp_parsely_trackable_statuses',
414 )
415 );
416
417 // Content ID Prefix.
418 $field_id = 'content_id_prefix';
419 $field_args = array(
420 'option_key' => $field_id,
421 'optional_args' => array(
422 'placeholder' => 'WP-',
423 ),
424 'help_text' => __( 'If you use more than one content management system (e.g. WordPress and Drupal), you may end up with duplicate content IDs. Adding a Content ID Prefix will ensure the content IDs from WordPress will not conflict with other content management systems. We recommend using "WP-" for your prefix.', 'wp-parsely' ),
425 'label_for' => $field_id,
426 );
427 add_settings_field(
428 $field_id,
429 __( 'Content ID Prefix', 'wp-parsely' ),
430 array( $this, 'print_text_tag' ),
431 Parsely::MENU_SLUG,
432 $section_key,
433 $field_args
434 );
435
436 // Use top-level categories.
437 add_settings_field(
438 'use_top_level_cats',
439 __( 'Use Top-Level Categories for Section', 'wp-parsely' ),
440 array( $this, 'print_radio_tags' ),
441 Parsely::MENU_SLUG,
442 $section_key,
443 array(
444 'title' => __( 'Use Top-Level Categories for Section', 'wp-parsely' ), // Passed for legend element.
445 'option_key' => 'use_top_level_cats',
446 'radio_options' => array(
447 'true' => __( 'Yes, use the first category assigned to a post as the section name.', 'wp-parsely' ),
448 'false' => __( 'No, do not use the first category assigned to a post as the section name.', 'wp-parsely' ),
449 ),
450 'help_text' => __( 'If you choose Yes, and post a story to News > National > Florida, the plugin will use "News" for the section name in your dashboard instead of "Florida".', 'wp-parsely' ),
451 )
452 );
453
454 // Allow use of custom taxonomy to populate articleSection in parselyPage; defaults to category.
455 $field_id = 'custom_taxonomy_section';
456 $field_args = array(
457 'option_key' => $field_id,
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' ),
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 ),
470 'label_for' => Parsely::OPTIONS_KEY . "[$field_id]",
471 );
472 add_settings_field(
473 $field_id,
474 __( 'Use Custom Taxonomy for Section', 'wp-parsely' ),
475 array( $this, 'print_select_tag' ),
476 Parsely::MENU_SLUG,
477 $section_key,
478 $field_args
479 );
480
481 // Use categories and custom taxonomies as tags.
482 add_settings_field(
483 'cats_as_tags',
484 __( 'Add Categories to Tags', 'wp-parsely' ),
485 array( $this, 'print_radio_tags' ),
486 Parsely::MENU_SLUG,
487 $section_key,
488 array(
489 'title' => __( 'Add Categories to Tags', 'wp-parsely' ), // Passed for legend element.
490 'option_key' => 'cats_as_tags',
491 'radio_options' => array(
492 'true' => __( 'Yes, add all assigned categories and taxonomies to my tags.', 'wp-parsely' ),
493 'false' => __( 'No, do not add all assigned categories and taxonomies to my tags.', 'wp-parsely' ),
494 ),
495 'help_text' => __( 'If you choose Yes, then a post that has been assigned the categories "Business/Tech" and "Business/Social" will automatically include "Business/Tech" and "Business/Social" as tags, too.', 'wp-parsely' ),
496 )
497 );
498
499 // Lowercase all tags.
500 add_settings_field(
501 'lowercase_tags',
502 __( 'Lowercase All Tags', 'wp-parsely' ),
503 array( $this, 'print_radio_tags' ),
504 Parsely::MENU_SLUG,
505 $section_key,
506 array(
507 'title' => __( 'Lowercase All Tags', 'wp-parsely' ), // Passed for legend element.
508 'option_key' => 'lowercase_tags',
509 'radio_options' => array(
510 'true' => __( 'Yes, use lowercase versions of my tags to correct for potential misspellings.', 'wp-parsely' ),
511 'false' => __( 'No, do not use lowercase versions of my tags to correct for potential misspellings.', 'wp-parsely' ),
512 ),
513 )
514 );
515
516 add_settings_field(
517 'force_https_canonicals',
518 __( 'Force HTTPS Canonicals', 'wp-parsely' ),
519 array( $this, 'print_radio_tags' ),
520 Parsely::MENU_SLUG,
521 $section_key,
522 array(
523 'title' => __( 'Force HTTPS Canonicals', 'wp-parsely' ), // Passed for legend element.
524 'option_key' => 'force_https_canonicals',
525 'radio_options' => array(
526 'true' => __( 'Yes, force <code>https</code> canonical URLs by default.', 'wp-parsely' ),
527 'false' => __( 'No, I want to use <code>http</code>.', 'wp-parsely' ),
528 ),
529 'help_text' => __( 'Note: the plugin uses <code>http</code> by default, and this is fine for most publishers. It is unlikely you will have to change this unless directed to do so by a Parse.ly support representative.', 'wp-parsely' ),
530 )
531 );
532 }
533
534 /**
535 * Registers section and settings for Advanced section.
536 *
537 * @since 3.2.0
538 */
539 private function initialize_advanced_section(): void {
540 $section_key = 'advanced-section';
541
542 add_settings_section(
543 $section_key,
544 __( 'Advanced', 'wp-parsely' ),
545 '__return_null',
546 Parsely::MENU_SLUG
547 );
548
549 // Disable autotrack.
550 add_settings_field(
551 'disable_autotrack',
552 __( 'Disable Autotracking', 'wp-parsely' ),
553 array( $this, 'print_radio_tags' ),
554 Parsely::MENU_SLUG,
555 $section_key,
556 array(
557 'title' => __( 'Disable Autotracking', 'wp-parsely' ), // Passed for legend element.
558 'option_key' => 'disable_autotrack',
559 'radio_options' => array(
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' ),
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' ),
562 ),
563 )
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 );
579 }
580
581 /**
582 * Shows setting tabs.
583 *
584 * @since 3.8.0
585 */
586 public function show_setting_tabs(): void {
587 global $wp_settings_sections;
588 ?>
589
590 <nav class="nav-tab-wrapper">
591 <?php foreach ( $wp_settings_sections[ Parsely::MENU_SLUG ] as $section ) { ?>
592 <a
593 class="nav-tab <?php echo esc_attr( $section['id'] . '-tab' ); ?>"
594 href=<?php echo esc_url_raw( '?page=' . Parsely::MENU_SLUG . '#' . $section['id'] ); ?>
595 >
596 <?php echo esc_html( $section['title'] ); ?>
597 </a>
598 <?php } ?>
599 </nav>
600
601 <?php
602 }
603
604 /**
605 * Shows content of setting tabs.
606 *
607 * @since 3.8.0
608 */
609 public function show_setting_tabs_content(): void {
610 global $wp_settings_sections;
611
612 foreach ( $wp_settings_sections[ Parsely::MENU_SLUG ] as $section ) {
613 ?>
614
615 <div class="tab-content <?php echo esc_attr( $section['id'] ); ?>">
616 <?php
617 if ( $section['callback'] ) {
618 call_user_func( $section['callback'], $section );
619 }
620 ?>
621
622 <table class="form-table" role="presentation">
623 <?php do_settings_fields( Parsely::MENU_SLUG, $section['id'] ); ?>
624 </table>
625 </div>
626
627 <?php
628 }
629 }
630
631 /**
632 * Prints out a warning if the filter for the setting is defined, if any.
633 *
634 * @since 3.4.0
635 *
636 * @param Setting_Arguments $args The arguments for the form field. May contain 'filter'.
637 */
638 private function print_filter_text( $args ): void {
639 if ( isset( $args['filter'] ) && has_filter( $args['filter'] ) ) {
640 echo '<p>';
641 echo '<b><code>' . esc_html( $args['filter'] ) . '</code>' . esc_html__( 'filter hook is in use!', 'wp-parsely' ) . '</b> ';
642 echo esc_html__( 'A callback is attached to the filter hook that might interfere and override this setting.', 'wp-parsely' );
643 echo '</p>';
644 }
645 }
646
647 /**
648 * Prints out the description text, if there is any.
649 *
650 * @since 3.1.0
651 *
652 * @param Setting_Arguments $args The arguments for the form field. May contain 'help_text'.
653 */
654 private function print_description_text( $args ): void {
655 echo isset( $args['help_text'] ) ? '<p class="description" id="' . esc_attr( $args['option_key'] ) . '-description">' . wp_kses_post( $args['help_text'] ) . '</p>' : '';
656 }
657
658 /**
659 * Prints out an input text tag.
660 *
661 * @param Setting_Arguments $args The arguments for text tag.
662 */
663 public function print_text_tag( $args ): void {
664 $options = $this->parsely->get_options();
665 $name = $args['option_key'];
666 /**
667 * Variable.
668 *
669 * @var string
670 */
671 $value = $options[ $name ] ?? '';
672 $optional_args = $args['optional_args'] ?? array();
673 $id = esc_attr( $name );
674 $name = Parsely::OPTIONS_KEY . "[$id]";
675 $is_obfuscated_value = $optional_args['is_obfuscated_value'] ?? false;
676 $value = $is_obfuscated_value ? $this->get_obfuscated_value( $value ) : esc_attr( $value );
677 $accepted_args = array( 'placeholder', 'required' );
678 $type = $optional_args['type'] ?? 'text';
679
680 echo sprintf( "<input type='%s' name='%s' id='%s' value='%s'", esc_attr( $type ), esc_attr( $name ), esc_attr( $id ), esc_attr( $value ) );
681
682 if ( isset( $args['help_text'] ) ) {
683 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
684 }
685
686 foreach ( $optional_args as $key => $val ) {
687 if ( \in_array( $key, $accepted_args, true ) ) {
688 echo ' ' . esc_attr( $key ) . '="' . esc_attr( (string) $val ) . '"';
689 }
690 }
691 echo ' />';
692
693 $this->print_description_text( $args );
694 }
695
696 /**
697 * Prints a checkbox tag in the settings page.
698 *
699 * @param Setting_Arguments $args Arguments to print to checkbox tag.
700 */
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'] ?? '';
708
709 echo sprintf( "<input type='checkbox' name='%s' id='%s_true' value='true' ", esc_attr( $name ), esc_attr( $id ) );
710 if ( isset( $args['help_text'] ) ) {
711 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
712 }
713 echo checked( true === $value, true, false );
714 echo sprintf( " /> <label for='%s_true'>%s</label>", esc_attr( $id ), esc_html( $yes_text ) );
715
716 $this->print_description_text( $args );
717 }
718
719 /**
720 * Prints out the select tags
721 *
722 * @param Setting_Arguments $args The arguments for the select dropdowns.
723 */
724 public function print_select_tag( $args ): void {
725 $options = $this->parsely->get_options();
726 $name = $args['option_key'];
727 $select_options = $args['select_options'] ?? array();
728 $selected = $options[ $name ] ?? null;
729 $id = esc_attr( $name );
730 $name = Parsely::OPTIONS_KEY . "[$id]";
731
732 echo sprintf( "<select name='%s' id='%s'", esc_attr( $name ), esc_attr( $name ) );
733 if ( isset( $args['help_text'] ) ) {
734 echo ' aria-describedby="' . esc_attr( $id ) . '-description"';
735 }
736 echo '>';
737
738 foreach ( $select_options as $key => $val ) {
739 echo '<option value="' . esc_attr( $key ) . '" ';
740 echo selected( $selected, $key, false ) . '>';
741 echo esc_html( $val );
742 echo '</option>';
743 }
744 echo '</select>';
745
746 $this->print_filter_text( $args );
747 $this->print_description_text( $args );
748 }
749
750 /**
751 * Prints the radio buttons.
752 *
753 * @param Setting_Arguments $args The arguments for the radio buttons.
754 */
755 public function print_radio_tags( $args ): void {
756 $name = $args['option_key'];
757 $id = esc_attr( $name );
758 $selected = $this->parsely->get_options()[ $name ];
759 $title = $args['title'] ?? '';
760 $radio_options = $args['radio_options'] ?? array();
761
762 if ( is_bool( $selected ) ) {
763 // Converting boolean to string so that we have string type keys for all cases.
764 $selected = $selected ? 'true' : 'false';
765 }
766
767 ?>
768 <fieldset>
769 <legend class="screen-reader-text"><span><?php echo esc_html( $title ); ?></span></legend>
770 <p>
771 <?php foreach ( $radio_options as $value => $text ) { ?>
772 <label for="<?php echo esc_attr( "{$id}_{$value}" ); ?>">
773 <input
774 type="radio"
775 name="<?php echo esc_attr( Parsely::OPTIONS_KEY . "[$id]" ); ?>"
776 id="<?php echo esc_attr( "{$id}_{$value}" ); ?>"
777 value="<?php echo esc_attr( $value ); ?>"
778 <?php checked( $selected, $value ); ?>
779 />
780 <?php echo wp_kses_post( $text ); ?>
781 </label>
782 <br />
783 <?php } ?>
784 </p>
785 </fieldset>
786 <?php
787 $this->print_filter_text( $args );
788 $this->print_description_text( $args );
789 }
790
791 /**
792 * Prints out a "single-image browse control" which includes a text input to
793 * store image path and a button to browse for images.
794 *
795 * @param Setting_Arguments $args The arguments for the control.
796 */
797 public function print_media_single_image( $args ): void {
798 $key = $args['option_key'];
799 $title = $args['title'] ?? '';
800 /**
801 * Variable.
802 *
803 * @var string
804 */
805 $input_value = $this->parsely->get_options()[ $key ];
806 $input_name = Parsely::OPTIONS_KEY . "[$key]";
807 $button_text = __( 'Browse', 'wp-parsely' );
808 ?>
809
810 <fieldset class="media-single-image" id="media-single-image-<?php echo esc_attr( $key ); ?>">
811 <legend class="screen-reader-text"><span><?php echo esc_html( $title ); ?></span></legend>
812 <input class="file-path" type="text" name="<?php echo esc_attr( $input_name ); ?>" id="logo" value="<?php echo esc_attr( $input_value ); ?>" />
813 <button data-option="<?php echo esc_attr( $key ); ?>" class="browse button" type="button"><?php echo esc_html( $button_text ); ?></button>
814 </fieldset>
815
816 <?php
817 $this->print_description_text( $args );
818 }
819
820 /**
821 * Prints out the post tracking options table.
822 *
823 * @since 3.2.0
824 *
825 * @param Setting_Arguments $args The arguments used in the output HTML elements.
826 */
827 public function print_track_post_types_table( $args ): void {
828 $option_key = esc_attr( $args['option_key'] );
829 $title = $args['title'] ?? '';
830 /**
831 * Variable.
832 *
833 * @var array<string>
834 */
835 $post_types = get_post_types( array( 'public' => true ) );
836 $values = $this->get_tracking_values_for_display();
837 ?>
838 <fieldset>
839 <legend class="screen-reader-text"><span><?php echo esc_html( $title ); ?></span></legend>
840 <table class="form-table widefat striped" id="track-post-types">
841 <caption class="screen-reader-text"><?php echo esc_html( $title ); ?></caption>
842 <thead>
843 <tr>
844 <th scope="col"><?php echo esc_html__( 'Post Type', 'wp-parsely' ); ?></th>
845 <th id="track-post-types--post" scope="col"><?php echo esc_html__( 'Track as Post', 'wp-parsely' ); ?></th>
846 <th id="track-post-types--page" scope="col"><?php echo esc_html__( 'Track as Non-Post', 'wp-parsely' ); ?></th>
847 <th id="track-post-types--none" scope="col"><?php echo esc_html__( 'Do not track', 'wp-parsely' ); ?></th>
848 </tr>
849 </thead>
850 <tbody>
851 <?php
852 foreach ( $post_types as $post_type ) {
853 $group_name = "parsely[{$option_key}][{$post_type}]";
854 $id_post = "{$option_key}_{$post_type}_post";
855 $id_page = "{$option_key}_{$post_type}_page";
856 $id_none = "{$option_key}_{$post_type}_none";
857 $value = $values[ $post_type ] ?? 'none';
858 ?>
859 <tr>
860 <th scope="row"><?php echo esc_html( $post_type ); ?></th>
861 <td>
862 <label aria-labelledby="track-post-types--post" for="<?php echo esc_attr( $id_post ); ?>">
863 <input id="<?php echo esc_attr( $id_post ); ?>" name="<?php echo esc_attr( $group_name ); ?>" type="radio" value="post" <?php checked( $value, 'post' ); ?> />
864 </label>
865 </td>
866 <td>
867 <label aria-labelledby="track-post-types--page" for="<?php echo esc_attr( $id_page ); ?>">
868 <input id="<?php echo esc_attr( $id_page ); ?>" name="<?php echo esc_attr( $group_name ); ?>" type="radio" value="page" <?php checked( $value, 'page' ); ?> />
869 </label>
870 </td>
871 <td>
872 <label aria-labelledby="track-post-types--none" for="<?php echo esc_attr( $id_none ); ?>">
873 <input id="<?php echo esc_attr( $id_none ); ?>" name="<?php echo esc_attr( $group_name ); ?>" type="radio" value="none" <?php checked( $value, 'none' ); ?> />
874 </label>
875 </td>
876 </tr>
877 <?php } ?>
878 </tbody>
879 </table>
880 </fieldset>
881 <?php
882 $this->print_filter_text( $args );
883 $this->print_description_text( $args );
884 }
885
886 /**
887 * Returns the custom post type tracking values in a format that is easily
888 * consumable by the print_track_post_types_table() function.
889 *
890 * @since 3.2.0
891 *
892 * @return array<string> Key-value pairs with post type and their 'track as' value.
893 */
894 public function get_tracking_values_for_display(): array {
895 $options = $this->parsely->get_options();
896 $types = array( 'post', 'page' );
897 $result = array();
898
899 foreach ( $types as $type ) {
900 $array_value = $options[ "track_{$type}_types" ];
901
902 foreach ( $array_value as $post_type ) {
903 $result[ $post_type ] = $type;
904 }
905 }
906
907 return $result;
908 }
909
910 /**
911 * Validates the options provided by the user.
912 *
913 * @param ParselySettingOptions $input Options from the settings page.
914 *
915 * @return ParselySettingOptions
916 */
917 public function validate_options( $input ) {
918 $input = $this->validate_basic_section( $input );
919 $input = $this->validate_recrawl_section( $input );
920 $input = $this->validate_advanced_section( $input );
921
922 return $input;
923 }
924
925 /**
926 * Validates fields of Basic Section.
927 *
928 * @param ParselySettingOptions $input Options from the settings page.
929 *
930 * @return ParselySettingOptions Validated inputs.
931 */
932 private function validate_basic_section( $input ) {
933 $options = $this->parsely->get_options();
934
935 if ( '' === $input['apikey'] ) {
936 add_settings_error(
937 Parsely::OPTIONS_KEY,
938 'apikey',
939 __( 'Please specify the Site ID', 'wp-parsely' )
940 );
941 } else {
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 }
953
954 $input['api_secret'] = $this->get_unobfuscated_value( $input['api_secret'], $this->parsely->get_api_secret() );
955
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 ) {
959 add_settings_error(
960 Parsely::OPTIONS_KEY,
961 'metadata_secret',
962 __( 'Metadata secret is incorrect. Please contact Parse.ly support!', 'wp-parsely' )
963 );
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' );
968
969 wp_schedule_event( time() + 100, 'everytenminutes', 'parsely_bulk_metas_update' );
970 $input['parsely_wipe_metadata_cache'] = false;
971 }
972 }
973
974 if ( ! isset( $input['meta_type'] ) ) {
975 $input['meta_type'] = $options['meta_type'];
976 } else {
977 $input['meta_type'] = sanitize_text_field( $input['meta_type'] );
978 }
979
980 if ( '' === $input['logo'] ) {
981 $input['logo'] = self::get_logo_default();
982 }
983
984 // Track authenticated users.
985 if ( 'true' !== $input['track_authenticated_users'] && 'false' !== $input['track_authenticated_users'] ) {
986 add_settings_error(
987 Parsely::OPTIONS_KEY,
988 'track_authenticated_users',
989 __( 'Value passed for track_authenticated_users must be either "true" or "false".', 'wp-parsely' )
990 );
991 } else {
992 $input['track_authenticated_users'] = 'true' === $input['track_authenticated_users'];
993 }
994
995 if ( 'true' !== $input['disable_javascript'] && 'false' !== $input['disable_javascript'] ) {
996 add_settings_error(
997 Parsely::OPTIONS_KEY,
998 'disable_javascript',
999 __( 'Value passed for disable_javascript must be either "Yes" or "No".', 'wp-parsely' )
1000 );
1001 } else {
1002 $input['disable_javascript'] = 'true' === $input['disable_javascript'];
1003 }
1004
1005 // Allow for Disable AMP setting to be conditionally included on the page.
1006 // If it's not shown, then set the value as what was previously saved.
1007 if ( ! isset( $input['disable_amp'] ) ) {
1008 $input['disable_amp'] = 'true';
1009 if ( false === $options['disable_amp'] ) {
1010 $input['disable_amp'] = 'false';
1011 }
1012 }
1013
1014 if ( 'true' !== $input['disable_amp'] && 'false' !== $input['disable_amp'] ) {
1015 add_settings_error(
1016 Parsely::OPTIONS_KEY,
1017 'disable_amp',
1018 __( 'Value passed for disable_amp must be either "true" or "false".', 'wp-parsely' )
1019 );
1020 } else {
1021 $input['disable_amp'] = 'true' === $input['disable_amp'];
1022 }
1023
1024 return $input;
1025 }
1026
1027 /**
1028 * Validates fields of Recrawl Section.
1029 *
1030 * @param ParselySettingOptions $input Options from the settings page.
1031 *
1032 * @return ParselySettingOptions Validated inputs.
1033 */
1034 private function validate_recrawl_section( $input ) {
1035 $options = $this->parsely->get_options();
1036
1037 $this->validate_options_post_type_tracking( $input );
1038
1039 // Content ID prefix.
1040 if ( ! isset( $input['content_id_prefix'] ) ) {
1041 $input['content_id_prefix'] = $options['content_id_prefix'];
1042 } else {
1043 $input['content_id_prefix'] = sanitize_text_field( $input['content_id_prefix'] );
1044 }
1045
1046 // Allow for Top-level categories setting to be conditionally included on the page.
1047 // If it's not shown, then set the value as what was previously saved.
1048 if ( ! isset( $input['use_top_level_cats'] ) ) {
1049 $input['use_top_level_cats'] = 'true';
1050 if ( false === $options['use_top_level_cats'] ) {
1051 $input['use_top_level_cats'] = 'false';
1052 }
1053 }
1054
1055 // Top-level categories.
1056 if ( 'true' !== $input['use_top_level_cats'] && 'false' !== $input['use_top_level_cats'] ) {
1057 add_settings_error(
1058 Parsely::OPTIONS_KEY,
1059 'use_top_level_cats',
1060 __( 'Value passed for use_top_level_cats must be either "true" or "false".', 'wp-parsely' )
1061 );
1062 } else {
1063 $input['use_top_level_cats'] = 'true' === $input['use_top_level_cats'];
1064 }
1065
1066 // Custom taxonomy as section.
1067 if ( ! isset( $input['custom_taxonomy_section'] ) ) {
1068 $input['custom_taxonomy_section'] = $options['custom_taxonomy_section'];
1069 } else {
1070 $input['custom_taxonomy_section'] = sanitize_text_field( $input['custom_taxonomy_section'] );
1071 }
1072
1073 // Allow for Categories as Tags setting to be conditionally included on the page.
1074 // If it's not shown, then set the value as what was previously saved.
1075 if ( ! isset( $input['cats_as_tags'] ) ) {
1076 $input['cats_as_tags'] = 'true';
1077 if ( false === $options['cats_as_tags'] ) {
1078 $input['cats_as_tags'] = 'false';
1079 }
1080 }
1081
1082 // Child categories as tags.
1083 if ( 'true' !== $input['cats_as_tags'] && 'false' !== $input['cats_as_tags'] ) {
1084 add_settings_error(
1085 Parsely::OPTIONS_KEY,
1086 'cats_as_tags',
1087 __( 'Value passed for cats_as_tags must be either "true" or "false".', 'wp-parsely' )
1088 );
1089 } else {
1090 $input['cats_as_tags'] = 'true' === $input['cats_as_tags'];
1091 }
1092
1093 // Allow for Lowercase Tags setting to be conditionally included on the page.
1094 // If it's not shown, then set the value as what was previously saved.
1095 if ( ! isset( $input['lowercase_tags'] ) ) {
1096 $input['lowercase_tags'] = 'true';
1097 if ( false === $options['lowercase_tags'] ) {
1098 $input['lowercase_tags'] = 'false';
1099 }
1100 }
1101
1102 // Lowercase tags.
1103 if ( 'true' !== $input['lowercase_tags'] && 'false' !== $input['lowercase_tags'] ) {
1104 add_settings_error(
1105 Parsely::OPTIONS_KEY,
1106 'lowercase_tags',
1107 __( 'Value passed for lowercase_tags must be either "true" or "false".', 'wp-parsely' )
1108 );
1109 } else {
1110 $input['lowercase_tags'] = 'true' === $input['lowercase_tags'];
1111 }
1112
1113 // Allow for Force HTTPS Canonical setting to be conditionally included on the page.
1114 // If it's not shown, then set the value as what was previously saved.
1115 if ( ! isset( $input['force_https_canonicals'] ) ) {
1116 $input['force_https_canonicals'] = 'true';
1117 if ( false === $options['force_https_canonicals'] ) {
1118 $input['force_https_canonicals'] = 'false';
1119 }
1120 }
1121
1122 if ( 'true' !== $input['force_https_canonicals'] && 'false' !== $input['force_https_canonicals'] ) {
1123 add_settings_error(
1124 Parsely::OPTIONS_KEY,
1125 'force_https_canonicals',
1126 __( 'Value passed for force_https_canonicals must be either "true" or "false".', 'wp-parsely' )
1127 );
1128 } else {
1129 $input['force_https_canonicals'] = 'true' === $input['force_https_canonicals'];
1130 }
1131
1132 return $input;
1133 }
1134
1135 /**
1136 * Validates fields of Advanced Section.
1137 *
1138 * @param ParselySettingOptions $input Options from the settings page.
1139 *
1140 * @return ParselySettingOptions Validated inputs.
1141 */
1142 private function validate_advanced_section( $input ) {
1143 $options = $this->parsely->get_options();
1144
1145 if ( ! isset( $input['disable_autotrack'] ) ) {
1146 $input['disable_autotrack'] = $options['disable_autotrack'];
1147 } elseif ( 'true' !== $input['disable_autotrack'] && 'false' !== $input['disable_autotrack'] ) {
1148 add_settings_error(
1149 Parsely::OPTIONS_KEY,
1150 'disable_autotrack',
1151 __( 'Value passed for disable_autotrack must be either "Yes" or "No".', 'wp-parsely' )
1152 );
1153 } else {
1154 $input['disable_autotrack'] = 'true' === $input['disable_autotrack'];
1155 }
1156
1157 return $input;
1158 }
1159
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 /**
1183 * Sanitizes the passed Site ID.
1184 *
1185 * @since 3.3.0
1186 *
1187 * @param string $site_id The Site ID to be sanitized.
1188 * @return string
1189 */
1190 private function sanitize_site_id( string $site_id ): string {
1191 return strtolower( sanitize_text_field( $site_id ) );
1192 }
1193
1194 /**
1195 * Receives the $input array from the validate_options() function and
1196 * validate post tracking options.
1197 *
1198 * This function will mutate the $input array.
1199 *
1200 * @since 3.2.0
1201 *
1202 * @param ParselySettingOptions $input Array passed to validate_options() function.
1203 */
1204 private function validate_options_post_type_tracking( &$input ): void {
1205 $options = $this->parsely->get_options();
1206 $posts = 'track_post_types';
1207 $pages = 'track_page_types';
1208 $track_as = 'track_post_types_as';
1209 $input[ $posts ] = $options[ $posts ];
1210 $input[ $pages ] = $options[ $pages ];
1211
1212 // @phpstan-ignore-next-line
1213 if ( isset( $input[ $track_as ] ) && is_array( $input[ $track_as ] ) && 0 < count( $input[ $track_as ] ) ) {
1214 $post_types = get_post_types( array( 'public' => true ) );
1215 $temp_posts = array();
1216 $temp_pages = array();
1217
1218 // Create temporary Post and Page arrays, disallowing non-existent post types.
1219 foreach ( $input[ $track_as ] as $key => $value ) {
1220 if ( false === in_array( $key, $post_types, true ) ) {
1221 continue;
1222 }
1223
1224 if ( 'post' === $value ) {
1225 $temp_posts[] = $key;
1226 } elseif ( 'page' === $value ) {
1227 $temp_pages[] = $key;
1228 }
1229 }
1230
1231 // Cleanup and sanitized values assignment.
1232 $input [ $posts ] = self::sanitize_option_array( $temp_posts );
1233 $input [ $pages ] = self::sanitize_option_array( $temp_pages );
1234 }
1235
1236 if ( isset( $input[ $track_as ] ) ) {
1237 unset( $input[ $track_as ] );
1238 }
1239 }
1240
1241 /**
1242 * Returns default logo if one can be found.
1243 *
1244 * @return string
1245 */
1246 private static function get_logo_default(): string {
1247 /**
1248 * Variable.
1249 *
1250 * @var int
1251 */
1252 $custom_logo_id = get_theme_mod( 'custom_logo' );
1253 if ( (bool) $custom_logo_id ) {
1254 $logo_attrs = wp_get_attachment_image_src( $custom_logo_id, 'full' );
1255 if ( isset( $logo_attrs[0] ) ) {
1256 return $logo_attrs[0];
1257 }
1258 }
1259
1260 // get_site_icon_url returns an empty string if one isn't found,
1261 // which is what we want to use as the default anyway.
1262 return get_site_icon_url();
1263 }
1264
1265 /**
1266 * Sanitizes all elements in an option array.
1267 *
1268 * @param array<int, string> $array Array of options to be sanitized.
1269 * @return array<int, string>
1270 */
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 );
1275 }
1276 return $new_array;
1277 }
1278
1279 /**
1280 * Gets obfuscated value.
1281 *
1282 * @param string $current_value Current value of the field.
1283 *
1284 * @return string
1285 */
1286 private function get_obfuscated_value( $current_value ): string {
1287 return str_repeat( '*', strlen( $current_value ) );
1288 }
1289
1290 /**
1291 * Gets unobfuscated value.
1292 *
1293 * @param string $current_value Current value of the field.
1294 * @param string $previous_value Previous value of the field. If current
1295 * value is obfuscated then we will use this.
1296 *
1297 * @return string
1298 */
1299 private function get_unobfuscated_value( $current_value, $previous_value ): string {
1300 if ( $current_value === $this->get_obfuscated_value( $current_value ) ) {
1301 return '' === $current_value ? $current_value : $previous_value;
1302 }
1303
1304 return $current_value;
1305 }
1306 }
1307