PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
← All changes | lib/options.php +2107 -0 21.13.122.7.0 View file →
@@ -1,0 +1,2107 @@
1 +<?php
2 +/*
3 + * License: GPLv3
4 + * License URI: https://www.gnu.org/licenses/gpl.txt
5 + * Copyright 2012-2026 Jean-Sebastien Morisset (https://wpsso.com/)
6 + */
7 +
8 +if ( ! defined( 'ABSPATH' ) ) {
9 +
10 + die( 'These aren\'t the droids you\'re looking for.' );
11 +}
12 +
13 +if ( ! defined( 'WPSSO_PLUGINDIR' ) ) {
14 +
15 + die( 'Do. Or do not. There is no try.' );
16 +}
17 +
18 +if ( ! class_exists( 'WpssoOptions' ) ) {
19 +
20 + class WpssoOptions {
21 +
22 + private $p; // Wpsso class object.
23 + private $upgrade; // WpssoUpgrade class object.
24 + private $filters; // WpssoOptionsFilters class object.
25 +
26 + private static $cache_allowed = false;
27 +
28 + /*
29 + * Instantiated by Wpsso->set_objects().
30 + */
31 + public function __construct( &$plugin ) {
32 +
33 + $this->p =& $plugin;
34 +
35 + if ( $this->p->debug->enabled ) {
36 +
37 + $this->p->debug->mark();
38 + }
39 +
40 + require_once WPSSO_PLUGINDIR . 'lib/options-filters.php';
41 +
42 + $this->filters = new WpssoOptionsFilters( $plugin );
43 +
44 + $this->p->util->add_plugin_actions( $this, array(
45 + 'init_objects' => 0,
46 + ), $prio = 1000 );
47 + }
48 +
49 + /*
50 + * This action is called by Wpsso->set_objects() to initialize additional class objects.
51 + */
52 + public function action_init_objects() {
53 +
54 + if ( $this->p->debug->enabled ) {
55 +
56 + $this->p->debug->log( 'setting cache_allowed to true' );
57 + }
58 +
59 + self::$cache_allowed = true;
60 + }
61 +
62 + public static function is_cache_allowed() {
63 +
64 + return self::$cache_allowed;
65 + }
66 +
67 + public function get_defaults( $opt_key = false, $force_filter = false ) {
68 +
69 + if ( $this->p->debug->enabled ) {
70 +
71 + $this->p->debug->log_args( array(
72 + 'opt_key' => $opt_key,
73 + 'force_filter' => $force_filter,
74 + ) );
75 + }
76 +
77 + static $local_cache = array();
78 +
79 + $is_cache_allowed = self::is_cache_allowed();
80 +
81 + if ( empty( $local_cache ) || ! $is_cache_allowed ) {
82 +
83 + $local_cache = $this->p->cf[ 'opt' ][ 'defaults' ];
84 + }
85 +
86 + if ( $force_filter || empty( $local_cache[ 'opt_filtered' ] ) ) {
87 +
88 + if ( $this->p->debug->enabled ) {
89 +
90 + $this->p->debug->mark( 'get_defaults filters' ); // Begin timer.
91 + }
92 +
93 + /*
94 + * Set before calling filters to prevent recursion.
95 + */
96 + if ( $this->p->debug->enabled ) {
97 +
98 + $this->p->debug->log( 'setting opt_filtered to 1' );
99 + }
100 +
101 + $local_cache[ 'opt_filtered' ] = 1;
102 +
103 + /*
104 + * If there is a plugin auth method configured, make sure the option key exists.
105 + */
106 + foreach ( $this->p->cf[ 'plugin' ] as $ext => $info ) {
107 +
108 + if ( ! empty( $info[ 'update_auth' ] ) && 'none' !== $info[ 'update_auth' ] ) { // Just in case.
109 +
110 + $local_cache[ 'plugin_' . $ext . '_' . $info[ 'update_auth' ] ] = '';
111 + }
112 + }
113 +
114 + /*
115 + * Complete the options array for custom post types and taxonomies.
116 + */
117 + $this->add_custom_post_tax_options( $local_cache );
118 +
119 + /*
120 + * Define the default organization or person ID for Knowledge Graph markup in the home page.
121 + */
122 + if ( isset( $this->p->options[ 'site_pub_schema_type' ] ) ) {
123 +
124 + switch ( $this->p->options[ 'site_pub_schema_type' ] ) {
125 +
126 + case 'person':
127 +
128 + $local_cache[ 'schema_def_pub_org_id' ] = 'none';
129 + $local_cache[ 'schema_def_pub_person_id' ] = $this->p->options[ 'site_pub_person_id' ];
130 +
131 + break;
132 +
133 + case 'organization':
134 +
135 + $local_cache[ 'schema_def_pub_org_id' ] = 'site';
136 + $local_cache[ 'schema_def_pub_person_id' ] = 'none';
137 +
138 + break;
139 + }
140 + }
141 +
142 + /*
143 + * Update default place options based on the open graph defaults.
144 + */
145 + if ( isset( $this->p->options[ 'og_def_country' ] ) ) $local_cache[ 'schema_def_place_country' ] = $this->p->options[ 'og_def_country' ];
146 + if ( isset( $this->p->options[ 'og_def_timezone' ] ) ) $local_cache[ 'schema_def_place_timezone' ] = $this->p->options[ 'og_def_timezone' ];
147 +
148 + /*
149 + * Get translated strings for variable based options.
150 + */
151 + $this->set_default_text( $local_cache, 'plugin_title_part_site' ); // Title Tag Site Prefix / Suffix.
152 + $this->set_default_text( $local_cache, 'plugin_title_part_tagline' ); // Title Tag Tagline Prefix / Suffix.
153 + $this->set_default_text( $local_cache, 'plugin_img_alt_prefix' ); // Content Image Alt Prefix.
154 + $this->set_default_text( $local_cache, 'plugin_p_cap_prefix' ); // WP Caption Text Prefix.
155 + $this->set_default_text( $local_cache, 'plugin_comment_title' ); // Comment Title.
156 + $this->set_default_text( $local_cache, 'plugin_comment_reply_title' ); // Reply Comment Title.
157 + $this->set_default_text( $local_cache, 'plugin_comment_review_title' ); // Review Comment Title.
158 + $this->set_default_text( $local_cache, 'plugin_product_var_title' ); // Product Variation Title.
159 + $this->set_default_text( $local_cache, 'plugin_feed_title' ); // RSS Feed Title.
160 + $this->set_default_text( $local_cache, 'plugin_404_page_title' ); // 404 Page Title.
161 + $this->set_default_text( $local_cache, 'plugin_404_page_desc' ); // 404 Page Description.
162 + $this->set_default_text( $local_cache, 'plugin_no_title_text' ); // No Title Text.
163 + $this->set_default_text( $local_cache, 'plugin_no_desc_text' ); // No Description Text.
164 + $this->set_default_text( $local_cache, 'plugin_term_page_title' ); // Term Archive Title.
165 + $this->set_default_text( $local_cache, 'plugin_term_page_desc' ); // Term Archive Description.
166 + $this->set_default_text( $local_cache, 'plugin_author_page_title' ); // Author Archive Title.
167 + $this->set_default_text( $local_cache, 'plugin_author_page_desc' ); // Author Archive Description.
168 + $this->set_default_text( $local_cache, 'plugin_search_page_title' ); // Search Results Title.
169 + $this->set_default_text( $local_cache, 'plugin_search_page_desc' ); // Search Results Description.
170 + $this->set_default_text( $local_cache, 'plugin_year_page_title' ); // Year Archive Title.
171 + $this->set_default_text( $local_cache, 'plugin_year_page_desc' ); // Year Archive Description.
172 + $this->set_default_text( $local_cache, 'plugin_month_page_title' ); // Month Archive Title.
173 + $this->set_default_text( $local_cache, 'plugin_month_page_desc' ); // Month Archive Description.
174 + $this->set_default_text( $local_cache, 'plugin_day_page_title' ); // Day Archive Title.
175 + $this->set_default_text( $local_cache, 'plugin_day_page_desc' ); // Day Archive Description.
176 +
177 + /*
178 + * Translate contact method field labels for current language.
179 + */
180 + if ( $this->p->debug->enabled ) {
181 +
182 + $this->p->debug->log( 'translating plugin contact field labels' );
183 + }
184 +
185 + SucomUtilOptions::transl_key_values( '/^plugin_(cm_.*_label|.*_prefix)$/', $local_cache, 'wpsso' );
186 +
187 + /*
188 + * Define the default Facebook locale and current locale values.
189 + */
190 + if ( $this->p->debug->enabled ) {
191 +
192 + $this->p->debug->log( 'calling get_fb_locale() for default' );
193 + }
194 +
195 + $local_cache[ 'fb_locale' ] = $this->p->og->get_fb_locale( $mixed = 'default', $use_opts = false );
196 +
197 + $current_fb_locale_key = SucomUtilOptions::get_key_locale( 'fb_locale' );
198 +
199 + if ( 'fb_locale' !== $current_fb_locale_key ) {
200 +
201 + if ( $this->p->debug->enabled ) {
202 +
203 + $this->p->debug->log( 'calling get_fb_locale() for current' );
204 + }
205 +
206 + $local_cache[ $current_fb_locale_key ] = $this->p->og->get_fb_locale( $mixed = 'current', $use_opts = false );
207 + }
208 +
209 + /*
210 + * Check to see if we have a full webpage cache plugin or service active.
211 + */
212 + if ( ! empty( $this->p->avail[ 'cache' ][ 'any' ] ) ) {
213 +
214 + $local_cache[ 'plugin_page_cache_active' ] = 1;
215 + }
216 +
217 + /*
218 + * Import metadata and block attributes from known SEO plugins.
219 + */
220 + foreach ( array(
221 + 'aioseop' => 'aioseo_options', // All in One SEO Pack.
222 + 'rankmath' => 'rank-math-options-general', // Rank Math SEO.
223 + 'seoframework' => 'autodescription-site-settings', // The SEO Framework.
224 + 'wpmetaseo' => 'wpmetaseo', // WP Meta SEO.
225 + 'wpseo' => 'wpseo', // Yoast SEO.
226 + ) as $avail_key => $seo_option_key ) {
227 +
228 + if ( ! empty( $this->p->avail[ 'seo' ][ $avail_key ] ) ||
229 + ( empty( $this->p->avail[ 'seo' ][ 'any' ] ) && get_option( $seo_option_key ) ) ) {
230 +
231 + foreach ( array( 'meta', 'blocks' ) as $import_type ) {
232 +
233 + /*
234 + * Option key examples:
235 + *
236 + * 'plugin_import_aioseop_meta'
237 + * 'plugin_import_rankmath_meta'
238 + * 'plugin_import_seoframework_meta'
239 + * 'plugin_import_wpmetaseo_meta'
240 + * 'plugin_import_wpseo_meta'
241 + * 'plugin_import_wpseo_blocks'
242 + */
243 + $key = 'plugin_import_' . $avail_key . '_' . $import_type;
244 +
245 + if ( isset( $local_cache[ $key ] ) ) { // Make sure the option exists.
246 +
247 + $local_cache[ $key ] = 1;
248 + }
249 + }
250 + }
251 + }
252 +
253 + /*
254 + * Check for website verification IDs and enable/disable meta tags as required.
255 + */
256 + foreach ( WpssoConfig::$cf[ 'opt' ][ 'site_verify_meta_names' ] as $site_verify => $meta_name ) {
257 +
258 + $fixed[ 'add_meta_name_' . $meta_name ] = empty( $opts[ $site_verify ] ) ? 0 : 1;
259 + }
260 +
261 + /*
262 + * Check for default values from network admin settings.
263 + */
264 + if ( is_multisite() && is_array( $this->p->site_options ) ) {
265 +
266 + foreach ( $this->p->site_options as $site_opt_key => $site_opt_val ) {
267 +
268 + if ( isset( $local_cache[ $site_opt_key ] ) && isset( $this->p->site_options[ $site_opt_key . ':use' ] ) ) {
269 +
270 + if ( 'default' === $this->p->site_options[ $site_opt_key . ':use' ] ) {
271 +
272 + $local_cache[ $site_opt_key ] = $this->p->site_options[ $site_opt_key ];
273 + }
274 + }
275 + }
276 + }
277 +
278 + if ( $this->p->debug->enabled ) {
279 +
280 + $this->p->debug->log( 'applying filters "wpsso_get_defaults"' );
281 + }
282 +
283 + $local_cache = apply_filters( 'wpsso_get_defaults', $local_cache );
284 +
285 + if ( ! $is_cache_allowed ) {
286 +
287 + unset( $local_cache[ 'opt_filtered' ] );
288 + }
289 +
290 + if ( $this->p->debug->enabled ) {
291 +
292 + $this->p->debug->mark( 'get_defaults filters' ); // End timer.
293 + }
294 +
295 + } elseif ( $this->p->debug->enabled ) {
296 +
297 + $this->p->debug->log( 'skipped filters: opt_filtered is true' );
298 + }
299 +
300 + if ( false !== $opt_key ) {
301 +
302 + if ( isset( $local_cache[ $opt_key ] ) ) {
303 +
304 + return $local_cache[ $opt_key ];
305 + }
306 +
307 + return null;
308 + }
309 +
310 + return $local_cache;
311 + }
312 +
313 + public function get_site_defaults( $opt_key = false, $force_filter = false ) {
314 +
315 + if ( $this->p->debug->enabled ) {
316 +
317 + $this->p->debug->log_args( array(
318 + 'opt_key' => $opt_key,
319 + 'force_filter' => $force_filter,
320 + ) );
321 + }
322 +
323 + static $local_cache = array();
324 +
325 + $is_cache_allowed = self::is_cache_allowed();
326 +
327 + if ( empty( $local_cache ) || ! $is_cache_allowed ) {
328 +
329 + /*
330 + * Automatically include all advanced plugin options.
331 + */
332 + $local_cache = SucomUtil::preg_grep_keys( '/^plugin_/', $this->p->cf[ 'opt' ][ 'defaults' ] );
333 +
334 + /*
335 + * Add a "Site Use" for each option.
336 + */
337 + foreach ( $local_cache as $key => $val ) {
338 +
339 + if ( false === strpos( $key, ':' ) ) { // Just in case.
340 +
341 + $local_cache[ $key . ':use' ] = 'default';
342 + }
343 + }
344 +
345 + $local_cache = array_merge( $local_cache, $this->p->cf[ 'opt' ][ 'site_defaults' ] );
346 + }
347 +
348 + if ( $force_filter || empty( $local_cache[ 'opt_filtered' ] ) ) {
349 +
350 + if ( $this->p->debug->enabled ) {
351 +
352 + $this->p->debug->mark( 'get_site_defaults filters' ); // Begin timer.
353 + }
354 +
355 + /*
356 + * Set before calling filters to prevent recursion.
357 + */
358 + if ( $this->p->debug->enabled ) {
359 +
360 + $this->p->debug->log( 'setting opt_filtered to 1' );
361 + }
362 +
363 + $local_cache[ 'opt_filtered' ] = 1;
364 +
365 + /*
366 + * If there is a plugin auth method configured, make sure the option key exists.
367 + */
368 + foreach ( $this->p->cf[ 'plugin' ] as $ext => $info ) {
369 +
370 + if ( ! empty( $info[ 'update_auth' ] ) && 'none' !== $info[ 'update_auth' ] ) { // Just in case.
371 +
372 + $local_cache[ 'plugin_' . $ext . '_' . $info[ 'update_auth' ] ] = '';
373 +
374 + $local_cache[ 'plugin_' . $ext . '_' . $info[ 'update_auth' ] . ':use' ] = 'default';
375 + }
376 + }
377 +
378 + if ( $this->p->debug->enabled ) {
379 +
380 + $this->p->debug->log( 'applying filters "wpsso_get_site_defaults"' );
381 + }
382 +
383 + $local_cache = apply_filters( 'wpsso_get_site_defaults', $local_cache );
384 +
385 + if ( ! $is_cache_allowed ) {
386 +
387 + unset( $local_cache[ 'opt_filtered' ] );
388 + }
389 +
390 + if ( $this->p->debug->enabled ) {
391 +
392 + $this->p->debug->mark( 'get_site_defaults filters' ); // End timer.
393 + }
394 + }
395 +
396 + if ( false !== $opt_key ) {
397 +
398 + if ( isset( $local_cache[ $opt_key ] ) ) {
399 +
400 + return $local_cache[ $opt_key ];
401 + }
402 +
403 + return null;
404 + }
405 +
406 + return $local_cache;
407 + }
408 +
409 + /*
410 + * Returns a checked, fixed, and/or upgraded options array.
411 + *
412 + * See WpssoAdmin->init_check_options().
413 + * See WpssoAdmin->import_plugin_settings_json().
414 + */
415 + public function check_options( $options_name, array $opts, $network = false ) {
416 +
417 + if ( $this->p->debug->enabled ) {
418 +
419 + $this->p->debug->mark( 'checking options' ); // Begin timer.
420 + }
421 +
422 + $defs = null; // Optimize and only get the defaults array when needed.
423 + $fixed = array();
424 + $save_changes = false;
425 + $is_plugin_upg = $this->is_plugin_upgrading( $opts ); // Existing plugin versions have changed.
426 + $is_option_upg = $this->is_upgrade_required( $opts ); // Existing option versions have changed.
427 +
428 + /*
429 + * Upgrade the options array if necessary (rename or remove keys).
430 + */
431 + if ( $is_option_upg ) {
432 +
433 + if ( $this->p->debug->enabled ) {
434 +
435 + $this->p->debug->log( 'upgrading ' . $options_name . ' options' );
436 + }
437 +
438 + if ( ! is_object( $this->upgrade ) ) {
439 +
440 + require_once WPSSO_PLUGINDIR . 'lib/upgrade.php';
441 +
442 + $this->upgrade = new WpssoUpgrade( $this->p );
443 + }
444 +
445 + $defs = $network ? $this->get_site_defaults() : $this->get_defaults();
446 +
447 + $opts = $this->upgrade->options( $options_name, $opts, $defs, $network );
448 + }
449 +
450 + /*
451 + * Complete the options array for any custom post types and/or custom taxonomies.
452 + */
453 + $this->add_custom_post_tax_options( $opts );
454 +
455 + /*
456 + * Note that generator meta tags are required for plugin support.
457 + *
458 + * If you disable the generator meta tags, requests for plugin support will be denied.
459 + */
460 + $fixed[ 'add_meta_name_generator' ] = SucomUtil::get_const( 'WPSSO_META_GENERATOR_DISABLE' ) ? 0 : 1;
461 +
462 + /*
463 + * Google does not recognize all Schema Organization sub-types as valid organization and publisher types.
464 + * The site organization type ID should be "organization" unless you are confident that Google will
465 + * recognize your preferred Schema Organization sub-type as a valid organization. To select a different
466 + * organization type ID for your site, define the WPSSO_SCHEMA_ORGANIZATION_TYPE_ID constant with your
467 + * preferred type ID (not the Schema type URL).
468 + */
469 + $site_org_type_id = SucomUtil::get_const( 'WPSSO_SCHEMA_ORGANIZATION_TYPE_ID', 'organization' );
470 +
471 + if ( ! preg_match( '/^[a-z\.]+$/', $site_org_type_id ) ) { // Quick sanitation to allow only valid IDs.
472 +
473 + $site_org_type_id = 'organization';
474 + }
475 +
476 + $fixed[ 'site_org_schema_type' ] = $site_org_type_id;
477 +
478 + /*
479 + * Include VAT in Product Prices.
480 + *
481 + * Allow the WPSSO_PRODUCT_PRICE_INCLUDE_VAT constant to override the 'plugin_product_include_vat' value.
482 + */
483 + if ( defined( 'WPSSO_PRODUCT_PRICE_INCLUDE_VAT' ) ) {
484 +
485 + $fixed[ 'plugin_product_include_vat' ] = WPSSO_PRODUCT_PRICE_INCLUDE_VAT ? 1 : 0;
486 + }
487 +
488 + /*
489 + * Adjust / cleanup non-network options.
490 + */
491 + if ( ! $network ) {
492 +
493 + /*
494 + * Adjust SEO options.
495 + */
496 + if ( empty( $this->p->avail[ 'seo' ][ 'any' ] ) ) { // No SEO plugin active.
497 +
498 + if ( empty( $opts[ 'plugin_wpsso_tid' ] ) ) {
499 +
500 + $fixed[ 'add_link_rel_canonical' ] = 1;
501 + $fixed[ 'add_meta_name_description' ] = 1;
502 + $fixed[ 'add_meta_name_robots' ] = 1;
503 + $fixed[ 'plugin_title_tag' ] = 'seo_title';
504 + }
505 +
506 + } else { // An SEO plugin is active.
507 +
508 + $fixed[ 'add_link_rel_canonical' ] = 0;
509 + $fixed[ 'add_meta_name_description' ] = 0;
510 + $fixed[ 'add_meta_name_robots' ] = 0;
511 + $fixed[ 'plugin_title_tag' ] = 'wp_title';
512 +
513 + foreach ( array(
514 + 'aioseop', // All in One SEO Pack.
515 + 'rankmath', // Rank Math SEO.
516 + 'seoframework', // The SEO Framework.
517 + 'wpseo', // Yoast SEO.
518 + ) as $avail_key ) {
519 +
520 + /*
521 + * Disable the metadata import of all others (ie. non-active SEO plugins).
522 + */
523 + if ( empty( $this->p->avail[ 'seo' ][ $avail_key ] ) ) {
524 +
525 + foreach ( array( 'meta', 'blocks' ) as $import_type ) {
526 +
527 + $key = 'plugin_import_' . $avail_key . '_' . $import_type;
528 +
529 + if ( isset( $opts[ $key ] ) ) { // Make sure the option exists.
530 +
531 + $fixed[ $key ] = 0;
532 + }
533 + }
534 + }
535 + }
536 + }
537 +
538 + /*
539 + * Fixed value / unchangeable options.
540 + */
541 + foreach ( array( 'og:image', 'og:video' ) as $mt_name ) {
542 +
543 + $fixed[ 'add_meta_property_' . $mt_name . ':secure_url' ] = 0; // Always unchecked.
544 + $fixed[ 'add_meta_property_' . $mt_name . ':url' ] = 0; // Always unchecked.
545 + $fixed[ 'add_meta_property_' . $mt_name ] = 1; // Always checked (canonical URL).
546 + }
547 +
548 + /*
549 + * Check for website verification IDs and enable/disable meta tags as required.
550 + */
551 + foreach ( WpssoConfig::$cf[ 'opt' ][ 'site_verify_meta_names' ] as $site_verify => $meta_name ) {
552 +
553 + $fixed[ 'add_meta_name_' . $meta_name ] = empty( $opts[ $site_verify ] ) ? 0 : 1;
554 + }
555 +
556 + /*
557 + * Check for invalid update transaction status.
558 + */
559 + if ( class_exists( 'WpssoUmConfig' ) ) {
560 +
561 + foreach ( $this->p->cf[ 'plugin' ] as $ext => $info ) {
562 +
563 + $ext_auth_type = $this->p->check->get_ext_auth_type( $ext );
564 + $ext_auth_key = 'plugin_' . $ext . '_' . $ext_auth_type; // Options key for authentication ID.
565 + $ext_filter_key = 'update_filter_for_' . $ext; // Options key for version filter.
566 +
567 + if ( ! empty( $opts[ $ext_auth_key ] ) ) {
568 +
569 + if ( $txn_status = SucomUpdate::get_option( $ext, 'txn_status' ) ) {
570 +
571 + switch ( $txn_status ) {
572 +
573 + case 'Completed':
574 + case 'Updates':
575 +
576 + break; // Nothing to do.
577 +
578 + default: // Invalid status.
579 +
580 + $opts[ $ext_auth_key ] = '';
581 + $opts[ $ext_filter_key ] = 'stable';
582 +
583 + $save_changes = true; // Save the options.
584 +
585 + break;
586 + }
587 + }
588 + }
589 + }
590 + }
591 +
592 + /*
593 + * Check for incompatible option values between plugin editions.
594 + */
595 + if ( empty( $opts[ 'plugin_wpsso_tid' ] ) ) {
596 +
597 + if ( null === $defs ) { // Optimize and only get the defaults array when needed.
598 +
599 + $defs = $network ? $this->get_site_defaults() : $this->get_defaults();
600 + }
601 +
602 + $adv_incl = array(
603 + 'add_.*',
604 + 'og_type_for_.*',
605 + 'og_vid_.*',
606 + 'plugin_.*',
607 + 'schema_def_.*',
608 + 'schema_type_for_.*',
609 + '.*_img_(width|height|crop|crop_x|crop_y)',
610 + );
611 +
612 + $adv_excl = apply_filters( 'wpsso_plugin_upgrade_advanced_exclude', array(
613 + 'plugin_clean_on_uninstall',
614 + 'plugin_schema_json_min',
615 + 'plugin_load_mofiles',
616 + 'plugin_cache_disable',
617 + 'plugin_debug_html',
618 + 'plugin_.*_tid',
619 + ) );
620 +
621 + $adv_check = SucomUtil::preg_grep_keys( '/^(' . implode( '|', $adv_incl ) . ')$/', $defs );
622 + $adv_check = SucomUtil::preg_grep_keys( '/^(' . implode( '|', $adv_excl ) . ')$/', $adv_check, $invert = true );
623 +
624 + foreach ( $fixed as $key => $val ) {
625 +
626 + unset( $adv_check[ $key ] );
627 + }
628 +
629 + foreach ( $adv_check as $key => $val ) {
630 +
631 + if ( ! isset( $opts[ $key ] ) || $opts[ $key ] !== $val ) {
632 +
633 + $opts[ $key ] = $val;
634 +
635 + $save_changes = true; // Save the options.
636 + }
637 + }
638 + }
639 + }
640 +
641 + /*
642 + * Check if options need to be changed and saved.
643 + *
644 + * Disable these options as they would get changed back anyway.
645 + */
646 + foreach ( $fixed as $key => $val ) {
647 +
648 + $opts[ $key . ':disabled' ] = true;
649 +
650 + if ( ! isset( $opts[ $key ] ) || $opts[ $key ] !== $val ) { // Check for changes.
651 +
652 + $opts[ $key ] = $val; // Update the option value.
653 +
654 + $save_changes = true; // Save the options.
655 + }
656 + }
657 +
658 + /*
659 + * Save options and show reminders.
660 + */
661 + if ( $save_changes || $is_plugin_upg || $is_option_upg ) {
662 +
663 + $this->save_options( $options_name, $opts, $network );
664 + }
665 +
666 + if ( $this->p->debug->enabled ) {
667 +
668 + $this->p->debug->mark( 'checking options' ); // End timer.
669 + }
670 +
671 + return $opts;
672 + }
673 +
674 + /*
675 + * Sanitize and validate options, including both the plugin options and custom meta options arrays.
676 + *
677 + * Called by WpssoAdmin->settings_sanitation().
678 + * Called by WpssoAdmin->save_site_settings().
679 + * Called by WpssoAbstractWpMeta->get_submit_opts().
680 + */
681 + public function sanitize( array $opts, $defs = array(), $network = false, $mod = false ) {
682 +
683 + if ( $this->p->debug->enabled ) {
684 +
685 + $this->p->debug->mark();
686 + }
687 +
688 + /*
689 + * Add any missing options from the defaults, unless sanitizing for a module, in which case we do not
690 + * complete the options array.
691 + */
692 + if ( empty( $mod[ 'name' ] ) ) {
693 +
694 + if ( ! empty( $defs ) && is_array( $defs ) ) { // Just in case.
695 +
696 + $opts = array_merge( $defs, $opts ); // Complete the array with default options.
697 + }
698 + }
699 +
700 + /*
701 + * Sort the options to re-order 0, 1, 10, 2 suffixes as 0, 1, 2, 10.
702 + */
703 + ksort( $opts, SORT_FLAG_CASE | SORT_NATURAL );
704 +
705 + /*
706 + * Sanitize values.
707 + */
708 + unset( $opts[ 'opt_filtered' ] ); // Just in case.
709 +
710 + foreach ( $opts as $opt_key => $opt_val ) {
711 +
712 + if ( empty( $opt_key ) ) { // Just in case.
713 +
714 + continue;
715 +
716 + /*
717 + * Maybe save the disabled option, but don't save the ':disabled' qualifier.
718 + */
719 + } elseif ( false !== strpos( $opt_key, ':disabled' ) ) {
720 +
721 + unset( $opts[ $opt_key ] );
722 +
723 + continue;
724 +
725 + /*
726 + * Ignore all other controller qualifiers (ie. ':use', ':width', ':height', etc.).
727 + */
728 + } elseif ( strpos( $opt_key, ':' ) ) {
729 +
730 + continue;
731 +
732 + /*
733 + * Ignore localized options with an empty string value and no default.
734 + */
735 + } elseif ( strpos( $opt_key, '#' ) && ! isset( $defs[ $opt_key ] ) && '' === $opt_val ) {
736 +
737 + unset( $opts[ $opt_key ] );
738 +
739 + continue;
740 + }
741 +
742 + /*
743 + * Match the base option name without option numbers and localization.
744 + */
745 + $base_key = preg_replace( '/(_[0-9]+)?([#].*)?$/', '', $opt_key );
746 +
747 + /*
748 + * Multi-options and localized options default to an empty string.
749 + */
750 + $def_val = isset( $defs[ $opt_key ] ) ? $defs[ $opt_key ] : '';
751 +
752 + $opts[ $opt_key ] = $this->check_value( $opt_key, $base_key, $opt_val, $def_val, $network, $mod );
753 + }
754 +
755 + /*
756 + * Adjust Dependent Options
757 + *
758 + * All options (site and meta as well) are sanitized here, so always use isset() or array_key_exists() on
759 + * all tests to make sure additional / unnecessary options are not created in post meta.
760 + */
761 + $opt_prefixes = SucomUtil::preg_grep_keys( '/^(.*)_img_width$/', $opts, $invert = false, $replace = '$1' );
762 +
763 + foreach ( $opt_prefixes as $opt_pre => $img_width ) {
764 +
765 + if ( ! isset( $opts[ $opt_pre . '_img_height' ] ) ) { // Just in case;
766 +
767 + continue;
768 + }
769 +
770 + $img_height = $opts[ $opt_pre . '_img_height' ];
771 + $img_crop = isset( $opts[ $opt_pre . '_img_crop' ] ) ? $opts[ $opt_pre . '_img_crop' ] : 0;
772 +
773 + /*
774 + * If sanitizing for a module, load any missing width / height values.
775 + */
776 + if ( false !== $mod ) {
777 +
778 + if ( empty( $img_width ) && isset( $this->p->options[ $opt_pre . '_img_width' ] ) ) {
779 +
780 + $img_width = $this->p->options[ $opt_pre . '_img_width' ];
781 + }
782 +
783 + if ( empty( $img_height ) && isset( $this->p->options[ $opt_pre . '_img_height' ] ) ) {
784 +
785 + $img_height = $this->p->options[ $opt_pre . '_img_height' ];
786 + }
787 + }
788 +
789 + /*
790 + * Both width and height are required to calculate and check the aspect ratio.
791 + */
792 + if ( empty( $img_width ) || empty( $img_height ) ) {
793 +
794 + continue;
795 + }
796 +
797 + $img_ratio = $img_width >= $img_height ? $img_width / $img_height : $img_height / $img_width;
798 + $img_ratio = number_format( $img_ratio, 3, '.', '' );
799 +
800 + foreach ( array( 'limit', 'limit_max' ) as $limit_type ) {
801 +
802 + if ( ! isset( $this->p->cf[ 'head' ][ $limit_type ][ $opt_pre . '_img_ratio' ] ) ) {
803 +
804 + continue;
805 + }
806 +
807 + $notice_msg = false;
808 + $limit_ratio = number_format( $this->p->cf[ 'head' ][ $limit_type ][ $opt_pre . '_img_ratio' ], 3, '.', '' );
809 +
810 + switch ( $limit_type ) {
811 +
812 + case 'limit':
813 +
814 + $opts[ $opt_pre . '_img_crop' ] = 1;
815 + $opts[ $opt_pre . '_img_crop:disabled' ] = true; // Prevent changes in settings page.
816 +
817 + if ( $img_ratio !== $limit_ratio ) {
818 +
819 + $notice_msg = sprintf( __( 'Option keys "%1$s" (%2$d) and "%3$s" (%4$d) have an aspect ratio of %5$s:1, which not equal to the required image ratio of %6$s:1.', 'wpsso' ), $opt_pre . '_img_width', $img_width, $opt_pre . '_img_height', $img_height, $img_ratio, $limit_ratio );
820 + }
821 +
822 + break;
823 +
824 + case 'limit_max':
825 +
826 + if ( $img_crop && $img_ratio >= $limit_ratio ) {
827 +
828 + $notice_msg = sprintf( __( 'Option keys "%1$s" (%2$d) and "%3$s" (%4$d) have an aspect ratio of %5$s:1, which is equal to / or greater than the maximum image ratio of %6$s:1.', 'wpsso' ), $opt_pre . '_img_width', $img_width, $opt_pre . '_img_height', $img_height, $img_ratio, $limit_ratio );
829 + }
830 +
831 + break;
832 + }
833 +
834 + if ( $notice_msg ) {
835 +
836 + $notice_msg .= ' ' . __( 'These options have been reset to their default values.', 'wpsso' );
837 +
838 + $this->p->notice->err( $notice_msg );
839 +
840 + $opts[ $opt_pre . '_img_width' ] = $defs[ $opt_pre . '_img_width' ];
841 + $opts[ $opt_pre . '_img_height' ] = $defs[ $opt_pre . '_img_height' ];
842 + $opts[ $opt_pre . '_img_crop' ] = $defs[ $opt_pre . '_img_crop' ];
843 + }
844 + }
845 + }
846 +
847 + if ( false === $mod ) {
848 +
849 + /*
850 + * Check the Facebook App ID value.
851 + */
852 + if ( ! empty( $opts[ 'fb_app_id' ] ) && ( ! is_numeric( $opts[ 'fb_app_id' ] ) || strlen( $opts[ 'fb_app_id' ] ) > 32 ) ) {
853 +
854 + $this->p->notice->err( sprintf( __( 'The Facebook App ID must be numeric and 32 characters or less in length - the value of "%s" is not valid.', 'wpsso' ), $opts[ 'fb_app_id' ] ) );
855 + }
856 +
857 + /*
858 + * If the plugin_check_head option is disabled, then delete the check counter.
859 + */
860 + if ( ! $network ) {
861 +
862 + if ( empty( $this->p->options[ 'plugin_check_head' ] ) ) {
863 +
864 + delete_option( WPSSO_POST_CHECK_COUNT_NAME );
865 + }
866 + }
867 + }
868 +
869 + /*
870 + * Skip refreshing the image URL dimensions if saving network options.
871 + */
872 + if ( ! $network ) {
873 +
874 + $this->refresh_image_url_sizes( $opts ); // $opts passed by reference.
875 +
876 + if ( empty( $mod[ 'name' ] ) ) { // Only check when saving the plugin settings.
877 +
878 + $this->check_site_org_image_sizes( $opts );
879 + }
880 + }
881 +
882 + /*
883 + * The options array should not contain any numeric keys.
884 + */
885 + SucomUtil::unset_numeric_keys( $opts );
886 +
887 + return $opts;
888 + }
889 +
890 + /*
891 + * Save both options and site options.
892 + *
893 + * Called by WpssoAdmin->load_settings_page() for the 'reload_default_image_sizes' action.
894 + * Called by WpssoAdmin->import_plugin_settings_json().
895 + */
896 + public function save_options( $options_name, array $opts, $network = false ) {
897 +
898 + if ( $this->p->debug->enabled ) {
899 +
900 + $this->p->debug->mark();
901 + }
902 +
903 + /*
904 + * Make sure we have something to work with.
905 + */
906 + if ( empty( $opts ) || ! is_array( $opts ) ) {
907 +
908 + if ( $this->p->debug->enabled ) {
909 +
910 + $this->p->debug->log( 'exiting early: options variable is empty and/or not array' );
911 + }
912 +
913 + return false;
914 + }
915 +
916 + $is_option_upg = $this->is_upgrade_required( $opts ); // Existing option versions have changed.
917 +
918 + /*
919 + * $opts is the new options to be saved. Wpsso->options and Wpsso->site_options are still the old options.
920 + *
921 + * $network is true if we're saving the multisite network settings.
922 + *
923 + * $is_option_upg is true when the options versions, not the plugin versions, have changed.
924 + *
925 + * Also applied by WpssoAdmin->settings_sanitation().
926 + * Also applied by WpssoAdmin->save_site_settings().
927 + *
928 + * See WpssoRrssbFiltersOptions->filter_save_settings_options().
929 + * See WpssoUmFiltersOptions->filter_save_settings_options().
930 + */
931 + if ( $this->p->debug->enabled ) {
932 +
933 + $this->p->debug->log( 'applying filters "wpsso_save_settings_options"' );
934 + }
935 +
936 + $opts = apply_filters( 'wpsso_save_settings_options', $opts, $network, $is_option_upg );
937 +
938 + /*
939 + * Add plugin and add-on versions (ie. 'checksum', 'opt_checksum', and 'opt_versions').
940 + */
941 + $this->p->opt->add_versions_checksum( $opts ); // $opts must be an array.
942 +
943 + /*
944 + * Don't save the disabled option status.
945 + *
946 + * Example: add_meta_name_robots:disabled = true
947 + */
948 + foreach ( preg_grep( '/:disabled$/', array_keys( $opts ) ) as $key ) {
949 +
950 + unset( $opts[ $key ] );
951 + }
952 +
953 + if ( $network && $saved = update_site_option( $options_name, $opts ) ) { // Auto-creates options with autoload no.
954 +
955 + $this->p->site_options = $opts; // Update the current plugin options array.
956 +
957 + } elseif ( $saved = update_option( $options_name, $opts ) ) { // Auto-creates options with autoload yes.
958 +
959 + $this->p->options = $opts; // Update the current plugin options array.
960 + }
961 +
962 + if ( $saved ) {
963 +
964 + if ( $is_option_upg ) {
965 +
966 + if ( $this->p->debug->enabled ) {
967 +
968 + $this->p->debug->log( $options_name . ' settings have been upgraded and saved' );
969 + }
970 +
971 + /*
972 + * Refresh the Schema types transient cache and the minimized notice stylesheet immediately.
973 + */
974 + $this->p->schema->refresh_schema_types();
975 +
976 + if ( is_admin() ) {
977 +
978 + $this->p->notice->refresh_notice_style();
979 +
980 + $user_id = get_current_user_id();
981 + $notice_msg = '<strong>' . __( 'Plugin settings have been upgraded and saved.', 'wpsso' ) . '</strong> ';
982 + $notice_key = 'settings-upgraded-and-saved';
983 +
984 + $this->p->notice->upd( $notice_msg, $user_id, $notice_key );
985 +
986 + /*
987 + * Schedule a cache refresh.
988 + */
989 + if ( $this->p->debug->enabled ) {
990 +
991 + $this->p->debug->log( 'scheduling cache refresh' );
992 + }
993 +
994 + $this->p->util->cache->schedule_refresh( $user_id );
995 + }
996 +
997 + } elseif ( $this->p->debug->enabled ) {
998 +
999 + $this->p->debug->log( $options_name . ' settings have been saved silently' );
1000 + }
1001 +
1002 + } elseif ( $this->p->debug->enabled ) {
1003 +
1004 + $this->p->debug->log( 'wordpress failed to save the ' . $options_name . ' settings' );
1005 + }
1006 +
1007 + return $saved;
1008 + }
1009 +
1010 + public function get_version( array $opts, $ext ) {
1011 +
1012 + if ( isset( $opts[ 'opt_versions' ][ $ext ] ) ) { // Check for current version key first.
1013 +
1014 + return (int) $opts[ 'opt_versions' ][ $ext ];
1015 +
1016 + } elseif ( isset( $opts[ 'plugin_' . $ext . '_opt_version' ] ) ) { // Deprecated options version key.
1017 +
1018 + return (int) $opts[ 'plugin_' . $ext . '_opt_version' ];
1019 + }
1020 +
1021 + return 0;
1022 + }
1023 +
1024 + /*
1025 + * Returns true or false.
1026 + */
1027 + public function set_version( array &$opts, $ext, $version = 0 ) {
1028 +
1029 + if ( $ext ) {
1030 +
1031 + if ( $version > 0 ) {
1032 +
1033 + if ( ! isset( $opts[ 'opt_versions' ] ) || ! is_array( $opts[ 'opt_versions' ] ) ) {
1034 +
1035 + $opts[ 'opt_versions' ] = array();
1036 + }
1037 +
1038 + $opts[ 'opt_versions' ][ $ext ] = $version;
1039 +
1040 + } else {
1041 +
1042 + unset( $opts[ 'opt_versions' ][ $ext ] );
1043 + }
1044 +
1045 + if ( isset( $opts[ 'plugin_' . $ext . '_opt_version' ] ) ) { // Deprecated options version key.
1046 +
1047 + unset( $opts[ 'plugin_' . $ext . '_opt_version' ] );
1048 + }
1049 +
1050 + return true;
1051 + }
1052 +
1053 + return false;
1054 + }
1055 +
1056 + /*
1057 + * Returns true or false.
1058 + */
1059 + public function is_new_options( array $opts ) {
1060 +
1061 + return empty( $opts[ 'opt_checksum' ] ) && empty( $opts[ 'options_version' ] ) ? true : false;
1062 + }
1063 +
1064 + /*
1065 + * Returns true or false, false for a new options array ('checksum' is an empty string by default).
1066 + */
1067 + public function is_plugin_upgrading( array $opts ) {
1068 +
1069 + $cf_checksum = md5( $this->p->cf[ '*' ][ 'version' ] );
1070 +
1071 + $prev_checksum = '';
1072 +
1073 + if ( isset( $opts[ 'checksum' ] ) ) { // Empty string by default.
1074 +
1075 + $prev_checksum = $opts[ 'checksum' ];
1076 + }
1077 +
1078 + return $prev_checksum && $prev_checksum !== $cf_checksum ? true : false;
1079 + }
1080 +
1081 + /*
1082 + * Returns true or false, false for a new options array ('opt_checksum' is an empty string by default).
1083 + */
1084 + public function is_upgrade_required( array $opts ) {
1085 +
1086 + $cf_checksum = md5( $this->p->cf[ 'opt' ][ 'version' ] );
1087 +
1088 + $prev_checksum = '';
1089 +
1090 + if ( isset( $opts[ 'opt_checksum' ] ) ) { // Empty string by default.
1091 +
1092 + $prev_checksum = $opts[ 'opt_checksum' ];
1093 +
1094 + } elseif ( isset( $opts[ 'options_version' ] ) ) { // Deprecated options checksum key.
1095 +
1096 + $prev_checksum = md5( $opts[ 'options_version' ] );
1097 + }
1098 +
1099 + return $prev_checksum && $prev_checksum !== $cf_checksum ? true : false;
1100 + }
1101 +
1102 + /*
1103 + * Add plugin and add-on versions (ie. 'checksum', 'opt_checksum', and 'opt_versions').
1104 + */
1105 + public function add_versions_checksum( array &$opts ) { // Pass by reference is OK.
1106 +
1107 + if ( isset( $opts[ 'options_version' ] ) ) { // Deprecated options checksum key.
1108 +
1109 + unset( $opts[ 'options_version' ] );
1110 + }
1111 +
1112 + $opts[ 'checksum' ] = md5( $this->p->cf[ '*' ][ 'version' ] );
1113 +
1114 + $opts[ 'opt_checksum' ] = md5( $this->p->cf[ 'opt' ][ 'version' ] );
1115 +
1116 + if ( ! isset( $opts[ 'opt_versions' ] ) || ! is_array( $opts[ 'opt_versions' ] ) ) {
1117 +
1118 + $opts[ 'opt_versions' ] = array();
1119 + }
1120 +
1121 + foreach ( $this->p->cf[ 'plugin' ] as $ext => $info ) {
1122 +
1123 + if ( isset( $opts[ 'plugin_' . $ext . '_opt_version' ] ) ) { // Deprecated options version key.
1124 +
1125 + unset( $opts[ 'plugin_' . $ext . '_opt_version' ] );
1126 + }
1127 +
1128 + if ( isset( $info[ 'opt_version' ] ) ) { // Just in case.
1129 +
1130 + $opts[ 'opt_versions' ][ $ext ] = $info[ 'opt_version' ];
1131 + }
1132 + }
1133 + }
1134 +
1135 + /*
1136 + * Since WPSSO Core v17.0.0.
1137 + *
1138 + * Remove plugin and add-on versions (ie. 'checksum', 'opt_checksum', and 'opt_versions').
1139 + */
1140 + public function remove_versions_checksum( array &$opts ) { // Pass by reference is OK.
1141 +
1142 + unset( $opts[ 'checksum' ] );
1143 +
1144 + unset( $opts[ 'opt_checksum' ] );
1145 +
1146 + unset( $opts[ 'opt_versions' ] );
1147 + }
1148 +
1149 + /*
1150 + * Complete the options array for any custom post types and/or custom taxonomies.
1151 + *
1152 + * This method should be called after themes and plugins have registered their custom post types and taxonomies.
1153 + *
1154 + * Called by WpssoOptions->get_defaults().
1155 + */
1156 + private function add_custom_post_tax_options( array &$opts ) { // Pass by reference is OK.
1157 +
1158 + if ( $this->p->debug->enabled ) {
1159 +
1160 + $this->p->debug->mark();
1161 + }
1162 +
1163 + $col_headers = WpssoAbstractWpMeta::get_column_headers();
1164 +
1165 + /*
1166 + * Add options using a key prefix array and post type names.
1167 + */
1168 + $opt_prefixes = array(
1169 + 'og_type_for' => 'article', // Advanced Settings > Document Types > Open Graph > Type by Post Type.
1170 + 'plugin_add_to' => 1, // Advanced Settings > Plugin Settings > Interface > Show Document SSO Metabox.
1171 + 'plugin_ratings_reviews_for' => 0, // Advanced Settings > Service APIs > Ratings and Reviews > Get Reviews for Post Type.
1172 + 'schema_type_for' => 'webpage', // Advanced Settings > Document Types > Schema > Type by Post Type.
1173 + );
1174 +
1175 + foreach ( $col_headers as $col_key => $col_header ) {
1176 +
1177 + $opt_prefix = 'plugin_' . $col_key . '_col';
1178 +
1179 + /*
1180 + * Show the Open Graph Image column for post types by default.
1181 + */
1182 + $def_val = 'og_img' === $col_key ? 1 : 0;
1183 +
1184 + $opt_prefixes[ $opt_prefix ] = $def_val;
1185 + }
1186 +
1187 + /*
1188 + * See WpssoBcFiltersOptions->filter_custom_post_type_options().
1189 + * See WpssoRarFiltersOptions->filter_custom_post_type_options().
1190 + * See WpssoWpsmFiltersOptions->filter_custom_post_type_options().
1191 + */
1192 + $opt_prefixes = apply_filters( 'wpsso_custom_post_type_options', $opt_prefixes );
1193 +
1194 + $this->p->util->add_post_type_names( $opts, $opt_prefixes );
1195 +
1196 + /*
1197 + * Add options using a key prefix array and post type archive names.
1198 + */
1199 + $opt_prefixes = array(
1200 + 'og_type_for_pta' => 'website', // Advanced Settings > Document Types > Open Graph > Type by Post Type Archive.
1201 + 'schema_type_for_pta' => 'item.list', // Advanced Settings > Document Types > Schema > Type by Post Type Archive.
1202 + );
1203 +
1204 + $opt_prefixes = apply_filters( 'wpsso_custom_post_type_archive_options', $opt_prefixes );
1205 +
1206 + $this->p->util->add_post_type_archive_names( $opts, $opt_prefixes );
1207 +
1208 + /*
1209 + * Add options using a key prefix array and term names.
1210 + */
1211 + $opt_prefixes = array(
1212 + 'og_type_for_tax' => 'website', // Advanced Settings > Document Types > Open Graph > Type by Taxonomy.
1213 + 'plugin_add_to_tax' => 1, // Advanced Settings > Plugin Settings > Interface > Show Document SSO Metabox.
1214 + 'schema_type_for_tax' => 'item.list', // Advanced Settings > Document Types > Schema > Type by Taxonomy.
1215 + );
1216 +
1217 + foreach ( $col_headers as $col_key => $col_header ) {
1218 +
1219 + $opt_prefix = 'plugin_' . $col_key . '_col_tax';
1220 +
1221 + /*
1222 + * Show the Open Graph Image and Description columns for taxonomies by default.
1223 + */
1224 + $def_val = 'og_img' === $col_key || 'og_desc' === $col_key ? 1 : 0;
1225 +
1226 + $opt_prefixes[ $opt_prefix ] = $def_val;
1227 + }
1228 +
1229 + /*
1230 + * See WpssoBcFiltersOptions->filter_custom_taxonomy_options().
1231 + * See WpssoRarFiltersOptions->filter_custom_taxonomy_options().
1232 + * See WpssoWpsmFiltersOptions->filter_custom_taxonomy_options().
1233 + */
1234 + $opt_prefixes = apply_filters( 'wpsso_custom_taxonomy_options', $opt_prefixes );
1235 +
1236 + $this->p->util->add_taxonomy_names( $opts, $opt_prefixes );
1237 + }
1238 +
1239 + /*
1240 + * Update the width / height of remote image URLs.
1241 + */
1242 + private function refresh_image_url_sizes( array &$opts ) { // Pass by reference is OK.
1243 +
1244 + if ( $this->p->debug->enabled ) {
1245 +
1246 + $this->p->debug->mark();
1247 + }
1248 +
1249 + /*
1250 + * Remove custom field names to exclude 'plugin_cf_img_url' and 'plugin_cf_vid_url'.
1251 + */
1252 + $img_url_keys = preg_grep( '/^plugin_cf_/', array_keys( $opts ), PREG_GREP_INVERT );
1253 +
1254 + /*
1255 + * Allow for multi-option keys, like 'place_img_url_1'.
1256 + */
1257 + $img_url_keys = preg_grep( '/_(img|logo|banner)_url(_[0-9]+)?(#[a-zA-Z_]+)?$/', $img_url_keys );
1258 +
1259 + /*
1260 + * Add correct image sizes for the image URL using getimagesize().
1261 + *
1262 + * Note that PHP v7.1 or better is required to get the image size of WebP images.
1263 + */
1264 + $this->p->util->add_image_url_size( $opts, $img_url_keys );
1265 + }
1266 +
1267 + private function check_site_org_image_sizes( array $opts ) {
1268 +
1269 + /*
1270 + * Skip if notices have already been shown.
1271 + */
1272 + if ( ! $this->p->notice->is_admin_pre_notices() ) {
1273 +
1274 + return;
1275 + }
1276 +
1277 + /*
1278 + * Skip if the "Site Publisher Type" option is not an organization.
1279 + */
1280 + if ( empty( $opts[ 'site_pub_schema_type' ] ) || 'organization' !== $opts[ 'site_pub_schema_type' ] ) {
1281 +
1282 + return;
1283 + }
1284 +
1285 + /*
1286 + * Returns an image array:
1287 + *
1288 + * array(
1289 + * 'og:image:url' => null,
1290 + * 'og:image:width' => null,
1291 + * 'og:image:height' => null,
1292 + * 'og:image:cropped' => null,
1293 + * 'og:image:id' => null,
1294 + * 'og:image:alt' => null,
1295 + * 'og:image:size_name' => null,
1296 + * );
1297 + */
1298 + foreach ( array ( 'site_org_logo', 'site_org_banner' ) as $img_prefix ) {
1299 +
1300 + $mt_single_image = $this->p->media->get_mt_img_pre_url( $opts, $img_prefix );
1301 + $first_image_url = SucomUtil::get_first_mt_media_url( $mt_single_image );
1302 +
1303 + if ( 'site_org_logo' === $img_prefix ) {
1304 +
1305 + $option_label = _x( 'Organization Logo URL', 'option label', 'wpsso' );
1306 + $option_link = $this->p->util->get_admin_url( 'essential', $option_label );
1307 +
1308 + } elseif ( 'site_org_banner' === $img_prefix ) {
1309 +
1310 + $option_label = _x( 'Organization Banner URL', 'option label', 'wpsso' );
1311 + $option_link = $this->p->util->get_admin_url( 'essential', $option_label );
1312 + }
1313 +
1314 + if ( empty( $first_image_url ) ) {
1315 +
1316 + // translators: %s is a link to the option label.
1317 + $notice_msg = sprintf( __( 'The %s image is missing and required.', 'wpsso' ), $option_link ) . ' ';
1318 +
1319 + $this->p->notice->err( $notice_msg );
1320 +
1321 + } else {
1322 +
1323 + $image_href = '<a href="' . $first_image_url . '">' . $first_image_url . '</a>';
1324 + $image_width = $mt_single_image[ 'og:image:width' ];
1325 + $image_height = $mt_single_image[ 'og:image:height' ];
1326 + $image_dims = $image_width . 'x' . $image_height . 'px';
1327 + $notice_key = 'invalid-image-dimensions-' . $image_dims . '-' . $first_image_url;
1328 +
1329 + if ( '-1x-1px' === $image_dims ) {
1330 +
1331 + // translators: %s is a link to the option label.
1332 + $notice_msg = sprintf( __( 'The %s image dimensions cannot be determined.', 'wpsso' ), $option_link ) . ' ';
1333 +
1334 + // translators: %s is the image URL.
1335 + $notice_msg .= sprintf( __( 'Please make sure this site can access %s using the PHP getimagesize() function.',
1336 + 'wpsso' ), $image_href );
1337 +
1338 + $this->p->notice->err( $notice_msg, null, $notice_key );
1339 +
1340 + } elseif ( 'site_org_logo' === $img_prefix ) {
1341 +
1342 + $min_width = $this->p->cf[ 'head' ][ 'limit_min' ][ 'org_logo_width' ];
1343 + $min_height = $this->p->cf[ 'head' ][ 'limit_min' ][ 'org_logo_height' ];
1344 + $minimum_dims = $min_width . 'x' . $min_height . 'px';
1345 +
1346 + if ( $image_width < $min_width || $image_height < $min_height ) {
1347 +
1348 + // translators: %1$s is a link to the option label.
1349 + $notice_msg = sprintf( __( 'The %1$s image dimensions are %2$s and must be greater than %3$s.',
1350 + 'wpsso' ), $option_link, $image_dims, $minimum_dims ) . ' ';
1351 +
1352 + // translators: %s is the image URL.
1353 + $notice_msg .= sprintf( __( 'Please correct the %s logo image or select a different logo image.',
1354 + 'wpsso' ), $image_href );
1355 +
1356 + $this->p->notice->err( $notice_msg, null, $notice_key );
1357 + }
1358 +
1359 + } elseif ( 'site_org_banner' === $img_prefix ) {
1360 +
1361 + $min_width = $this->p->cf[ 'head' ][ 'limit' ][ 'org_banner_width' ];
1362 + $min_height = $this->p->cf[ 'head' ][ 'limit' ][ 'org_banner_height' ];
1363 + $required_dims = $min_width . 'x' . $min_height . 'px';
1364 +
1365 + if ( $image_dims !== $required_dims ) {
1366 +
1367 + // translators: %1$s is a link to the option label.
1368 + $notice_msg = sprintf( __( 'The %1$s image dimensions are %2$s and must be exactly %3$s.',
1369 + 'wpsso' ), $option_link, $image_dims, $required_dims ) . ' ';
1370 +
1371 + // translators: %s is the image URL.
1372 + $notice_msg .= sprintf( __( 'Please correct the %s banner image or select a different banner image.',
1373 + 'wpsso' ), $image_href );
1374 +
1375 + $this->p->notice->err( $notice_msg, null, $notice_key );
1376 + }
1377 + }
1378 + }
1379 + }
1380 + }
1381 +
1382 + private function check_value( $opt_key, $base_key, $opt_val, $def_val, $network, $mod ) {
1383 +
1384 + if ( is_array( $opt_val ) ) { // Just in case.
1385 +
1386 + return $opt_val;
1387 + }
1388 +
1389 + /*
1390 + * Translate error messages only once.
1391 + */
1392 + static $errors_transl = null;
1393 +
1394 + if ( null === $errors_transl ) {
1395 +
1396 + $errors_transl = array(
1397 + 'array' => __( 'The value of option "%s" must be an array - resetting this option to its default value.', 'wpsso' ),
1398 + 'api_key' => __( 'The value of option "%s" must be alpha-numeric - resetting this option to its default value.', 'wpsso' ),
1399 + 'blank_num' => __( 'The value of option "%s" must be blank or numeric - resetting this option to its default value.', 'wpsso' ),
1400 + 'color' => __( 'The value of option "%s" must be a CSS color code - resetting this option to its default value.', 'wpsso' ),
1401 + 'csv_urls' => __( 'The value of option "%s" must be a comma-delimited list of URL(s) - resetting this option to its default value.', 'wpsso' ),
1402 + 'date' => __( 'The value of option "%s" must be a yyyy-mm-dd date - resetting this option to its default value.', 'wpsso' ),
1403 + 'html' => __( 'The value of option "%s" must be HTML code - resetting this option to its default value.', 'wpsso' ),
1404 + 'img_id' => __( 'The value of option "%s" must be an image ID - resetting this option to its default value.', 'wpsso' ),
1405 + 'img_url' => __( 'The value of option "%s" must be a valid image URL - resetting this option to its default value.', 'wpsso' ),
1406 + 'not_blank' => __( 'The value of option "%s" cannot be an empty string - resetting this option to its default value.', 'wpsso' ),
1407 + 'numeric' => __( 'The value of option "%s" must be numeric - resetting this option to its default value.', 'wpsso' ),
1408 + 'pos_num' => __( 'The value of option "%1$s" must be equal to or greater than %2$s - resetting this option to its default value.', 'wpsso' ),
1409 + 'pos_num_gt' => __( 'The value of option "%1$s" must be greater than %2$s - resetting this option to its default value.', 'wpsso' ),
1410 + 'time' => __( 'The value of option "%s" must be a hh:mm time - resetting this option to its default value.', 'wpsso' ),
1411 + 'url' => __( 'The value of option "%s" must be a valid URL - resetting this option to its default value.', 'wpsso' ),
1412 + );
1413 + }
1414 +
1415 + /*
1416 + * Return the sanitation type for a given option key.
1417 + *
1418 + * Hooked by WpssoOptions->filter_option_type() and several add-ons.
1419 + */
1420 + $option_type = apply_filters( 'wpsso_option_type', $option_type = '', $base_key, $network, $mod );
1421 +
1422 + /*
1423 + * Apply a second more specific filter to customize the option type for a single base key.
1424 + */
1425 + $filter_name = SucomUtil::sanitize_hookname( 'wpsso_option_type_' . $base_key );
1426 +
1427 + $option_type = apply_filters( $filter_name, $option_type, $network, $mod );
1428 +
1429 + /*
1430 + * Pre-filter most values to remove html.
1431 + */
1432 + switch ( $option_type ) {
1433 +
1434 + case 'ignore':
1435 +
1436 + return $opt_val; // Stop here.
1437 +
1438 + break;
1439 +
1440 + case 'html': // Leave html, css, and javascript code blocks as-is.
1441 + case 'code': // Code values cannot be blank.
1442 + case 'preg': // A regular expression.
1443 +
1444 + $opt_val = preg_replace( '/[\r]+/', '', $opt_val );
1445 +
1446 + break;
1447 +
1448 + default:
1449 +
1450 + $opt_val = wp_filter_nohtml_kses( $opt_val ); // Strips all the HTML in the content.
1451 +
1452 + $opt_val = stripslashes( $opt_val ); // Strip slashes added by wp_filter_nohtml_kses().
1453 +
1454 + break;
1455 + }
1456 +
1457 + /*
1458 + * Optional cast on return.
1459 + */
1460 + $ret_int = null;
1461 + $ret_fnum = null;
1462 + $limit_min = null;
1463 + $fnum_prec = null; // Floating point number precision.
1464 +
1465 + if ( false !== ( $pos = strpos( $option_type, 'fnum' ) ) ) {
1466 +
1467 + $fnum_prec = substr( $option_type, $pos + 4 );
1468 + $option_type = substr( $option_type, 0, $pos + 4 );
1469 +
1470 + if ( ! is_numeric( $fnum_prec ) ) $fnum_prec = 1; // Just in case.
1471 + }
1472 +
1473 + switch ( $option_type ) {
1474 +
1475 + case 'array':
1476 +
1477 + if ( ! is_array( $opt_val ) ) {
1478 +
1479 + $this->p->notice->err( sprintf( $errors_transl[ 'array' ], $opt_key ) );
1480 +
1481 + $opt_val = is_array( $def_val ) ? $def_val : array();
1482 + }
1483 +
1484 + break;
1485 +
1486 + /*
1487 + * Empty or alpha-numeric (upper or lower case), plus underscores and hypens.
1488 + */
1489 + case 'api_key':
1490 +
1491 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1492 +
1493 + if ( '' !== $opt_val && preg_match( '/[^a-zA-Z0-9_\-]/', $opt_val ) ) {
1494 +
1495 + $this->p->notice->err( sprintf( $errors_transl[ 'api_key' ], $opt_key ) );
1496 +
1497 + $opt_val = $def_val;
1498 + }
1499 +
1500 + break;
1501 +
1502 + /*
1503 + * X (Twitter) usernames (prepend with an @ character).
1504 + */
1505 + case 'at_name':
1506 +
1507 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1508 +
1509 + if ( '' !== $opt_val ) {
1510 +
1511 + $opt_val = SucomUtil::sanitize_twitter_name( $opt_val, $add_at = true );
1512 + }
1513 +
1514 + break;
1515 +
1516 + /*
1517 + * Empty or alpha-numeric uppercase (hyphens are allowed as well). Silently convert illegal
1518 + * characters to single hyphens and trim excess.
1519 + */
1520 + case 'auth_id':
1521 +
1522 + $opt_val = trim( preg_replace( '/[^A-Z0-9\-]+/', '-', $opt_val ), '-' );
1523 + $opt_val = preg_replace( '/^ID-/', '', $opt_val ); // Just in case.
1524 +
1525 + break;
1526 +
1527 + case 'css_class':
1528 +
1529 + $opt_val = SucomUtil::sanitize_css_class( $opt_val );
1530 +
1531 + break;
1532 +
1533 + case 'css_id':
1534 +
1535 + $opt_val = SucomUtil::sanitize_css_id( $opt_val );
1536 +
1537 + break;
1538 +
1539 + case 'dashed':
1540 +
1541 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1542 + $opt_val = sanitize_title_with_dashes( $opt_val );
1543 +
1544 + break;
1545 +
1546 + /*
1547 + * Empty string or integer.
1548 + */
1549 + case 'blank_int':
1550 +
1551 + $ret_int = true;
1552 +
1553 + // No break.
1554 +
1555 + /*
1556 + * Empty string or numeric.
1557 + */
1558 + case 'blank_num':
1559 +
1560 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1561 +
1562 + if ( '' === $opt_val ) {
1563 +
1564 + $ret_int = false;
1565 +
1566 + } elseif ( ! is_numeric( $opt_val ) ) {
1567 +
1568 + $this->p->notice->err( sprintf( $errors_transl[ 'blank_num' ], $opt_key ) );
1569 +
1570 + $opt_val = $def_val;
1571 +
1572 + if ( '' === $opt_val ) $ret_int = false; // Default value is blank.
1573 + }
1574 +
1575 + break;
1576 +
1577 + /*
1578 + * Options that cannot be blank (aka empty string).
1579 + */
1580 + case 'code':
1581 + case 'not_blank':
1582 + case 'not_blank_quiet':
1583 +
1584 + if ( '' === $opt_val && '' !== $def_val ) {
1585 +
1586 + if ( false === strpos( $option_type, '_quiet' ) ) {
1587 +
1588 + $this->p->notice->err( sprintf( $errors_transl[ 'not_blank' ], $opt_key ) );
1589 + }
1590 +
1591 + $opt_val = $def_val;
1592 + }
1593 +
1594 + break;
1595 +
1596 + case 'csv_blank':
1597 +
1598 + if ( '' !== $opt_val ) {
1599 +
1600 + $opt_val = implode( $glue = ', ', SucomUtil::explode_csv( $opt_val ) );
1601 + }
1602 +
1603 + break;
1604 +
1605 + case 'csv_urls':
1606 +
1607 + if ( '' !== $opt_val ) {
1608 +
1609 + $parts = array();
1610 +
1611 + foreach ( SucomUtil::explode_csv( $opt_val ) as $part ) {
1612 +
1613 + $part = SucomUtil::decode_html( $part ); // Just in case.
1614 +
1615 + if ( false === filter_var( $part, FILTER_VALIDATE_URL ) ) {
1616 +
1617 + $this->p->notice->err( sprintf( $errors_transl[ 'csv_urls' ], $opt_key ) );
1618 +
1619 + $opt_val = $def_val;
1620 +
1621 + break;
1622 +
1623 + } else {
1624 +
1625 + $parts[] = $part;
1626 + }
1627 + }
1628 +
1629 + $opt_val = implode( $glue = ', ', $parts );
1630 + }
1631 +
1632 + break;
1633 +
1634 + /*
1635 + * Text strings that can be blank (line breaks are removed).
1636 + */
1637 + case 'desc':
1638 + case 'description':
1639 + case 'one_line':
1640 + case 'preg': // A regular expression.
1641 +
1642 + if ( '' !== $opt_val ) {
1643 +
1644 + $opt_val = trim( preg_replace( '/[\s\n\r]+/s', ' ', $opt_val ) );
1645 + }
1646 +
1647 + break;
1648 +
1649 + /*
1650 + * Floating-point number.
1651 + *
1652 + * The decimal precision is defined before the switch() statement.
1653 + */
1654 + case 'fnum':
1655 +
1656 + $ret_fnum = true;
1657 +
1658 + if ( ! is_numeric( $opt_val ) ) {
1659 +
1660 + $this->p->notice->err( sprintf( $errors_transl[ 'numeric' ], $opt_key ) );
1661 +
1662 + $opt_val = $def_val;
1663 + }
1664 +
1665 + break;
1666 +
1667 + /*
1668 + * Empty string or must include at least one HTML tag.
1669 + */
1670 + case 'html':
1671 +
1672 + if ( '' !== $opt_val ) {
1673 +
1674 + $opt_val = trim( $opt_val );
1675 +
1676 + if ( ! preg_match( '/<.*>/', $opt_val ) ) {
1677 +
1678 + $this->p->notice->err( sprintf( $errors_transl[ 'html' ], $opt_key ) );
1679 +
1680 + $opt_val = $def_val;
1681 + }
1682 + }
1683 +
1684 + break;
1685 +
1686 + /*
1687 + * Empty string or an image ID.
1688 + */
1689 + case 'img_id':
1690 +
1691 + if ( '' !== $opt_val ) {
1692 +
1693 + if ( ! preg_match( '/^[0-9]+$/', $opt_val ) ) {
1694 +
1695 + $this->p->notice->err( sprintf( $errors_transl[ 'img_id' ], $opt_key ) );
1696 +
1697 + $opt_val = $def_val;
1698 + }
1699 + }
1700 +
1701 + break;
1702 +
1703 + /*
1704 + * Integer.
1705 + */
1706 + case 'int':
1707 + case 'integer':
1708 +
1709 + $ret_int = true;
1710 +
1711 + // No break.
1712 +
1713 + /*
1714 + * Numeric.
1715 + */
1716 + case 'numeric':
1717 +
1718 + if ( ! is_numeric( $opt_val ) ) {
1719 +
1720 + $this->p->notice->err( sprintf( $errors_transl[ 'numeric' ], $opt_key ) );
1721 +
1722 + $opt_val = $def_val;
1723 +
1724 + if ( '' === $opt_val ) $ret_int = false; // Default value is blank.
1725 + }
1726 +
1727 + break;
1728 +
1729 + /*
1730 + * Integer options that must be 0 or more.
1731 + */
1732 + case 'zero_pos_int':
1733 +
1734 + $limit_min = 0;
1735 +
1736 + // No break.
1737 +
1738 + /*
1739 + * Integer options that must be 1 or more.
1740 + */
1741 + case 'img_height': // Image height, subject to minimum value (typically, at least 200px).
1742 + case 'img_width': // Image height, subject to minimum value (typically, at least 200px).
1743 + case 'pos_int':
1744 +
1745 + $ret_int = true;
1746 +
1747 + /*
1748 + * If $limit_min has not been defined above, check for a hard-coded minimum value (for
1749 + * example, 200 for "og_img_width").
1750 + */
1751 + if ( null === $limit_min ) {
1752 +
1753 + if ( isset( $this->p->cf[ 'head' ][ 'limit_min' ][ $base_key ] ) ) {
1754 +
1755 + $limit_min = $this->p->cf[ 'head' ][ 'limit_min' ][ $base_key ];
1756 +
1757 + } else $limit_min = 1;
1758 + }
1759 +
1760 + // No break.
1761 +
1762 + /*
1763 + * Zero or floating-point number.
1764 + *
1765 + * The decimal precision is defined before the switch() statement.
1766 + */
1767 + case 'zero_pos_fnum':
1768 +
1769 + if ( null === $limit_min ) {
1770 +
1771 + $limit_min = 0;
1772 + }
1773 +
1774 + // No break.
1775 +
1776 + /*
1777 + * Positive floating-point number.
1778 + *
1779 + * The decimal precision is defined before the switch() statement.
1780 + */
1781 + case 'pos_fnum':
1782 +
1783 + if ( null === $ret_int ) {
1784 +
1785 + $ret_fnum = true;
1786 + }
1787 +
1788 + // No break.
1789 +
1790 + /*
1791 + * Integer or numeric options that must be zero or larger than $limit_min.
1792 + */
1793 + case 'pos_num':
1794 +
1795 + if ( ! empty( $mod[ 'name' ] ) && '' === trim( $opt_val ) ) { // Custom meta options can be empty.
1796 +
1797 + $opt_val = '';
1798 +
1799 + } elseif ( null !== $limit_min ) {
1800 +
1801 + if ( $opt_val < $limit_min || ! is_numeric( $opt_val ) ) {
1802 +
1803 + $this->p->notice->err( sprintf( $errors_transl[ 'pos_num' ], $opt_key, $limit_min ) );
1804 +
1805 + $opt_val = $def_val;
1806 +
1807 + }
1808 +
1809 + } else { // $limit_min is null.
1810 +
1811 + if ( $opt_val <= 0 || ! is_numeric( $opt_val ) ) {
1812 +
1813 + $this->p->notice->err( sprintf( $errors_transl[ 'pos_num_gt' ], $opt_key, 0 ) );
1814 +
1815 + $opt_val = $def_val;
1816 + }
1817 + }
1818 +
1819 + if ( '' === $opt_val ) { // Default value is blank.
1820 +
1821 + $ret_int = false;
1822 + $ret_fnum = false;
1823 + }
1824 +
1825 + break;
1826 +
1827 + case 'color':
1828 + case 'date': // Empty or 'none' string, or date as yyyy-mm-dd.
1829 + case 'time': // Empty or 'none' string, or time as hh:mm or hh:mm:ss.
1830 +
1831 + $fmt = false;
1832 +
1833 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1834 +
1835 + if ( 'color' === $option_type ) {
1836 +
1837 + $fmt = '/^#[a-fA-f0-9]{6,6}$/'; // Color as #000000.
1838 +
1839 + } elseif ( 'date' === $option_type ) {
1840 +
1841 + $fmt = '/^[0-9]{4,4}-[0-9]{2,2}-[0-9]{2,2}$/'; // Date as yyyy-mm-dd.
1842 +
1843 + } elseif ( 'time' === $option_type ) {
1844 +
1845 + $fmt = '/^[0-9]{2,2}:[0-9]{2,2}(:[0-9]{2,2})?$/'; // Time as hh:mm or hh:mm:ss.
1846 + }
1847 +
1848 + if ( '' !== $opt_val && 'none' !== $opt_val && $fmt && ! preg_match( $fmt, $opt_val ) ) {
1849 +
1850 + $this->p->notice->err( sprintf( $errors_transl[ $option_type ], $opt_key ) );
1851 +
1852 + $opt_val = $def_val;
1853 + }
1854 +
1855 + break;
1856 +
1857 + /*
1858 + * Text strings that can be blank.
1859 + */
1860 + case 'ok_blank':
1861 +
1862 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1863 +
1864 + break;
1865 +
1866 + /*
1867 + * Empty or texturized string.
1868 + */
1869 + case 'textured':
1870 +
1871 + if ( '' !== $opt_val ) {
1872 +
1873 + $opt_val = trim( wptexturize( ' ' . $opt_val . ' ' ) );
1874 + }
1875 +
1876 + break;
1877 +
1878 + /*
1879 + * Empty string or a URL.
1880 + *
1881 + * Note that WebP is only supported since PHP v7.1.
1882 + */
1883 + case 'img_url':
1884 +
1885 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1886 +
1887 + if ( '' !== $opt_val ) {
1888 +
1889 + $opt_val = SucomUtil::decode_html( $opt_val ); // Just in case.
1890 +
1891 + if ( ! $this->p->util->is_image_url( $opt_val ) ) {
1892 +
1893 + $this->p->notice->err( sprintf( $errors_transl[ 'img_url' ], $opt_key ) );
1894 +
1895 + $opt_val = $def_val;
1896 + }
1897 + }
1898 +
1899 + case 'url':
1900 +
1901 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1902 +
1903 + if ( '' !== $opt_val ) {
1904 +
1905 + $opt_val = SucomUtil::decode_html( $opt_val ); // Just in case.
1906 +
1907 + if ( false === filter_var( $opt_val, FILTER_VALIDATE_URL ) ) {
1908 +
1909 + $this->p->notice->err( sprintf( $errors_transl[ 'url' ], $opt_key ) );
1910 +
1911 + $opt_val = $def_val;
1912 + }
1913 + }
1914 +
1915 + break;
1916 +
1917 + /*
1918 + * Strip leading URLs off facebook usernames.
1919 + */
1920 + case 'url_base':
1921 +
1922 + $opt_val = trim( $opt_val ); // Remove extra spaces from copy-paste.
1923 +
1924 + if ( '' !== $opt_val ) {
1925 +
1926 + $opt_val = preg_replace( '/(http|https):\/\/[^\/]*?\//', '', $opt_val );
1927 + }
1928 +
1929 + break;
1930 +
1931 + /*
1932 + * Everything else is a 1 or 0 checkbox option.
1933 + */
1934 + case 'checkbox':
1935 + default:
1936 +
1937 + if ( $def_val === 0 || $def_val === 1 ) { // Make sure the default option is also a 1 or 0, just in case.
1938 +
1939 + $opt_val = empty( $opt_val ) ? 0 : 1;
1940 + }
1941 +
1942 + break;
1943 + }
1944 +
1945 + if ( $ret_int ) {
1946 +
1947 + $opt_val = intval( $opt_val );
1948 +
1949 + } elseif ( $ret_fnum && null !== $fnum_prec ) {
1950 +
1951 + $opt_val = sprintf( '%.' . $fnum_prec . 'f', $opt_val );
1952 + }
1953 +
1954 + return $opt_val;
1955 + }
1956 +
1957 + public function set_default_text( array &$defs, $opt_key ) {
1958 +
1959 + if ( $opt_key && is_string( $opt_key ) ) { // Just in case.
1960 +
1961 + $text = $this->get_text( $opt_key, $use_opts = false );
1962 +
1963 + $opt_key_locale = SucomUtilOptions::get_key_locale( $opt_key, $defs, 'current' );
1964 +
1965 + $defs[ $opt_key_locale ] = $text;
1966 +
1967 + if ( ! isset( $this->p->options[ $opt_key_locale ] ) ) { // Just in case.
1968 +
1969 + $this->p->options[ $opt_key_locale ] = $text;
1970 + }
1971 + }
1972 + }
1973 +
1974 + /*
1975 + * Returns an option value or null.
1976 + *
1977 + * $mixed = 'default' | 'current' | post ID | $mod array
1978 + */
1979 + public function get_text( $opt_key, $use_opts = true, $mixed = 'current' ) {
1980 +
1981 + $text = null;
1982 +
1983 + if ( $use_opts && ! empty( $this->p->options ) ) {
1984 +
1985 + $text = SucomUtilOptions::get_key_value( $opt_key, $this->p->options, $mixed ); // Returns null if option key does not exist.
1986 + }
1987 +
1988 + if ( null === $text ) { // Fallback to default text from current locale.
1989 +
1990 + switch ( $opt_key ) {
1991 +
1992 + case 'plugin_title_part_site': // Title Tag Site Prefix / Suffix.
1993 +
1994 + return _x( '%%sitename%%', 'option value', 'wpsso' );
1995 +
1996 + case 'plugin_title_part_tagline': // Title Tag Tagline Prefix / Suffix.
1997 +
1998 + return _x( '%%sitedesc%%', 'option value', 'wpsso' );
1999 +
2000 + case 'plugin_img_alt_prefix': // Content Image Alt Prefix.
2001 +
2002 + return _x( 'Image:', 'option value', 'wpsso' );
2003 +
2004 + case 'plugin_p_cap_prefix': // WP Caption Text Prefix.
2005 +
2006 + return _x( 'Caption:', 'option value', 'wpsso' );
2007 +
2008 + case 'plugin_comment_title': // Comment Title.
2009 +
2010 + /*
2011 + * %%comment_date%% is formatted based on the WordPress Settings > General > Date Format value.
2012 + */
2013 + return _x( 'Comment by %%comment_author%% on %%comment_date%%', 'option value', 'wpsso' );
2014 +
2015 + case 'plugin_comment_reply_title': // Reply Comment Title.
2016 +
2017 + /*
2018 + * %%comment_date%% is formatted based on the WordPress Settings > General > Date Format value.
2019 + */
2020 + return _x( 'Reply by %%comment_author%% on %%comment_date%%', 'option value', 'wpsso' );
2021 +
2022 + case 'plugin_comment_review_title': // Review Comment Title.
2023 +
2024 + return _x( 'Review by %%comment_author%%', 'option value', 'wpsso' );
2025 +
2026 + case 'plugin_product_var_title': // Product Variation Title.
2027 +
2028 + return _x( '%%var_title%% %%sep%% %%var_attrs%%', 'option value', 'wpsso' );
2029 +
2030 + case 'plugin_feed_title': // RSS Feed Title.
2031 +
2032 + return _x( '%%sitename%%', 'option value', 'wpsso' );
2033 +
2034 + case 'plugin_404_page_title': // 404 Page Title.
2035 +
2036 + return _x( 'Page Not Found', 'option value', 'wpsso' );
2037 +
2038 + case 'plugin_404_page_desc': // 404 Page Description.
2039 +
2040 + return _x( 'Page "%%pagename%%" not found.', 'option value', 'wpsso' );
2041 +
2042 + case 'plugin_no_title_text': // No Title Text.
2043 +
2044 + return _x( 'No Title', 'option value', 'wpsso' );
2045 +
2046 + case 'plugin_no_desc_text': // No Description Text.
2047 +
2048 + return _x( 'No description.', 'option value', 'wpsso' );
2049 +
2050 + case 'plugin_term_page_title': // Term Archive Title.
2051 +
2052 + return _x( '%%term_hierarchy%%', 'option value', 'wpsso' );
2053 +
2054 + case 'plugin_term_page_desc': // Term Archive Description.
2055 +
2056 + return _x( '%%term_tax_single%% archive page for %%term_name%%.', 'option value', 'wpsso' );
2057 +
2058 + case 'plugin_author_page_title': // Author Archive Title.
2059 +
2060 + return _x( '%%author_name%%, Author at %%sitename%%', 'option value', 'wpsso' );
2061 +
2062 + case 'plugin_author_page_desc': // Author Archive Description.
2063 +
2064 + return _x( 'Author archive page for %%author_name%%.', 'option value', 'wpsso' );
2065 +
2066 + case 'plugin_search_page_title': // Search Results Title.
2067 +
2068 + return _x( 'Search Results %%sep%% %%query_search%%', 'option value', 'wpsso' );
2069 +
2070 + case 'plugin_search_page_desc': // Search Results Description.
2071 +
2072 + return _x( 'Search results for &#8220;%%query_search%%&#8221;.', 'option value', 'wpsso' );
2073 +
2074 + case 'plugin_year_page_title': // Year Archive Title.
2075 +
2076 + return _x( '%%query_year%%', 'option value', 'wpsso' );
2077 +
2078 + case 'plugin_year_page_desc': // Year Archive Description.
2079 +
2080 + return _x( 'Yearly archive for %%query_year%%.', 'option value', 'wpsso' );
2081 +
2082 + case 'plugin_month_page_title': // Month Archive Title.
2083 +
2084 + return _x( '%%query_month%% %%query_year%%', 'option value', 'wpsso' );
2085 +
2086 + case 'plugin_month_page_desc': // Month Archive Description.
2087 +
2088 + return _x( 'Monthly archive for %%query_month%%, %%query_year%%.', 'option value', 'wpsso' );
2089 +
2090 + case 'plugin_day_page_title': // Day Archive Title.
2091 +
2092 + return _x( '%%query_month%% %%query_day%%, %%query_year%%', 'option value', 'wpsso' );
2093 +
2094 + case 'plugin_day_page_desc': // Day Archive Description.
2095 +
2096 + return _x( 'Daily archive for %%query_month%% %%query_day%%, %%query_year%%.', 'option value', 'wpsso' );
2097 +
2098 + default:
2099 +
2100 + return apply_filters( 'wpsso_get_text_default_options_key', null, $opt_key );
2101 + }
2102 + }
2103 +
2104 + return $text;
2105 + }
2106 + }
2107 +}