ze_textarea_field( $value ); case 'string': return sanitize_text_field( $value ); case 'number': return intval( $value ); case 'array': $array = []; foreach ( (array) $value as $k => $v ) { if ( is_array( $v ) ) { $array[ $k ] = $this->sanitizeField( $v, 'array' ); continue; } $array[ $k ] = sanitize_text_field( $preserveHtml ? htmlspecialchars( $v, ENT_NOQUOTES, 'UTF-8' ) : $v ); } return $array; case 'float': return floatval( $value ); } } /** * Checks to see if we need to set the group key. If so, will return true. * * @since 4.0.0 * * @param string $name The name of the option to set. * @param array $arguments Any arguments needed if this was a method called. * @param mixed $value The value if we are setting an option. * @return boolean Whether or not we need to set the group key. */ private function setGroupKey( $name, $arguments = null, $value = null ) { $this->arguments = $arguments; $this->value = $value; if ( empty( $this->groupKey ) ) { $groups = array_keys( $this->defaultsMerged ); if ( in_array( $name, $groups, true ) ) { $this->groupKey = $name; return true; } $this->groupKey = $groups[0]; } return false; } /** * Sets the sub group key. Will set and return the instance. * * @since 4.0.0 * * @param string $name The name of the option to set. * @param array $arguments Any arguments needed if this was a method called. * @param mixed $value The value if we are setting an option. * @return object The options object. */ private function setSubGroup( $name, $arguments = null, $value = null ) { if ( ! is_null( $arguments ) ) { $this->arguments = $arguments; } if ( ! is_null( $value ) ) { $this->value = $value; } $defaults = $this->defaultsMerged[ $this->groupKey ]; if ( ! empty( $this->subGroups ) ) { foreach ( $this->subGroups as $subGroup ) { $defaults = $defaults[ $subGroup ]; } } $groups = array_keys( $defaults ); if ( in_array( $name, $groups, true ) ) { $this->subGroups[] = $name; } return $this; } /** * Reset groups. * * @since 4.0.0 * * @return void */ protected function resetGroups() { $this->groupKey = null; $this->subGroups = []; } /** * Converts an associative array of values into a structure * that works with our defaults. * * @since 4.0.0 * * @param array $defaults The defaults array we are currently working with. * @param array $values The values to adjust. * @param array $keys Parent keys for the current group we are parsing. * @param bool $sanitize Whether or not we should sanitize the value. * @return array The modified values. */ protected function addValueToValuesArray( $defaults, $values, $keys = [], $sanitize = false ) { foreach ( $values as $key => $value ) { $option = $this->isAnOption( $key, $defaults, $keys ); if ( $option ) { $preserveHtml = ! empty( $option['preserveHtml'] ); $newValue = $sanitize ? $this->sanitizeField( $value, $option['type'], $preserveHtml ) : $value; $values[ $key ] = [ 'value' => $newValue ]; // If this is a localized string, let's save it to our localized options. if ( $sanitize && ! empty( $option['localized'] ) ) { $localizedKey = ''; foreach ( $keys as $k ) { $localizedKey .= $k . '_'; } $localizedKey .= $key; $localizedValue = $newValue; if ( 'keywords' === $key ) { $keywords = json_decode( $localizedValue ) ? json_decode( $localizedValue ) : []; foreach ( $keywords as $k => $keyword ) { $keywords[ $k ] = $keyword->value; } $localizedValue = implode( ',', $keywords ); } $this->localized[ $localizedKey ] = $localizedValue; } continue; } if ( ! is_array( $value ) ) { continue; } $keys[] = $key; $values[ $key ] = $this->addValueToValuesArray( $defaults, $value, $keys, $sanitize ); array_pop( $keys ); } return $values; } /** * Our options array has values (or defaults). * This method converts them to how we would store them * in the DB. * * @since 4.0.0 * * @param array $options The options array. * @return array The converted options array. */ public function convertOptionsToValues( $options, $optionKey = 'type' ) { foreach ( $options as $key => $value ) { if ( ! is_array( $value ) ) { continue; } if ( ! isset( $value[ $optionKey ] ) ) { $options[ $key ] = $this->convertOptionsToValues( $value, $optionKey ); continue; } $options[ $key ] = null; if ( isset( $value['value'] ) ) { $preserveHtml = ! empty( $value['preserveHtml'] ); if ( $preserveHtml ) { if ( is_array( $value['value'] ) ) { foreach ( $value['value'] as $k => $v ) { $value['value'][ $k ] = html_entity_decode( $v, ENT_NOQUOTES ); } } else { $value['value'] = html_entity_decode( $value['value'], ENT_NOQUOTES ); } } $options[ $key ] = $value['value']; continue; } if ( isset( $value['default'] ) ) { $options[ $key ] = $value['default']; } } return $options; } /** * This checks to see if the current array/option is really an option * and not just another parent with a subgroup. * * @since 4.0.0 * * @param string $key The current array key we are working with. * @param array $defaults The defaults array to check against. * @param array $keys The parent keys to loop through. * @return bool Whether or not this is an option. */ private function isAnOption( $key, $defaults, $keys ) { if ( ! empty( $keys ) ) { foreach ( $keys as $k ) { $defaults = isset( $defaults[ $k ] ) ? $defaults[ $k ] : []; } } if ( isset( $defaults[ $key ]['type'] ) ) { return $defaults[ $key ]; } return false; } /** * Refreshes the options from the database. * * We need this during the migration to update through clones. * * @since 4.0.0 * * @return void */ public function refresh() { // Reset DB options to clear the cache. aioseo()->core->optionsCache->resetDb(); $this->init(); } /** * Returns the DB options. * * @since 4.1.4 * * @param string $optionsName The options name. * @return array The options. */ public function getDbOptions( $optionsName ) { $cache = aioseo()->core->optionsCache->getDb( $optionsName ); if ( empty( $cache ) ) { $options = json_decode( get_option( $optionsName ), true ); $options = ! empty( $options ) ? $options : []; // Set the cache. aioseo()->core->optionsCache->setDb( $optionsName, $options ); } return aioseo()->core->optionsCache->getDb( $optionsName ); } /** * In order to not have a conflict, we need to return a clone. * * @since 4.0.0 * * @param bool $reInitialize Whether to reinitialize on the clone. * @return object The cloned Options object. */ public function noConflict( $reInitialize = false ) { $class = clone $this; $class->isClone = true; if ( $reInitialize ) { $class->init(); } return $class; } /** * Get original instance. Since this could be a cloned object, let's get the original instance. * * @since 4.1.4 * * @return self */ public function getOriginalInstance() { if ( ! $this->isClone ) { return $this; } $class = new \ReflectionClass( get_called_class() ); $optionName = aioseo()->helpers->toCamelCase( $class->getShortName() ); if ( isset( aioseo()->{ $optionName } ) ) { return aioseo()->{ $optionName }; } return $this; } }