'xstore-core' ) ), 'description' => '', 'icon' => self::sanitize_icon_classes( 'dashicons-download' ), 'panel' => '', 'priority' => 999999, ); $fields_by_section = array(); $fields_by_setting = array(); foreach ( array_keys( $sections_by_id ) as $section_id ) { $fields = array(); if ( is_array( $raw_fields_global ) ) { foreach ( $raw_fields_global as $f ) { if ( ! is_array( $f ) ) { continue; } if ( sanitize_key( (string) ( $f['section'] ?? '' ) ) !== $section_id ) { continue; } $fields[] = $f; } } $section_fields = apply_filters( 'et/customizer/add/fields/' . $section_id, array() ); if ( is_array( $section_fields ) ) { $fields = array_merge( $fields, $section_fields ); } $norm_map = array(); foreach ( $fields as $f ) { if ( ! is_array( $f ) ) { continue; } $type = isset( $f['type'] ) ? sanitize_key( (string) $f['type'] ) : ''; $setting = isset( $f['settings'] ) ? sanitize_key( (string) $f['settings'] ) : ''; $field_section = isset( $f['section'] ) ? sanitize_key( (string) $f['section'] ) : $section_id; if ( ! $type || ! $setting ) { continue; } if ( ! isset( $sections_by_id[ $field_section ] ) ) { continue; } if ( in_array( $field_section, self::$exclude_sections, true ) ) { continue; } $normalized = array( 'setting' => $setting, 'type' => $type, 'section' => $field_section, 'label' => self::normalize_text( $f['label'] ?? '' ), 'description' => $f['description'] ?? '', 'tooltip' => $f['tooltip'] ?? '', 'default' => $f['default'] ?? null, 'choices' => self::deep_strip_tags( $f['choices'] ?? array() ), 'multiple' => isset( $f['multiple'] ) ? (int) $f['multiple'] : null, 'placeholder' => isset( $f['placeholder'] ) ? self::normalize_text( (string) $f['placeholder'] ) : '', 'priority' => (int) ( $f['priority'] ?? 10 ), 'active_callback' => self::sanitize_active_callback( $f['active_callback'] ?? array() ), ); if ( isset( $f['choices'] ) && is_array( $f['choices'] ) && ! empty( $f['choices']['setting'] ) ) { $normalized['description'] = esc_html__('Select the text color for your content.', 'xstore-core'); $normalized['tooltip'] = ''; } if ( $type === 'repeater' && isset( $f['fields'] ) && is_array( $f['fields'] ) ) { $normalized['fields'] = self::deep_strip_tags( $f['fields'] ); $normalized['row_label'] = isset( $f['row_label'] ) && is_array( $f['row_label'] ) ? self::deep_strip_tags( $f['row_label'] ) : array(); $normalized['button_label'] = isset( $f['button_label'] ) ? self::normalize_text( (string) $f['button_label'] ) : ''; if ( $setting === 'mobile_panel_package_et-mobile' && isset( $normalized['fields']['link'] ) && is_array( $normalized['fields']['link'] ) ) { $choices = $normalized['fields']['link']['choices'] ?? null; if ( ! is_array( $choices ) || empty( $choices ) ) { $normalized['fields']['link']['choices'] = self::get_pages_choices( true ); } } } if ( $setting === 'site_sections' && isset( $normalized['fields']['staticblock'] ) ) { if ( empty( $normalized['fields']['staticblock']['choices'] ) || ! is_array( $normalized['fields']['staticblock']['choices'] ) ) { $normalized['fields']['staticblock']['choices'] = self::get_staticblocks_choices( true ); } } if ( $type === 'custom' ) { $raw_default = (string) ( $f['default'] ?? '' ); if ( $raw_default !== '' && false !== strpos( $raw_default, 'et_edit' ) ) { continue; } $title = self::normalize_text( $raw_default ); if ( $title === '' ) { continue; } $normalized['is_separator'] = true; $normalized['label'] = $title; $normalized['description'] = ''; $normalized['tooltip'] = ''; $normalized['default'] = ''; } $norm_map[ $setting ] = $normalized; } if ( $norm_map ) { uasort( $norm_map, static function ( $a, $b ) { return ( $a['priority'] <=> $b['priority'] ); } ); $fields_by_section[ $section_id ] = array_values( $norm_map ); foreach ( $norm_map as $setting => $field ) { $fields_by_setting[ $setting ] = $field; } } } foreach ( array_keys( $sections_by_id ) as $section_id ) { if ( $section_id === self::IMPORT_EXPORT_SECTION_ID ) { continue; } if ( empty( $fields_by_section[ $section_id ] ) ) { unset( $sections_by_id[ $section_id ] ); } } uasort( $sections_by_id, static function ( $a, $b ) { return ( $a['priority'] <=> $b['priority'] ); } ); self::$schema_cache = array( 'panelsById' => $panels_by_id, 'sections' => array_values( $sections_by_id ), 'fieldsBySection' => $fields_by_section, 'fieldsBySetting' => $fields_by_setting, ); return self::$schema_cache; } private static function get_staticblocks_choices( bool $with_none ): array { $args = array( 'post_type' => 'staticblocks', 'post_status' => 'publish', 'posts_per_page' => 200, 'no_found_rows' => true, 'orderby' => 'title', 'order' => 'ASC', ); $posts = get_posts( $args ); $out = array(); foreach ( $posts as $p ) { $out[ (string) $p->ID ] = $p->post_title . ' (id - ' . $p->ID . ')'; } if ( $with_none ) { $out[0] = esc_html__( 'None', 'xstore-core' ); } return $out; } private static function get_pages_choices( bool $with_select_page ): array { $args = array( 'post_type' => 'page', 'post_status' => 'publish', 'posts_per_page' => 200, 'no_found_rows' => true, 'orderby' => 'title', 'order' => 'ASC', ); $posts = get_posts( $args ); $out = array(); if ( $with_select_page ) { $out[0] = esc_html__( 'Select page', 'xstore-core' ); } foreach ( $posts as $p ) { $out[ (string) $p->ID ] = $p->post_title . ' (id - ' . $p->ID . ')'; } return $out; } private static function deep_strip_tags( $data ) { if ( is_array( $data ) ) { $out = array(); foreach ( $data as $k => $v ) { $out[ $k ] = self::deep_strip_tags( $v ); } return $out; } if ( is_string( $data ) ) { $str = wp_strip_all_tags( $data ); $str = wp_kses_decode_entities( $str ); return html_entity_decode( $str, ENT_QUOTES, 'UTF-8' ); } return $data; } private static function normalize_text( $text ): string { $str = wp_strip_all_tags( (string) $text ); $str = wp_kses_decode_entities( $str ); return html_entity_decode( $str, ENT_QUOTES, 'UTF-8' ); } private static function sanitize_section_description( $html ): string { $raw = trim( (string) $html ); if ( $raw === '' ) { return ''; } $raw = wp_specialchars_decode( $raw, ENT_QUOTES ); $allowed = wp_kses_allowed_html( 'post' ); if ( ! isset( $allowed['a'] ) || ! is_array( $allowed['a'] ) ) { $allowed['a'] = array(); } $allowed['a']['href'] = true; $allowed['a']['rel'] = true; $allowed['a']['target'] = true; $allowed['a']['title'] = true; $allowed['a']['class'] = true; return trim( wp_kses( $raw, $allowed ) ); } private static function sanitize_icon_classes( $icon ): string { $raw = trim( self::normalize_text( $icon ) ); if ( $raw === '' ) { return ''; } $tokens = preg_split( '/\s+/', $raw ); if ( ! is_array( $tokens ) ) { return sanitize_html_class( $raw ); } $out = array(); foreach ( $tokens as $t ) { $t = sanitize_html_class( $t ); if ( $t !== '' ) { $out[] = $t; } } $out = array_values( array_unique( $out ) ); return implode( ' ', $out ); } private static function sanitize_active_callback( $data ): array { if ( ! is_array( $data ) ) { return array(); } $out = array(); foreach ( $data as $row ) { if ( ! is_array( $row ) ) { continue; } $setting = isset( $row['setting'] ) ? sanitize_key( (string) $row['setting'] ) : ''; $operator = isset( $row['operator'] ) ? (string) $row['operator'] : '=='; $value = $row['value'] ?? null; if ( ! $setting ) { continue; } $out[] = array( 'setting' => $setting, 'operator' => $operator, 'value' => $value, ); } return $out; } private static function sanitize_value( array $field, $value ) { $type = (string) ( $field['type'] ?? '' ); $default = $field['default'] ?? null; if ( $type === 'toggle' ) { return ( ! empty( $value ) ) ? 1 : 0; } if ( $type === 'checkbox' ) { return ( ! empty( $value ) ) ? true : false; } if ( $type === 'slider' || $type === 'number' ) { if ( $value === '' || $value === null ) { return ''; } if ( is_numeric( $value ) ) { return 0 + $value; } return is_numeric( $default ) ? ( 0 + $default ) : 0; } if ( $type === 'select' ) { $choices = $field['choices'] ?? array(); $allowed = is_array( $choices ) ? array_keys( $choices ) : array(); $multiple = isset( $field['multiple'] ) ? (int) $field['multiple'] : 0; $is_multi = $multiple > 1; if ( $is_multi ) { $raw = array(); if ( is_array( $value ) ) { $raw = $value; } elseif ( is_string( $value ) ) { $raw = array_filter( array_map( 'trim', explode( ',', $value ) ) ); } else { return is_array( $default ) ? $default : array(); } $selected = array(); foreach ( $raw as $v ) { $k = trim( (string) $v ); if ( $k !== '' ) { $selected[] = $k; } } $selected = array_values( array_unique( $selected ) ); if ( $allowed ) { $allowed_set = array_fill_keys( array_map( 'strval', $allowed ), true ); $out = array(); foreach ( $allowed as $k ) { $k = (string) $k; if ( isset( $allowed_set[ $k ] ) && in_array( $k, $selected, true ) ) { $out[] = $k; } } $selected = $out; } if ( $multiple > 0 && count( $selected ) > $multiple ) { $selected = array_slice( $selected, 0, $multiple ); } return $selected; } $value = (string) $value; if ( is_array( $choices ) && array_key_exists( $value, $choices ) ) { return $value; } return is_string( $default ) ? $default : ''; } if ( $type === 'radio-buttonset' || $type === 'radio-image' ) { $choices = $field['choices'] ?? array(); $value = (string) $value; if ( is_array( $choices ) && array_key_exists( $value, $choices ) ) { return $value; } return is_string( $default ) ? $default : ''; } if ( $type === 'multicheck' ) { $choices = $field['choices'] ?? array(); $allowed = is_array( $choices ) ? array_keys( $choices ) : array(); $raw = array(); if ( is_array( $value ) ) { $raw = $value; } elseif ( is_string( $value ) ) { $raw = array_filter( array_map( 'trim', explode( ',', $value ) ) ); } else { return is_array( $default ) ? $default : array(); } $selected = array(); foreach ( $raw as $v ) { $k = sanitize_key( (string) $v ); if ( $k !== '' ) { $selected[] = $k; } } $selected = array_values( array_unique( $selected ) ); if ( $allowed ) { $set = array_fill_keys( $selected, true ); $out = array(); foreach ( $allowed as $k ) { $k = sanitize_key( (string) $k ); if ( isset( $set[ $k ] ) ) { $out[] = $k; } } return $out; } return $selected; } if ( $type === 'color' ) { $value = trim( (string) $value ); if ( $value === '' ) { return ''; } if ( sanitize_hex_color( $value ) ) { return $value; } if ( preg_match( '/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+)\s*)?\)$/', $value ) ) { return $value; } return is_string( $default ) ? $default : ''; } if ( $type === 'image' ) { if ( $value === '' || $value === null ) { return ''; } if ( is_array( $value ) ) { return array( 'id' => isset( $value['id'] ) ? absint( $value['id'] ) : 0, 'url' => isset( $value['url'] ) ? esc_url_raw( (string) $value['url'] ) : '', ); } return esc_url_raw( (string) $value ); } if ( $type === 'upload' ) { if ( $value === '' || $value === null ) { return ''; } if ( is_array( $value ) ) { return isset( $value['url'] ) ? esc_url_raw( (string) $value['url'] ) : ''; } return esc_url_raw( (string) $value ); } if ( $type === 'textarea' || $type === 'etheme-textarea' ) { return sanitize_textarea_field( (string) $value ); } if ( $type === 'editor' ) { return wp_kses_post( (string) $value ); } if ( $type === 'code' ) { return wp_strip_all_tags( (string) $value ); } if ( $type === 'background' ) { if ( ! is_array( $value ) ) { return is_array( $default ) ? $default : array(); } return array( 'background-color' => isset( $value['background-color'] ) ? sanitize_text_field( (string) $value['background-color'] ) : '', 'background-image' => isset( $value['background-image'] ) ? esc_url_raw( (string) $value['background-image'] ) : '', 'background-repeat' => isset( $value['background-repeat'] ) ? sanitize_text_field( (string) $value['background-repeat'] ) : '', 'background-position' => isset( $value['background-position'] ) ? sanitize_text_field( (string) $value['background-position'] ) : '', 'background-size' => isset( $value['background-size'] ) ? sanitize_text_field( (string) $value['background-size'] ) : '', 'background-attachment' => isset( $value['background-attachment'] ) ? sanitize_text_field( (string) $value['background-attachment'] ) : '', ); } if ( $type === 'typography' && class_exists( 'Kirki_Field_Typography' ) && method_exists( 'Kirki_Field_Typography', 'sanitize' ) ) { $out = Kirki_Field_Typography::sanitize( $value ); if ( is_array( $out ) && array_key_exists( 'letter-spacing', $out ) ) { $ls = $out['letter-spacing']; if ( is_string( $ls ) ) { $ls = trim( $ls ); } if ( is_numeric( $ls ) && (float) $ls !== 0.0 ) { $out['letter-spacing'] = (string) $ls . 'px'; } } return $out; } if ( $type === 'dimensions' || $type === 'multicolor' || $type === 'typography' ) { if ( ! is_array( $value ) ) { return is_array( $default ) ? $default : array(); } $out = array(); foreach ( $value as $k => $v ) { $k = sanitize_key( (string) $k ); if ( is_string( $v ) ) { $out[ $k ] = sanitize_text_field( $v ); } else { $out[ $k ] = $v; } } return $out; } if ( $type === 'sortable' ) { $choices = $field['choices'] ?? array(); if ( ! is_array( $value ) ) { return is_array( $default ) ? $default : array(); } $out = array(); foreach ( $value as $v ) { $v = sanitize_key( (string) $v ); if ( is_array( $choices ) && ! array_key_exists( $v, $choices ) ) { continue; } $out[] = $v; } return array_values( array_unique( $out ) ); } if ( $type === 'repeater' ) { if ( ! is_array( $value ) ) { return is_array( $default ) ? $default : array(); } $out = array(); foreach ( $value as $row ) { if ( ! is_array( $row ) ) { continue; } $clean = array(); foreach ( $row as $k => $v ) { $k = sanitize_key( (string) $k ); if ( is_string( $v ) ) { $clean[ $k ] = sanitize_text_field( $v ); } elseif ( is_bool( $v ) ) { $clean[ $k ] = $v; } elseif ( is_numeric( $v ) ) { $clean[ $k ] = 0 + $v; } else { $clean[ $k ] = $v; } } $out[] = $clean; } return $out; } if ( is_array( $value ) ) { $sanitize = static function ( $v ) use ( &$sanitize ) { if ( is_array( $v ) ) { $out = array(); foreach ( $v as $k => $vv ) { $out[ $k ] = $sanitize( $vv ); } return $out; } if ( is_string( $v ) ) { return sanitize_text_field( $v ); } if ( is_bool( $v ) ) { return $v; } if ( is_numeric( $v ) ) { return 0 + $v; } return $v; }; return $sanitize( $value ); } return sanitize_text_field( (string) $value ); } } XStore_Options_Admin::init();