get_defaults(); * * {@internal Note: Some of the default values are added via the translate_defaults() method.}} */ protected $defaults = array( 'breadcrumbs-404crumb' => '', // Text field. 'breadcrumbs-blog-remove' => false, 'breadcrumbs-boldlast' => false, 'breadcrumbs-archiveprefix' => '', // Text field. 'breadcrumbs-enable' => false, 'breadcrumbs-home' => '', // Text field. 'breadcrumbs-prefix' => '', // Text field. 'breadcrumbs-searchprefix' => '', // Text field. 'breadcrumbs-sep' => '»', // Text field. /** * Uses enrich_defaults() to add more along the lines of: * - 'post_types-' . $pt->name . '-maintax' => 0 / string * - 'taxonomy-' . $tax->name . '-ptparent' => 0 / string */ ); /** * @var array Array of variable option name patterns for the option. */ protected $variable_array_key_patterns = array( 'post_types-', 'taxonomy-', ); /** * Get the singleton instance of this class. * * @return object */ public static function get_instance() { if ( ! ( self::$instance instanceof self ) ) { self::$instance = new self(); } return self::$instance; } /** * Translate strings used in the option defaults. * * @return void */ public function translate_defaults() { $this->defaults['breadcrumbs-404crumb'] = __( 'Error 404: Page not found', 'wordpress-seo' ); $this->defaults['breadcrumbs-archiveprefix'] = __( 'Archives for', 'wordpress-seo' ); $this->defaults['breadcrumbs-home'] = __( 'Home', 'wordpress-seo' ); $this->defaults['breadcrumbs-searchprefix'] = __( 'You searched for', 'wordpress-seo' ); } /** * Add dynamically created default options based on available post types and taxonomies. * * @return void */ public function enrich_defaults() { /* * Retrieve all the relevant post type and taxonomy arrays. * * WPSEO_Post_Type::get_accessible_post_types() should *not* be used here. */ $post_type_names = get_post_types( array( 'public' => true ), 'names' ); $taxonomy_names_custom = get_taxonomies( array( 'public' => true, '_builtin' => false, ), 'names' ); if ( $post_type_names !== array() ) { foreach ( $post_type_names as $pt ) { $pto_taxonomies = get_object_taxonomies( $pt, 'names' ); if ( $pto_taxonomies !== array() ) { $this->defaults[ 'post_types-' . $pt . '-maintax' ] = 0; // Select box. } unset( $pto_taxonomies ); } unset( $pt ); } if ( $taxonomy_names_custom !== array() ) { foreach ( $taxonomy_names_custom as $tax ) { $this->defaults[ 'taxonomy-' . $tax . '-ptparent' ] = 0; // Select box;. } unset( $tax ); } } /** * 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. */ 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, // Slug title of the setting. '_' . $key, // Suffix-id for the error message box. /* translators: %s expands to a post type. */ sprintf( __( 'Please select a valid taxonomy for post type "%s"', 'wordpress-seo' ), $post_type ), // The error message. 'error' // Error type, either 'error' or 'updated'. ); } } } elseif ( isset( $old[ $key ] ) ) { $clean[ $key ] = sanitize_title_with_dashes( $old[ $key ] ); } unset( $taxonomies, $post_type ); break; /* '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, // Slug title of the setting. '_' . $tax, // Suffix-id for the error message box. /* translators: %s expands to a taxonomy slug. */ sprintf( __( 'Please select a valid post type for taxonomy "%s"', 'wordpress-seo' ), $tax ), // The error message. 'error' // Error type, either 'error' or 'updated'. ); unset( $tax ); } } } elseif ( isset( $old[ $key ] ) ) { $clean[ $key ] = sanitize_key( $old[ $key ] ); } break; /* Boolean fields. */ /* Covers: * 'breadcrumbs-blog-remove' * 'breadcrumbs-boldlast' * 'breadcrumbs-enable' */ default: $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false ); break; } } return $clean; } /** * Retrieve a list of the allowed post types as breadcrumb parent for a taxonomy. * Helper method for validation. * * {@internal Don't make static as new types may still be registered.}} * * @return array */ protected function get_allowed_post_types() { $allowed_post_types = array(); /* * WPSEO_Post_Type::get_accessible_post_types() should *not* be used here. */ $post_types = get_post_types( array( 'public' => true ), 'objects' ); if ( get_option( 'show_on_front' ) === 'page' && get_option( 'page_for_posts' ) > 0 ) { $allowed_post_types[] = 'post'; } if ( is_array( $post_types ) && $post_types !== array() ) { foreach ( $post_types as $type ) { if ( $type->has_archive ) { $allowed_post_types[] = $type->name; } } } return $allowed_post_types; } /** * 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 old fall-back defaults for empty option keys are now added to the option .*/ if ( isset( $current_version ) && version_compare( $current_version, '1.5.2.3', '<' ) ) { if ( has_action( 'init', array( 'WPSEO_Options', 'bring_back_breadcrumb_defaults' ) ) === false ) { add_action( 'init', array( 'WPSEO_Options', 'bring_back_breadcrumb_defaults' ), 3 ); } } /* * 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() ) { $allowed_post_types = $this->get_allowed_post_types(); 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 ) { /* '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 ( $taxonomies !== array() && in_array( $value, $taxonomies, true ) ) { $option_value[ $key ] = $value; } elseif ( (string) $value === '0' || (string) $value === '' ) { $option_value[ $key ] = 0; } elseif ( sanitize_title_with_dashes( $value ) === $value ) { // Allow taxonomies which may not be registered yet. $option_value[ $key ] = $value; } unset( $taxonomies, $post_type ); break; /* 'taxonomy-' . $tax->name . '-ptparent' fields. */ case 'taxonomy-': if ( $allowed_post_types !== array() && in_array( $value, $allowed_post_types, true ) ) { $option_value[ $key ] = $value; } elseif ( (string) $value === '0' || (string) $value === '' ) { $option_value[ $key ] = 0; } elseif ( sanitize_key( $option_value[ $key ] ) === $option_value[ $key ] ) { // Allow post types which may not be registered yet. $option_value[ $key ] = $value; } break; } } } return $option_value; } /** * With the changes to v1.5, the defaults for some of the textual breadcrumb settings are added * dynamically, but empty strings are allowed. * This caused issues for people who left the fields empty on purpose relying on the defaults. * This little routine fixes that. * Needs to be run on 'init' hook at prio 3 to make sure the defaults are translated. */ public function bring_back_defaults() { $option = get_option( $this->option_name ); $values_to_bring_back = array( 'breadcrumbs-404crumb', 'breadcrumbs-archiveprefix', 'breadcrumbs-home', 'breadcrumbs-searchprefix', 'breadcrumbs-sep', ); foreach ( $values_to_bring_back as $key ) { if ( $option[ $key ] === '' && $this->defaults[ $key ] !== '' ) { $option[ $key ] = $this->defaults[ $key ]; } } update_option( $this->option_name, $option ); } }