/** * Clean a given option value * * @param array $option_value Old (not merged with defaults or filtered) option value to * clean according to the rules for this option. * @param string $current_version (optional) Version from which to upgrade, if not set, * version specific upgrades will be disregarded. * @param array $all_old_option_values (optional) Only used when importing old options to have * access to the real old values, in contrast to the saved ones. * * @return array Cleaned option */ protected function clean_option($option_value, $current_version = null, $all_old_option_values = null) { static $original = null; // Double-run this function to ensure renaming of the taxonomy options will work. if (!isset($original) && has_action('YMBESEO_double_clean_titles', array($this, 'clean')) === false) { add_action('YMBESEO_double_clean_titles', array($this, 'clean')); $original = $option_value; } /* Move options from very old option to this one @internal Don't rename to the 'current' names straight away as that would prevent the rename/unset combi below from working @todo [JRF] maybe figure out a smarter way to deal with this */ $old_option = null; if (isset($all_old_option_values)) { // Ok, we have an import. if (isset($all_old_option_values['YMBESEO_indexation']) && is_array($all_old_option_values['YMBESEO_indexation']) && $all_old_option_values['YMBESEO_indexation'] !== array()) { $old_option = $all_old_option_values['YMBESEO_indexation']; } } else { $old_option = get_option('YMBESEO_indexation'); } if (is_array($old_option) && $old_option !== array()) { $move = array('noindexauthor' => 'noindex-author', 'disableauthor' => 'disable-author', 'noindexdate' => 'noindex-archive', 'noindexcat' => 'noindex-category', 'noindextag' => 'noindex-post_tag', 'noindexpostformat' => 'noindex-post_format', 'noindexsubpages' => 'noindex-subpages', 'hidersdlink' => 'hide-rsdlink', 'hidefeedlinks' => 'hide-feedlinks', 'hidewlwmanifest' => 'hide-wlwmanifest', 'hideshortlink' => 'hide-shortlink'); foreach ($move as $old => $new) { if (isset($old_option[$old]) && !isset($option_value[$new])) { $option_value[$new] = $old_option[$old]; } } unset($move, $old, $new); } unset($old_option); // Fix wrongness created by buggy version 1.2.2. if (isset($option_value['title-home']) && $option_value['title-home'] === '%%sitename%% - %%sitedesc%% - 12345') { $option_value['title-home-wpseo'] = '%%sitename%% - %%sitedesc%%'; } /* Renaming these options to avoid ever overwritting these if a (bloody stupid) user / programmer would use any of the following as a custom post type or custom taxonomy: 'home', 'author', 'archive', 'search', '404', 'subpages' Similarly, renaming the tax options to avoid a custom post type and a taxonomy with the same name occupying the same option */ $rename = array('title-home' => 'title-home-wpseo', 'title-author' => 'title-author-wpseo', 'title-archive' => 'title-archive-wpseo', 'title-search' => 'title-search-wpseo', 'title-404' => 'title-404-wpseo', 'metadesc-home' => 'metadesc-home-wpseo', 'metadesc-author' => 'metadesc-author-wpseo', 'metadesc-archive' => 'metadesc-archive-wpseo', 'metakey-home' => 'metakey-home-wpseo', 'metakey-author' => 'metakey-author-wpseo', 'noindex-subpages' => 'noindex-subpages-wpseo', 'noindex-author' => 'noindex-author-wpseo', 'noindex-archive' => 'noindex-archive-wpseo'); foreach ($rename as $old => $new) { if (isset($option_value[$old]) && !isset($option_value[$new])) { $option_value[$new] = $option_value[$old]; unset($option_value[$old]); } } unset($rename, $old, $new); /** * @internal This clean-up action can only be done effectively once the taxonomies and post_types * have been registered, i.e. at the end of the init action. */ if (isset($original) && current_filter() === 'YMBESEO_double_clean_titles' || did_action('YMBESEO_double_clean_titles') > 0) { $rename = array('title-' => 'title-tax-', 'metadesc-' => 'metadesc-tax-', 'metakey-' => 'metakey-tax-', 'noindex-' => 'noindex-tax-', 'tax-hideeditbox-' => 'hideeditbox-tax-'); $taxonomy_names = get_taxonomies(array('public' => true), 'names'); $post_type_names = get_post_types(array('public' => true), 'names'); $defaults = $this->get_defaults(); if ($taxonomy_names !== array()) { foreach ($taxonomy_names as $tax) { foreach ($rename as $old_prefix => $new_prefix) { if (isset($original[$old_prefix . $tax]) && !isset($original[$new_prefix . $tax]) && (!isset($option_value[$new_prefix . $tax]) || isset($option_value[$new_prefix . $tax]) && $option_value[$new_prefix . $tax] === $defaults[$new_prefix . $tax])) { $option_value[$new_prefix . $tax] = $original[$old_prefix . $tax]; /* Check if there is a cpt with the same name as the tax, if so, we should make sure that the old setting hasn't been removed */ if (!isset($post_type_names[$tax]) && isset($option_value[$old_prefix . $tax])) { unset($option_value[$old_prefix . $tax]); } else { if (isset($post_type_names[$tax]) && !isset($option_value[$old_prefix . $tax])) { $option_value[$old_prefix . $tax] = $original[$old_prefix . $tax]; } } if ($old_prefix === 'tax-hideeditbox-') { unset($option_value[$old_prefix . $tax]); } } } } } unset($rename, $taxonomy_names, $post_type_names, $defaults, $tax, $old_prefix, $new_prefix); } /* Make sure the values of the variable option key options are cleaned as they may be retained and would not be cleaned/validated then */ if (is_array($option_value) && $option_value !== array()) { foreach ($option_value as $key => $value) { $switch_key = $this->get_switch_key($key); // Similar to validation routine - any changes made there should be made here too. switch ($switch_key) { /* text fields */ case 'title-': case 'metadesc-': case 'metakey-': case 'bctitle-ptarchive-': $option_value[$key] = YMBESEO_Utils::sanitize_text_field($value); break; case 'separator': if (!array_key_exists($value, $this->get_separator_options())) { $option_value[$key] = false; } break; /* Boolean fields */ /* Covers: * 'noindex-' * 'showdate-' * 'hideeditbox-' */ /* Boolean fields */ /* Covers: * 'noindex-' * 'showdate-' * 'hideeditbox-' */ default: $option_value[$key] = YMBESEO_Utils::validate_bool($value); break; } } unset($key, $value, $switch_key); } return $option_value; }
/** * Validate the option * * @param array $dirty New value for the option. * @param array $clean Clean value for the option, normally the defaults. * @param array $old Old value of the option. * * @return array Validated clean value for the option to be saved to the database */ protected function validate_option($dirty, $clean, $old) { foreach ($clean as $key => $value) { switch ($key) { case 'version': $clean[$key] = YMBESEO_VERSION; break; case 'blocking_files': /** * @internal [JRF] to really validate this we should also do a file_exists() * on each array entry and remove files which no longer exist, but that might be overkill */ if (isset($dirty[$key]) && is_array($dirty[$key])) { $clean[$key] = array_unique($dirty[$key]); } elseif (isset($old[$key]) && is_array($old[$key])) { $clean[$key] = array_unique($old[$key]); } break; case 'theme_description_found': if (isset($dirty[$key]) && is_string($dirty[$key])) { $clean[$key] = $dirty[$key]; // @todo [JRF/whomever] maybe do wp_kses ? } elseif (isset($old[$key]) && is_string($old[$key])) { $clean[$key] = $old[$key]; } break; case 'company_or_person': if (isset($dirty[$key]) && $dirty[$key] !== '') { if (in_array($dirty[$key], array('company', 'person'))) { $clean[$key] = $dirty[$key]; } } break; /* text fields */ /* text fields */ case 'company_name': case 'person_name': case 'website_name': case 'alternate_website_name': if (isset($dirty[$key]) && $dirty[$key] !== '') { $clean[$key] = sanitize_text_field($dirty[$key]); } break; case 'company_logo': $this->validate_url($key, $dirty, $old, $clean); break; /* verification strings */ /* verification strings */ case 'alexaverify': case 'googleverify': case 'msverify': case 'yandexverify': $this->validate_verification_string($key, $dirty, $old, $clean); break; /* boolean|null fields - if set a check was done, if null, it hasn't */ /* boolean|null fields - if set a check was done, if null, it hasn't */ case 'theme_has_description': if (isset($dirty[$key])) { $clean[$key] = YMBESEO_Utils::validate_bool($dirty[$key]); } elseif (isset($old[$key])) { $clean[$key] = YMBESEO_Utils::validate_bool($old[$key]); } break; /* Boolean dismiss warnings - not fields - may not be in form (and don't need to be either as long as the default is false) */ /* Boolean dismiss warnings - not fields - may not be in form (and don't need to be either as long as the default is false) */ case 'ignore_blog_public_warning': case 'ignore_meta_description_warning': case 'ignore_page_comments': case 'ignore_permalink': case 'ms_defaults_set': if (isset($dirty[$key])) { $clean[$key] = YMBESEO_Utils::validate_bool($dirty[$key]); } elseif (isset($old[$key])) { $clean[$key] = YMBESEO_Utils::validate_bool($old[$key]); } break; /* Boolean (checkbox) fields */ /* Covers * 'disableadvanced_meta' * 'yoast_tracking' */ /* Boolean (checkbox) fields */ /* Covers * 'disableadvanced_meta' * 'yoast_tracking' */ default: $clean[$key] = isset($dirty[$key]) ? YMBESEO_Utils::validate_bool($dirty[$key]) : false; break; } } return $clean; }
/** * Validate the option * * @param array $dirty New value for the option. * @param array $clean Clean value for the option, normally the defaults. * @param array $old Old value of the option. * * @return array Validated clean value for the option to be saved to the database */ protected function validate_option($dirty, $clean, $old) { foreach ($clean as $key => $value) { switch ($key) { case 'access': if (isset($dirty[$key]) && in_array($dirty[$key], self::$allowed_access_options, true)) { $clean[$key] = $dirty[$key]; } elseif (function_exists('add_settings_error')) { add_settings_error($this->group_name, '_' . $key, sprintf(__('%1$s is not a valid choice for who should be allowed access to the %2$s settings. Value reset to the default.', 'ymbeseo'), esc_html(sanitize_text_field($dirty[$key])), 'Yoast SEO'), 'error'); } break; case 'defaultblog': if (isset($dirty[$key]) && ($dirty[$key] !== '' && $dirty[$key] !== '-')) { $int = YMBESEO_Utils::validate_int($dirty[$key]); if ($int !== false && $int > 0) { // Check if a valid blog number has been received. $exists = get_blog_details($int, false); if ($exists && $exists->deleted == 0) { $clean[$key] = $int; } elseif (function_exists('add_settings_error')) { add_settings_error($this->group_name, '_' . $key, esc_html__('The default blog setting must be the numeric blog id of the blog you want to use as default.', 'ymbeseo') . '<br>' . sprintf(esc_html__('This must be an existing blog. Blog %s does not exist or has been marked as deleted.', 'ymbeseo'), '<strong>' . esc_html(sanitize_text_field($dirty[$key])) . '</strong>'), 'error'); } unset($exists); } elseif (function_exists('add_settings_error')) { add_settings_error($this->group_name, '_' . $key, esc_html__('The default blog setting must be the numeric blog id of the blog you want to use as default.', 'ymbeseo') . '<br>' . esc_html__('No numeric value was received.', 'ymbeseo'), 'error'); } unset($int); } break; default: $clean[$key] = isset($dirty[$key]) ? YMBESEO_Utils::validate_bool($dirty[$key]) : false; break; } } return $clean; }
/** * Validate the option * * @param array $dirty New value for the option. * @param array $clean Clean value for the option, normally the defaults. * @param array $old Old value of the option. * * @return array Validated clean value for the option to be saved to the database */ protected function validate_option($dirty, $clean, $old) { foreach ($clean as $key => $value) { switch ($key) { /* Automagic Facebook connect key */ case 'fbconnectkey': if (isset($old[$key]) && $old[$key] !== '' && preg_match('`^[a-f0-9]{32}$`', $old[$key]) > 0) { $clean[$key] = $old[$key]; } else { $clean[$key] = self::get_fbconnectkey(); } break; /* Will not always exist in form */ /* Will not always exist in form */ case 'fb_admins': if (isset($dirty[$key]) && is_array($dirty[$key])) { if ($dirty[$key] === array()) { $clean[$key] = array(); } else { foreach ($dirty[$key] as $user_id => $fb_array) { /* * @todo [JRF/JRF => Yoast/whomever] add user_id validation - * are these WP user-ids or FB user-ids ? Probably FB user-ids, * if so, find out the rules for FB user-ids */ if (is_array($fb_array) && $fb_array !== array()) { foreach ($fb_array as $fb_key => $fb_value) { switch ($fb_key) { case 'name': /** * @todo [JRF => whomever] add validation for name based * on rules if there are any * Input comes from: $_GET['userrealname'] */ $clean[$key][$user_id][$fb_key] = sanitize_text_field($fb_value); break; case 'link': $clean[$key][$user_id][$fb_key] = YMBESEO_Utils::sanitize_url($fb_value); break; } } } } unset($user_id, $fb_array, $fb_key, $fb_value); } } elseif (isset($old[$key]) && is_array($old[$key])) { $clean[$key] = $old[$key]; } break; /* text fields */ /* text fields */ case 'og_frontpage_desc': case 'og_frontpage_title': if (isset($dirty[$key]) && $dirty[$key] !== '') { $clean[$key] = YMBESEO_Utils::sanitize_text_field($dirty[$key]); } break; /* url text fields - no ftp allowed */ /* url text fields - no ftp allowed */ case 'facebook_site': case 'instagram_url': case 'linkedin_url': case 'myspace_url': case 'pinterest_url': case 'plus-publisher': case 'og_default_image': case 'og_frontpage_image': case 'youtube_url': case 'google_plus_url': $this->validate_url($key, $dirty, $old, $clean); break; case 'pinterestverify': $this->validate_verification_string($key, $dirty, $old, $clean); break; /* twitter user name */ /* twitter user name */ case 'twitter_site': if (isset($dirty[$key]) && $dirty[$key] !== '') { $twitter_id = sanitize_text_field(ltrim($dirty[$key], '@')); /** * From the Twitter documentation about twitter screen names: * Typically a maximum of 15 characters long, but some historical accounts * may exist with longer names. * A username can only contain alphanumeric characters (letters A-Z, numbers 0-9) * with the exception of underscores * @link https://support.twitter.com/articles/101299-why-can-t-i-register-certain-usernames * @link https://dev.twitter.com/docs/platform-objects/users */ if (preg_match('`^[A-Za-z0-9_]{1,25}$`', $twitter_id)) { $clean[$key] = $twitter_id; } elseif (preg_match('`^http(?:s)?://(?:www\\.)?twitter\\.com/(?P<handle>[A-Za-z0-9_]{1,25})/?$`', $twitter_id, $matches)) { $clean[$key] = $matches['handle']; } else { if (isset($old[$key]) && $old[$key] !== '') { $twitter_id = sanitize_text_field(ltrim($old[$key], '@')); if (preg_match('`^[A-Za-z0-9_]{1,25}$`', $twitter_id)) { $clean[$key] = $twitter_id; } } if (function_exists('add_settings_error')) { add_settings_error($this->group_name, '_' . $key, sprintf(__('%s does not seem to be a valid Twitter user-id. Please correct.', 'ymbeseo'), '<strong>' . esc_html(sanitize_text_field($dirty[$key])) . '</strong>'), 'error'); } } unset($twitter_id); } break; case 'twitter_card_type': if (isset($dirty[$key], self::$twitter_card_types[$dirty[$key]]) && $dirty[$key] !== '') { $clean[$key] = $dirty[$key]; } break; /* boolean fields */ /* boolean fields */ case 'googleplus': case 'opengraph': case 'twitter': $clean[$key] = isset($dirty[$key]) ? YMBESEO_Utils::validate_bool($dirty[$key]) : false; break; } } /** * Only validate 'fbadminapp', so leave the clean default. */ if (isset($dirty['fbadminapp']) && !empty($dirty['fbadminapp'])) { $clean['fbadminapp'] = $dirty['fbadminapp']; } return $clean; }
/** * Validate a value as boolean * * @deprecated 1.5.6.1 * @deprecated use YMBESEO_Utils::validate_bool() * @see YMBESEO_Utils::validate_bool() * * @static * * @param mixed $value * * @return bool */ public static function validate_bool($value) { _deprecated_function(__FUNCTION__, 'WPSEO 1.5.6.1', 'YMBESEO_Utils::validate_bool()'); return YMBESEO_Utils::validate_bool($value); }
/** * Clean a given option value * * @param array $option_value Old (not merged with defaults or filtered) option value to * clean according to the rules for this option. * @param string $current_version (optional) Version from which to upgrade, if not set, * version specific upgrades will be disregarded. * @param array $all_old_option_values (optional) Only used when importing old options to have * access to the real old values, in contrast to the saved ones. * * @return array Cleaned option */ protected function clean_option($option_value, $current_version = null, $all_old_option_values = null) { /* Make sure the values of the variable option key options are cleaned as they may be retained and would not be cleaned/validated then */ if (is_array($option_value) && $option_value !== array()) { foreach ($option_value as $key => $value) { $switch_key = $this->get_switch_key($key); // Similar to validation routine - any changes made there should be made here too. switch ($switch_key) { case 'user_role-': /* 'user_role-' . $role_name. '-not_in_sitemap' fields */ /* 'user_role-' . $role_name. '-not_in_sitemap' fields */ case 'post_types-': /* 'post_types-' . $pt->name . '-not_in_sitemap' fields */ /* 'post_types-' . $pt->name . '-not_in_sitemap' fields */ case 'taxonomies-': /* 'taxonomies-' . $tax->name . '-not_in_sitemap' fields */ $option_value[$key] = YMBESEO_Utils::validate_bool($value); break; } } } return $option_value; }
/** * Validate the option * * @param array $dirty New value for the option. * @param array $clean Clean value for the option, normally the defaults. * @param array $old Old value of the option (not used here as all fields will always be in the form). * * @return array Validated clean value for the option to be saved to the database */ protected function validate_option($dirty, $clean, $old) { foreach ($clean as $key => $value) { switch ($key) { /* text fields */ case 'cleanpermalink-extravars': if (isset($dirty[$key]) && $dirty[$key] !== '') { $clean[$key] = sanitize_text_field($dirty[$key]); } break; /* Boolean (checkbox) fields */ /* Covers: * 'cleanpermalinks' * 'cleanpermalink-googlesitesearch' * 'cleanpermalink-googlecampaign' * 'cleanreplytocom' * 'cleanslugs' * 'hide-rsdlink' * 'hide-wlwmanifest' * 'hide-shortlink' * 'hide-feedlinks' * 'redirectattachment' * 'stripcategorybase' * 'trailingslash' */ /* Boolean (checkbox) fields */ /* Covers: * 'cleanpermalinks' * 'cleanpermalink-googlesitesearch' * 'cleanpermalink-googlecampaign' * 'cleanreplytocom' * 'cleanslugs' * 'hide-rsdlink' * 'hide-wlwmanifest' * 'hide-shortlink' * 'hide-feedlinks' * 'redirectattachment' * 'stripcategorybase' * 'trailingslash' */ default: $clean[$key] = isset($dirty[$key]) ? YMBESEO_Utils::validate_bool($dirty[$key]) : false; break; } } return $clean; }
/** * Validate the option * * @param array $dirty New value for the option. * @param array $clean Clean value for the option, normally the defaults. * @param array $old Old value of the option. * * @return array Validated clean value for the option to be saved to the database */ protected function validate_option($dirty, $clean, $old) { $allowed_post_types = $this->get_allowed_post_types(); foreach ($clean as $key => $value) { $switch_key = $this->get_switch_key($key); switch ($switch_key) { /* text fields */ case 'breadcrumbs-404crumb': case 'breadcrumbs-archiveprefix': case 'breadcrumbs-home': case 'breadcrumbs-prefix': case 'breadcrumbs-searchprefix': case 'breadcrumbs-sep': if (isset($dirty[$key])) { $clean[$key] = wp_kses_post($dirty[$key]); } break; /* 'post_types-' . $pt->name . '-maintax' fields */ /* 'post_types-' . $pt->name . '-maintax' fields */ case 'post_types-': $post_type = str_replace(array('post_types-', '-maintax'), '', $key); $taxonomies = get_object_taxonomies($post_type, 'names'); if (isset($dirty[$key])) { if ($taxonomies !== array() && in_array($dirty[$key], $taxonomies, true)) { $clean[$key] = $dirty[$key]; } elseif ((string) $dirty[$key] === '0' || (string) $dirty[$key] === '') { $clean[$key] = 0; } elseif (sanitize_title_with_dashes($dirty[$key]) === $dirty[$key]) { // Allow taxonomies which may not be registered yet. $clean[$key] = $dirty[$key]; } else { if (isset($old[$key])) { $clean[$key] = sanitize_title_with_dashes($old[$key]); } if (function_exists('add_settings_error')) { /** * @todo [JRF => whomever] maybe change the untranslated $pt name in the * error message to the nicely translated label ? */ add_settings_error($this->group_name, '_' . $key, sprintf(__('Please select a valid taxonomy for post type "%s"', 'ymbeseo'), $post_type), 'error'); } } } elseif (isset($old[$key])) { $clean[$key] = sanitize_title_with_dashes($old[$key]); } unset($taxonomies, $post_type); break; /* 'taxonomy-' . $tax->name . '-ptparent' fields */ /* 'taxonomy-' . $tax->name . '-ptparent' fields */ case 'taxonomy-': if (isset($dirty[$key])) { if ($allowed_post_types !== array() && in_array($dirty[$key], $allowed_post_types, true)) { $clean[$key] = $dirty[$key]; } elseif ((string) $dirty[$key] === '0' || (string) $dirty[$key] === '') { $clean[$key] = 0; } elseif (sanitize_key($dirty[$key]) === $dirty[$key]) { // Allow taxonomies which may not be registered yet. $clean[$key] = $dirty[$key]; } else { if (isset($old[$key])) { $clean[$key] = sanitize_key($old[$key]); } if (function_exists('add_settings_error')) { /** * @todo [JRF =? whomever] maybe change the untranslated $tax name in the * error message to the nicely translated label ? */ $tax = str_replace(array('taxonomy-', '-ptparent'), '', $key); add_settings_error($this->group_name, '_' . $tax, sprintf(__('Please select a valid post type for taxonomy "%s"', 'ymbeseo'), $tax), 'error'); unset($tax); } } } elseif (isset($old[$key])) { $clean[$key] = sanitize_key($old[$key]); } break; /* Boolean fields */ /* Covers: * 'breadcrumbs-blog-remove' * 'breadcrumbs-boldlast' * 'breadcrumbs-enable' */ /* Boolean fields */ /* Covers: * 'breadcrumbs-blog-remove' * 'breadcrumbs-boldlast' * 'breadcrumbs-enable' */ default: $clean[$key] = isset($dirty[$key]) ? YMBESEO_Utils::validate_bool($dirty[$key]) : false; break; } } return $clean; }