Conversation
| private function build_schema_from_fields( $fields ) { | ||
| $raw_schema = Resolate_Template_Parser::build_schema_from_field_definitions( $fields ); | ||
| if ( ! is_array( $raw_schema ) ) { | ||
| return array(); | ||
| } | ||
|
|
||
| $schema = array(); | ||
| foreach ( $raw_schema as $entry ) { | ||
| if ( ! is_array( $entry ) || empty( $entry['slug'] ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $slug = sanitize_key( $entry['slug'] ); | ||
| $label = isset( $entry['label'] ) ? sanitize_text_field( $entry['label'] ) : $this->humanize_slug( $slug ); | ||
| $type = isset( $entry['type'] ) ? sanitize_key( $entry['type'] ) : 'textarea'; | ||
| $placeholder = isset( $entry['placeholder'] ) ? $this->sanitize_placeholder_name( $entry['placeholder'] ) : $slug; | ||
| $data_type = isset( $entry['data_type'] ) ? sanitize_key( $entry['data_type'] ) : 'text'; | ||
|
|
||
| if ( '' === $slug ) { | ||
| continue; | ||
| } | ||
| if ( '' === $label ) { | ||
| $label = $this->humanize_slug( $slug ); | ||
| } | ||
| if ( '' === $placeholder ) { | ||
| $placeholder = $slug; | ||
| } | ||
|
|
||
| if ( 'array' === $type ) { | ||
| $item_schema = array(); | ||
| if ( isset( $entry['item_schema'] ) && is_array( $entry['item_schema'] ) ) { | ||
| foreach ( $entry['item_schema'] as $key => $item ) { | ||
| $item_key = sanitize_key( $key ); | ||
| if ( '' === $item_key ) { | ||
| continue; | ||
| } | ||
| $item_label = isset( $item['label'] ) ? sanitize_text_field( $item['label'] ) : $this->humanize_slug( $item_key ); | ||
| $item_type = isset( $item['type'] ) ? sanitize_key( $item['type'] ) : 'textarea'; | ||
| if ( ! in_array( $item_type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $item_type = 'textarea'; | ||
| } | ||
| $item_data_type = isset( $item['data_type'] ) ? sanitize_key( $item['data_type'] ) : 'text'; | ||
| if ( ! in_array( $item_data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
| $item_schema[ $item_key ] = array( | ||
| 'label' => $item_label, | ||
| 'type' => $item_type, | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| $schema[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => 'array', | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => $item_schema, | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
| if ( ! in_array( $data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $data_type = 'text'; | ||
| } | ||
|
|
||
| $schema[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => $type, | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => $data_type, | ||
| ); | ||
| } | ||
|
|
||
| return $schema; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| private function build_schema_from_fields( $fields ) { | ||
| $raw_schema = Resolate_Template_Parser::build_schema_from_field_definitions( $fields ); | ||
| if ( ! is_array( $raw_schema ) ) { | ||
| return array(); | ||
| } | ||
|
|
||
| $schema = array(); | ||
| foreach ( $raw_schema as $entry ) { | ||
| if ( ! is_array( $entry ) || empty( $entry['slug'] ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $slug = sanitize_key( $entry['slug'] ); | ||
| $label = isset( $entry['label'] ) ? sanitize_text_field( $entry['label'] ) : $this->humanize_slug( $slug ); | ||
| $type = isset( $entry['type'] ) ? sanitize_key( $entry['type'] ) : 'textarea'; | ||
| $placeholder = isset( $entry['placeholder'] ) ? $this->sanitize_placeholder_name( $entry['placeholder'] ) : $slug; | ||
| $data_type = isset( $entry['data_type'] ) ? sanitize_key( $entry['data_type'] ) : 'text'; | ||
|
|
||
| if ( '' === $slug ) { | ||
| continue; | ||
| } | ||
| if ( '' === $label ) { | ||
| $label = $this->humanize_slug( $slug ); | ||
| } | ||
| if ( '' === $placeholder ) { | ||
| $placeholder = $slug; | ||
| } | ||
|
|
||
| if ( 'array' === $type ) { | ||
| $item_schema = array(); | ||
| if ( isset( $entry['item_schema'] ) && is_array( $entry['item_schema'] ) ) { | ||
| foreach ( $entry['item_schema'] as $key => $item ) { | ||
| $item_key = sanitize_key( $key ); | ||
| if ( '' === $item_key ) { | ||
| continue; | ||
| } | ||
| $item_label = isset( $item['label'] ) ? sanitize_text_field( $item['label'] ) : $this->humanize_slug( $item_key ); | ||
| $item_type = isset( $item['type'] ) ? sanitize_key( $item['type'] ) : 'textarea'; | ||
| if ( ! in_array( $item_type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $item_type = 'textarea'; | ||
| } | ||
| $item_data_type = isset( $item['data_type'] ) ? sanitize_key( $item['data_type'] ) : 'text'; | ||
| if ( ! in_array( $item_data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
| $item_schema[ $item_key ] = array( | ||
| 'label' => $item_label, | ||
| 'type' => $item_type, | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| $schema[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => 'array', | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => $item_schema, | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
| if ( ! in_array( $data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $data_type = 'text'; | ||
| } | ||
|
|
||
| $schema[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => $type, | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => $data_type, | ||
| ); | ||
| } | ||
|
|
||
| return $schema; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: NPathComplexity Warning
| @@ -404,81 +453,81 @@ private static function build_output_path( $post_id, $extension ) { | |||
| * | |||
| * @return string Absolute directory path. | |||
| */ | |||
| private static function ensure_output_dir() { | |||
| $upload_dir = wp_upload_dir(); | |||
| $dir = trailingslashit( $upload_dir['basedir'] ) . 'resolate'; | |||
| if ( ! is_dir( $dir ) ) { | |||
| wp_mkdir_p( $dir ); | |||
| } | |||
|
|
|||
| return $dir; | |||
| } | |||
|
|
|||
| /** | |||
| * Sanitize placeholders preserving TinyButStrong supported characters. | |||
| * | |||
| * @param string $placeholder Placeholder name. | |||
| * @return string | |||
| */ | |||
| private static function sanitize_placeholder_name( $placeholder ) { | |||
| $placeholder = (string) $placeholder; | |||
| $placeholder = preg_replace( '/[^A-Za-z0-9._:-]/', '', $placeholder ); | |||
| return $placeholder; | |||
| } | |||
|
|
|||
| /** | |||
| * Normalize a field value based on the detected data type. | |||
| * | |||
| * @param string $value Original value. | |||
| * @param string $data_type Detected data type. | |||
| * @return mixed | |||
| */ | |||
| private static function normalize_field_value( $value, $data_type ) { | |||
| $value = is_string( $value ) ? trim( $value ) : $value; | |||
| $data_type = sanitize_key( $data_type ); | |||
|
|
|||
| switch ( $data_type ) { | |||
| case 'number': | |||
| if ( '' === $value ) { | |||
| return ''; | |||
| } | |||
| if ( is_numeric( $value ) ) { | |||
| return 0 + $value; | |||
| } | |||
| $filtered = preg_replace( '/[^0-9.,\-]/', '', (string) $value ); | |||
| if ( '' === $filtered ) { | |||
| return ''; | |||
| } | |||
| $normalized = str_replace( ',', '.', $filtered ); | |||
| if ( is_numeric( $normalized ) ) { | |||
| return 0 + $normalized; | |||
| } | |||
| return $value; | |||
| case 'boolean': | |||
| if ( is_bool( $value ) ) { | |||
| return $value ? 1 : 0; | |||
| } | |||
| $value = strtolower( (string) $value ); | |||
| if ( in_array( $value, array( '1', 'true', 'si', 'sí', 'yes', 'on' ), true ) ) { | |||
| return 1; | |||
| } | |||
| if ( in_array( $value, array( '0', 'false', 'no', 'off' ), true ) ) { | |||
| return 0; | |||
| } | |||
| return '' === $value ? 0 : 0; | |||
| case 'date': | |||
| if ( '' === $value ) { | |||
| return ''; | |||
| } | |||
| $timestamp = strtotime( (string) $value ); | |||
| if ( false === $timestamp ) { | |||
| return $value; | |||
| } | |||
| return wp_date( 'Y-m-d', $timestamp ); | |||
| default: | |||
| return $value; | |||
| } | |||
| } | |||
| private static function ensure_output_dir() { | |||
| $upload_dir = wp_upload_dir(); | |||
| $dir = trailingslashit( $upload_dir['basedir'] ) . 'resolate'; | |||
| if ( ! is_dir( $dir ) ) { | |||
| wp_mkdir_p( $dir ); | |||
| } | |||
|
|
|||
| return $dir; | |||
| } | |||
|
|
|||
| /** | |||
| * Sanitize placeholders preserving TinyButStrong supported characters. | |||
| * | |||
| * @param string $placeholder Placeholder name. | |||
| * @return string | |||
| */ | |||
| private static function sanitize_placeholder_name( $placeholder ) { | |||
| $placeholder = (string) $placeholder; | |||
| $placeholder = preg_replace( '/[^A-Za-z0-9._:-]/', '', $placeholder ); | |||
| return $placeholder; | |||
| } | |||
|
|
|||
| /** | |||
| * Normalize a field value based on the detected data type. | |||
| * | |||
| * @param string $value Original value. | |||
| * @param string $data_type Detected data type. | |||
| * @return mixed | |||
| */ | |||
| private static function normalize_field_value( $value, $data_type ) { | |||
| $value = is_string( $value ) ? trim( $value ) : $value; | |||
| $data_type = sanitize_key( $data_type ); | |||
|
|
|||
| switch ( $data_type ) { | |||
| case 'number': | |||
| if ( '' === $value ) { | |||
| return ''; | |||
| } | |||
| if ( is_numeric( $value ) ) { | |||
| return 0 + $value; | |||
| } | |||
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| public static function build_schema_from_field_definitions( $fields ) { | ||
| if ( ! is_array( $fields ) ) { | ||
| return array(); | ||
| } | ||
|
|
||
| $array_defs = array(); | ||
| $array_order = array(); | ||
| $repeat_hints = array(); | ||
| $pending = array(); | ||
| $order_counter = 0; | ||
|
|
||
| foreach ( $fields as $index => $field ) { | ||
| if ( ! is_array( $field ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $placeholder = isset( $field['placeholder'] ) ? trim( (string) $field['placeholder'] ) : ''; | ||
| $parameters = isset( $field['parameters'] ) && is_array( $field['parameters'] ) ? $field['parameters'] : array(); | ||
| $label = isset( $field['label'] ) ? sanitize_text_field( $field['label'] ) : ''; | ||
| $data_type = isset( $field['data_type'] ) ? sanitize_key( $field['data_type'] ) : 'text'; | ||
|
|
||
| $array_match = self::detect_array_placeholder_with_index( $placeholder ); | ||
| if ( $array_match ) { | ||
| $base = $array_match['base']; | ||
| $key = $array_match['key']; | ||
|
|
||
| if ( '' === $base || '' === $key ) { | ||
| continue; | ||
| } | ||
|
|
||
| $repeat_hints[ $base ] = true; | ||
|
|
||
| if ( ! isset( $array_defs[ $base ] ) ) { | ||
| $array_defs[ $base ] = array( | ||
| 'slug' => $base, | ||
| 'label' => self::humanize_key( $base ), | ||
| 'type' => 'array', | ||
| 'placeholder' => $base, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => array(), | ||
| '_order' => $order_counter++, | ||
| ); | ||
| $array_order[] = $base; | ||
| } | ||
|
|
||
| if ( '' === $label ) { | ||
| $label = self::humanize_key( $array_match['raw_key'] ); | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ]['item_schema'][ $key ] ) ) { | ||
| $item_data_type = self::detect_data_type( $placeholder, $parameters ); | ||
| if ( '' === $item_data_type ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
|
|
||
| $array_defs[ $base ]['item_schema'][ $key ] = array( | ||
| 'label' => $label, | ||
| 'type' => self::infer_array_item_type( $key, $item_data_type ), | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| if ( isset( $parameters['repeat'] ) ) { | ||
| $repeat_base = sanitize_key( $parameters['repeat'] ); | ||
| if ( '' !== $repeat_base ) { | ||
| $repeat_hints[ $repeat_base ] = true; | ||
| } | ||
| } | ||
|
|
||
| $pending[] = array( | ||
| 'field' => $field, | ||
| 'placeholder' => $placeholder, | ||
| 'parameters' => $parameters, | ||
| 'label' => $label, | ||
| 'data_type' => $data_type, | ||
| 'index' => $index, | ||
| ); | ||
| } | ||
|
|
||
| $schema = array(); | ||
| $scalar_fields = array(); | ||
|
|
||
| foreach ( $pending as $entry ) { | ||
| $placeholder = $entry['placeholder']; | ||
| $parameters = $entry['parameters']; | ||
| $label = $entry['label']; | ||
| $data_type = $entry['data_type']; | ||
|
|
||
| $dot_match = self::detect_array_placeholder_without_index( $placeholder ); | ||
| if ( $dot_match && ( isset( $repeat_hints[ $dot_match['base'] ] ) || isset( $array_defs[ $dot_match['base'] ] ) ) ) { | ||
| $base = $dot_match['base']; | ||
| $key = $dot_match['key']; | ||
|
|
||
| if ( '' === $base || '' === $key ) { | ||
| continue; | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ] ) ) { | ||
| $array_defs[ $base ] = array( | ||
| 'slug' => $base, | ||
| 'label' => self::humanize_key( $base ), | ||
| 'type' => 'array', | ||
| 'placeholder' => $base, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => array(), | ||
| '_order' => $order_counter++, | ||
| ); | ||
| $array_order[] = $base; | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ]['item_schema'][ $key ] ) ) { | ||
| $item_data_type = self::detect_data_type( $placeholder, $parameters ); | ||
| if ( '' === $label ) { | ||
| $label = self::humanize_key( $dot_match['raw_key'] ); | ||
| } | ||
| if ( '' === $item_data_type ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
| $array_defs[ $base ]['item_schema'][ $key ] = array( | ||
| 'label' => ( '' !== $label ) ? $label : self::humanize_key( $dot_match['raw_key'] ), | ||
| 'type' => self::infer_array_item_type( $key, $item_data_type ), | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| $slug = isset( $entry['field']['slug'] ) ? sanitize_key( $entry['field']['slug'] ) : ''; | ||
| if ( '' === $slug ) { | ||
| $slug = sanitize_key( $placeholder ); | ||
| } | ||
|
|
||
| if ( '' === $slug ) { | ||
| continue; | ||
| } | ||
|
|
||
| $normalized_placeholder = ''; | ||
| if ( '' !== $placeholder ) { | ||
| $normalized_placeholder = preg_replace( '/[^A-Za-z0-9._:-]/', '', $placeholder ); | ||
| } | ||
| if ( '' === $label ) { | ||
| $source = '' !== $normalized_placeholder ? $normalized_placeholder : $slug; | ||
| $label = self::humanize_key( $source ); | ||
| } | ||
|
|
||
| if ( '' === $normalized_placeholder ) { | ||
| $normalized_placeholder = $slug; | ||
| } | ||
|
|
||
| if ( ! in_array( $data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $data_type = 'text'; | ||
| } | ||
|
|
||
| if ( in_array( $slug, array( 'onshow', 'ondata', 'block', 'var' ), true ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $scalar_fields[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'placeholder' => $normalized_placeholder, | ||
| 'data_type' => $data_type, | ||
| '_order' => $entry['index'], | ||
| ); | ||
| } | ||
|
|
||
| if ( ! empty( $array_defs ) ) { | ||
| uasort( | ||
| $array_defs, | ||
| static function ( $a, $b ) { | ||
| $order_a = isset( $a['_order'] ) ? intval( $a['_order'] ) : 0; | ||
| $order_b = isset( $b['_order'] ) ? intval( $b['_order'] ) : 0; | ||
| return $order_a <=> $order_b; | ||
| } | ||
| ); | ||
|
|
||
| foreach ( $array_defs as $base => $def ) { | ||
| unset( $def['_order'] ); | ||
| $schema[] = $def; | ||
| } | ||
| } | ||
|
|
||
| if ( ! empty( $scalar_fields ) ) { | ||
| usort( | ||
| $scalar_fields, | ||
| static function ( $a, $b ) { | ||
| $order_a = isset( $a['_order'] ) ? intval( $a['_order'] ) : 0; | ||
| $order_b = isset( $b['_order'] ) ? intval( $b['_order'] ) : 0; | ||
| return $order_a <=> $order_b; | ||
| } | ||
| ); | ||
|
|
||
| foreach ( $scalar_fields as $field ) { | ||
| unset( $field['_order'] ); | ||
| $field['type'] = 'textarea'; | ||
| $schema[] = $field; | ||
| } | ||
| } | ||
|
|
||
| return $schema; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| public static function build_schema_from_field_definitions( $fields ) { | ||
| if ( ! is_array( $fields ) ) { | ||
| return array(); | ||
| } | ||
|
|
||
| $array_defs = array(); | ||
| $array_order = array(); | ||
| $repeat_hints = array(); | ||
| $pending = array(); | ||
| $order_counter = 0; | ||
|
|
||
| foreach ( $fields as $index => $field ) { | ||
| if ( ! is_array( $field ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $placeholder = isset( $field['placeholder'] ) ? trim( (string) $field['placeholder'] ) : ''; | ||
| $parameters = isset( $field['parameters'] ) && is_array( $field['parameters'] ) ? $field['parameters'] : array(); | ||
| $label = isset( $field['label'] ) ? sanitize_text_field( $field['label'] ) : ''; | ||
| $data_type = isset( $field['data_type'] ) ? sanitize_key( $field['data_type'] ) : 'text'; | ||
|
|
||
| $array_match = self::detect_array_placeholder_with_index( $placeholder ); | ||
| if ( $array_match ) { | ||
| $base = $array_match['base']; | ||
| $key = $array_match['key']; | ||
|
|
||
| if ( '' === $base || '' === $key ) { | ||
| continue; | ||
| } | ||
|
|
||
| $repeat_hints[ $base ] = true; | ||
|
|
||
| if ( ! isset( $array_defs[ $base ] ) ) { | ||
| $array_defs[ $base ] = array( | ||
| 'slug' => $base, | ||
| 'label' => self::humanize_key( $base ), | ||
| 'type' => 'array', | ||
| 'placeholder' => $base, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => array(), | ||
| '_order' => $order_counter++, | ||
| ); | ||
| $array_order[] = $base; | ||
| } | ||
|
|
||
| if ( '' === $label ) { | ||
| $label = self::humanize_key( $array_match['raw_key'] ); | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ]['item_schema'][ $key ] ) ) { | ||
| $item_data_type = self::detect_data_type( $placeholder, $parameters ); | ||
| if ( '' === $item_data_type ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
|
|
||
| $array_defs[ $base ]['item_schema'][ $key ] = array( | ||
| 'label' => $label, | ||
| 'type' => self::infer_array_item_type( $key, $item_data_type ), | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| if ( isset( $parameters['repeat'] ) ) { | ||
| $repeat_base = sanitize_key( $parameters['repeat'] ); | ||
| if ( '' !== $repeat_base ) { | ||
| $repeat_hints[ $repeat_base ] = true; | ||
| } | ||
| } | ||
|
|
||
| $pending[] = array( | ||
| 'field' => $field, | ||
| 'placeholder' => $placeholder, | ||
| 'parameters' => $parameters, | ||
| 'label' => $label, | ||
| 'data_type' => $data_type, | ||
| 'index' => $index, | ||
| ); | ||
| } | ||
|
|
||
| $schema = array(); | ||
| $scalar_fields = array(); | ||
|
|
||
| foreach ( $pending as $entry ) { | ||
| $placeholder = $entry['placeholder']; | ||
| $parameters = $entry['parameters']; | ||
| $label = $entry['label']; | ||
| $data_type = $entry['data_type']; | ||
|
|
||
| $dot_match = self::detect_array_placeholder_without_index( $placeholder ); | ||
| if ( $dot_match && ( isset( $repeat_hints[ $dot_match['base'] ] ) || isset( $array_defs[ $dot_match['base'] ] ) ) ) { | ||
| $base = $dot_match['base']; | ||
| $key = $dot_match['key']; | ||
|
|
||
| if ( '' === $base || '' === $key ) { | ||
| continue; | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ] ) ) { | ||
| $array_defs[ $base ] = array( | ||
| 'slug' => $base, | ||
| 'label' => self::humanize_key( $base ), | ||
| 'type' => 'array', | ||
| 'placeholder' => $base, | ||
| 'data_type' => 'array', | ||
| 'item_schema' => array(), | ||
| '_order' => $order_counter++, | ||
| ); | ||
| $array_order[] = $base; | ||
| } | ||
|
|
||
| if ( ! isset( $array_defs[ $base ]['item_schema'][ $key ] ) ) { | ||
| $item_data_type = self::detect_data_type( $placeholder, $parameters ); | ||
| if ( '' === $label ) { | ||
| $label = self::humanize_key( $dot_match['raw_key'] ); | ||
| } | ||
| if ( '' === $item_data_type ) { | ||
| $item_data_type = 'text'; | ||
| } | ||
| $array_defs[ $base ]['item_schema'][ $key ] = array( | ||
| 'label' => ( '' !== $label ) ? $label : self::humanize_key( $dot_match['raw_key'] ), | ||
| 'type' => self::infer_array_item_type( $key, $item_data_type ), | ||
| 'data_type' => $item_data_type, | ||
| ); | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| $slug = isset( $entry['field']['slug'] ) ? sanitize_key( $entry['field']['slug'] ) : ''; | ||
| if ( '' === $slug ) { | ||
| $slug = sanitize_key( $placeholder ); | ||
| } | ||
|
|
||
| if ( '' === $slug ) { | ||
| continue; | ||
| } | ||
|
|
||
| $normalized_placeholder = ''; | ||
| if ( '' !== $placeholder ) { | ||
| $normalized_placeholder = preg_replace( '/[^A-Za-z0-9._:-]/', '', $placeholder ); | ||
| } | ||
| if ( '' === $label ) { | ||
| $source = '' !== $normalized_placeholder ? $normalized_placeholder : $slug; | ||
| $label = self::humanize_key( $source ); | ||
| } | ||
|
|
||
| if ( '' === $normalized_placeholder ) { | ||
| $normalized_placeholder = $slug; | ||
| } | ||
|
|
||
| if ( ! in_array( $data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $data_type = 'text'; | ||
| } | ||
|
|
||
| if ( in_array( $slug, array( 'onshow', 'ondata', 'block', 'var' ), true ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $scalar_fields[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'placeholder' => $normalized_placeholder, | ||
| 'data_type' => $data_type, | ||
| '_order' => $entry['index'], | ||
| ); | ||
| } | ||
|
|
||
| if ( ! empty( $array_defs ) ) { | ||
| uasort( | ||
| $array_defs, | ||
| static function ( $a, $b ) { | ||
| $order_a = isset( $a['_order'] ) ? intval( $a['_order'] ) : 0; | ||
| $order_b = isset( $b['_order'] ) ? intval( $b['_order'] ) : 0; | ||
| return $order_a <=> $order_b; | ||
| } | ||
| ); | ||
|
|
||
| foreach ( $array_defs as $base => $def ) { | ||
| unset( $def['_order'] ); | ||
| $schema[] = $def; | ||
| } | ||
| } | ||
|
|
||
| if ( ! empty( $scalar_fields ) ) { | ||
| usort( | ||
| $scalar_fields, | ||
| static function ( $a, $b ) { | ||
| $order_a = isset( $a['_order'] ) ? intval( $a['_order'] ) : 0; | ||
| $order_b = isset( $b['_order'] ) ? intval( $b['_order'] ) : 0; | ||
| return $order_a <=> $order_b; | ||
| } | ||
| ); | ||
|
|
||
| foreach ( $scalar_fields as $field ) { | ||
| unset( $field['_order'] ); | ||
| $field['type'] = 'textarea'; | ||
| $schema[] = $field; | ||
| } | ||
| } | ||
|
|
||
| return $schema; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: NPathComplexity Warning
| private function normalize_array_item_schema( $definition ) { | ||
| $schema = array(); | ||
|
|
||
| if ( isset( $definition['item_schema'] ) && is_array( $definition['item_schema'] ) ) { | ||
| foreach ( $definition['item_schema'] as $key => $item ) { | ||
| $item_key = sanitize_key( $key ); | ||
| if ( '' === $item_key ) { | ||
| continue; | ||
| } | ||
|
|
||
| $label = isset( $item['label'] ) ? sanitize_text_field( $item['label'] ) : $this->humanize_unknown_field_label( $item_key ); | ||
| $type = isset( $item['type'] ) ? sanitize_key( $item['type'] ) : 'textarea'; | ||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
|
|
||
| $data_type = isset( $item['data_type'] ) ? sanitize_key( $item['data_type'] ) : 'text'; | ||
| if ( ! in_array( $data_type, array( 'text', 'number', 'boolean', 'date' ), true ) ) { | ||
| $data_type = 'text'; | ||
| } | ||
|
|
||
| $schema[ $item_key ] = array( | ||
| 'label' => $label, | ||
| 'type' => $type, | ||
| 'data_type' => $data_type, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { | ||
| return; | ||
| if ( empty( $schema ) ) { | ||
| $schema['content'] = array( | ||
| 'label' => __( 'Contenido', 'resolate' ), | ||
| 'type' => 'textarea', | ||
| 'data_type' => 'text', | ||
| ); | ||
| } | ||
|
|
||
| if ( ! current_user_can( 'edit_post', $post_id ) ) { | ||
| return; | ||
| return $schema; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| 'type' => 'textarea', | ||
| 'data_type' => 'text', | ||
| ); | ||
| } | ||
|
|
||
| if ( ! current_user_can( 'edit_post', $post_id ) ) { | ||
| return; | ||
| return $schema; | ||
| } | ||
|
|
||
| /** | ||
| * Render an array field with repeatable items. | ||
| * | ||
| * @param string $slug Field slug. | ||
| * @param string $label Field label. | ||
| * @param array $item_schema Item schema definition. | ||
| * @param array $items Current values. | ||
| * @return void | ||
| */ | ||
| private function render_array_field( $slug, $label, $item_schema, $items ) { | ||
| $slug = sanitize_key( $slug ); | ||
| $label = sanitize_text_field( $label ); | ||
| $field_id = 'resolate-array-' . $slug; | ||
| $items = is_array( $items ) ? $items : array(); | ||
| $item_schema = is_array( $item_schema ) ? $item_schema : array(); | ||
|
|
||
| echo '<div class="resolate-array-field" data-array-field="' . esc_attr( $slug ) . '" style="margin-bottom:24px;">'; | ||
| echo '<div class="resolate-array-heading" style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;gap:12px;">'; | ||
| echo '<span class="resolate-array-title" style="font-weight:600;font-size:15px;">' . esc_html( $label ) . '</span>'; | ||
| echo '<button type="button" class="button button-secondary resolate-array-add" data-array-target="' . esc_attr( $slug ) . '">' . esc_html__( 'Añadir elemento', 'resolate' ) . '</button>'; | ||
| echo '</div>'; | ||
|
|
||
| echo '<div class="resolate-array-items" id="' . esc_attr( $field_id ) . '" data-field="' . esc_attr( $slug ) . '">'; | ||
| foreach ( $items as $index => $values ) { | ||
| $values = is_array( $values ) ? $values : array(); | ||
| $this->render_array_field_item( $slug, (string) $index, $item_schema, $values ); | ||
| } | ||
| echo '</div>'; | ||
|
|
||
| // Handle type selection (lock after set). | ||
| if ( isset( $_POST['resolate_type_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['resolate_type_nonce'] ) ), 'resolate_type_nonce' ) ) { | ||
| $posted = isset( $_POST['resolate_doc_type'] ) ? intval( $_POST['resolate_doc_type'] ) : 0; | ||
| $assigned = wp_get_post_terms( $post_id, 'resolate_doc_type', array( 'fields' => 'ids' ) ); | ||
| $current = ( ! is_wp_error( $assigned ) && ! empty( $assigned ) ) ? intval( $assigned[0] ) : 0; | ||
| if ( $current <= 0 && $posted > 0 ) { | ||
| wp_set_post_terms( $post_id, array( $posted ), 'resolate_doc_type', false ); | ||
| echo '<template class="resolate-array-template" data-field="' . esc_attr( $slug ) . '">'; | ||
| $this->render_array_field_item( $slug, '__INDEX__', $item_schema, array(), true ); | ||
| echo '</template>'; | ||
| echo '</div>'; | ||
| } | ||
|
|
||
| /** | ||
| * Render a single repeatable array item row. | ||
| * | ||
| * @param string $slug Field slug. | ||
| * @param string $index Item index. | ||
| * @param array $item_schema Item schema definition. | ||
| * @param array $values Current values. | ||
| * @param bool $is_template Whether the row is a template placeholder. | ||
| * @return void |
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| 'type' => 'textarea', | ||
| 'data_type' => 'text', | ||
| ); | ||
| } | ||
|
|
||
| if ( ! current_user_can( 'edit_post', $post_id ) ) { | ||
| return; | ||
| return $schema; | ||
| } | ||
|
|
||
| /** | ||
| * Render an array field with repeatable items. | ||
| * | ||
| * @param string $slug Field slug. | ||
| * @param string $label Field label. | ||
| * @param array $item_schema Item schema definition. | ||
| * @param array $items Current values. | ||
| * @return void | ||
| */ | ||
| private function render_array_field( $slug, $label, $item_schema, $items ) { | ||
| $slug = sanitize_key( $slug ); | ||
| $label = sanitize_text_field( $label ); | ||
| $field_id = 'resolate-array-' . $slug; | ||
| $items = is_array( $items ) ? $items : array(); | ||
| $item_schema = is_array( $item_schema ) ? $item_schema : array(); | ||
|
|
||
| echo '<div class="resolate-array-field" data-array-field="' . esc_attr( $slug ) . '" style="margin-bottom:24px;">'; | ||
| echo '<div class="resolate-array-heading" style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;gap:12px;">'; | ||
| echo '<span class="resolate-array-title" style="font-weight:600;font-size:15px;">' . esc_html( $label ) . '</span>'; | ||
| echo '<button type="button" class="button button-secondary resolate-array-add" data-array-target="' . esc_attr( $slug ) . '">' . esc_html__( 'Añadir elemento', 'resolate' ) . '</button>'; | ||
| echo '</div>'; | ||
|
|
||
| echo '<div class="resolate-array-items" id="' . esc_attr( $field_id ) . '" data-field="' . esc_attr( $slug ) . '">'; | ||
| foreach ( $items as $index => $values ) { | ||
| $values = is_array( $values ) ? $values : array(); | ||
| $this->render_array_field_item( $slug, (string) $index, $item_schema, $values ); | ||
| } | ||
| echo '</div>'; | ||
|
|
||
| // Handle type selection (lock after set). | ||
| if ( isset( $_POST['resolate_type_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['resolate_type_nonce'] ) ), 'resolate_type_nonce' ) ) { | ||
| $posted = isset( $_POST['resolate_doc_type'] ) ? intval( $_POST['resolate_doc_type'] ) : 0; | ||
| $assigned = wp_get_post_terms( $post_id, 'resolate_doc_type', array( 'fields' => 'ids' ) ); | ||
| $current = ( ! is_wp_error( $assigned ) && ! empty( $assigned ) ) ? intval( $assigned[0] ) : 0; | ||
| if ( $current <= 0 && $posted > 0 ) { | ||
| wp_set_post_terms( $post_id, array( $posted ), 'resolate_doc_type', false ); | ||
| echo '<template class="resolate-array-template" data-field="' . esc_attr( $slug ) . '">'; | ||
| $this->render_array_field_item( $slug, '__INDEX__', $item_schema, array(), true ); | ||
| echo '</template>'; | ||
| echo '</div>'; | ||
| } | ||
|
|
||
| /** | ||
| * Render a single repeatable array item row. | ||
| * | ||
| * @param string $slug Field slug. | ||
| * @param string $index Item index. | ||
| * @param array $item_schema Item schema definition. | ||
| * @param array $values Current values. | ||
| * @param bool $is_template Whether the row is a template placeholder. | ||
| * @return void |
Check warning
Code scanning / PHPMD
Code Size Rules: NPathComplexity Warning
| private function render_array_field_item( $slug, $index, $item_schema, $values, $is_template = false ) { | ||
| $slug = sanitize_key( $slug ); | ||
| $index_attr = (string) $index; | ||
| $item_schema = is_array( $item_schema ) ? $item_schema : array(); | ||
| $values = is_array( $values ) ? $values : array(); | ||
|
|
||
| echo '<div class="resolate-array-item" data-index="' . esc_attr( $index_attr ) . '" draggable="true" style="border:1px solid #e5e5e5;padding:16px;margin-bottom:12px;background:#fff;">'; | ||
| echo '<div class="resolate-array-item-toolbar" style="display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px;">'; | ||
| echo '<span class="resolate-array-handle" role="button" tabindex="0" aria-label="' . esc_attr__( 'Mover elemento', 'resolate' ) . '" style="cursor:move;user-select:none;">≡</span>'; | ||
| echo '<button type="button" class="button-link-delete resolate-array-remove">' . esc_html__( 'Eliminar', 'resolate' ) . '</button>'; | ||
| echo '</div>'; | ||
|
|
||
| foreach ( $item_schema as $key => $definition ) { | ||
| $item_key = sanitize_key( $key ); | ||
| if ( '' === $item_key ) { | ||
| continue; | ||
| } | ||
|
|
||
| $field_name = 'tpl_fields[' . $slug . '][' . $index_attr . '][' . $item_key . ']'; | ||
| $field_id = 'resolate-' . $slug . '-' . $item_key . '-' . $index_attr; | ||
| $label = isset( $definition['label'] ) ? sanitize_text_field( $definition['label'] ) : $this->humanize_unknown_field_label( $item_key ); | ||
| $type = isset( $definition['type'] ) ? sanitize_key( $definition['type'] ) : 'textarea'; | ||
| $value = isset( $values[ $item_key ] ) ? (string) $values[ $item_key ] : ''; | ||
|
|
||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
|
|
||
| echo '<div class="resolate-array-field-control" style="margin-bottom:12px;">'; | ||
| echo '<label for="' . esc_attr( $field_id ) . '" style="font-weight:600;display:block;margin-bottom:4px;">' . esc_html( $label ) . '</label>'; | ||
|
|
||
| if ( 'single' === $type ) { | ||
| echo '<input type="text" class="widefat" id="' . esc_attr( $field_id ) . '" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $value ) . '" />'; | ||
| } else { | ||
| $rows = ( 'rich' === $type ) ? 8 : 4; | ||
| echo '<textarea class="widefat" rows="' . esc_attr( (string) $rows ) . '" id="' . esc_attr( $field_id ) . '" name="' . esc_attr( $field_name ) . '">' . esc_textarea( $value ) . '</textarea>'; | ||
| } | ||
|
|
||
| echo '</div>'; | ||
| } | ||
|
|
||
| echo '</div>'; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: CyclomaticComplexity Warning
| private function render_array_field_item( $slug, $index, $item_schema, $values, $is_template = false ) { | ||
| $slug = sanitize_key( $slug ); | ||
| $index_attr = (string) $index; | ||
| $item_schema = is_array( $item_schema ) ? $item_schema : array(); | ||
| $values = is_array( $values ) ? $values : array(); | ||
|
|
||
| echo '<div class="resolate-array-item" data-index="' . esc_attr( $index_attr ) . '" draggable="true" style="border:1px solid #e5e5e5;padding:16px;margin-bottom:12px;background:#fff;">'; | ||
| echo '<div class="resolate-array-item-toolbar" style="display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px;">'; | ||
| echo '<span class="resolate-array-handle" role="button" tabindex="0" aria-label="' . esc_attr__( 'Mover elemento', 'resolate' ) . '" style="cursor:move;user-select:none;">≡</span>'; | ||
| echo '<button type="button" class="button-link-delete resolate-array-remove">' . esc_html__( 'Eliminar', 'resolate' ) . '</button>'; | ||
| echo '</div>'; | ||
|
|
||
| foreach ( $item_schema as $key => $definition ) { | ||
| $item_key = sanitize_key( $key ); | ||
| if ( '' === $item_key ) { | ||
| continue; | ||
| } | ||
|
|
||
| $field_name = 'tpl_fields[' . $slug . '][' . $index_attr . '][' . $item_key . ']'; | ||
| $field_id = 'resolate-' . $slug . '-' . $item_key . '-' . $index_attr; | ||
| $label = isset( $definition['label'] ) ? sanitize_text_field( $definition['label'] ) : $this->humanize_unknown_field_label( $item_key ); | ||
| $type = isset( $definition['type'] ) ? sanitize_key( $definition['type'] ) : 'textarea'; | ||
| $value = isset( $values[ $item_key ] ) ? (string) $values[ $item_key ] : ''; | ||
|
|
||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
|
|
||
| echo '<div class="resolate-array-field-control" style="margin-bottom:12px;">'; | ||
| echo '<label for="' . esc_attr( $field_id ) . '" style="font-weight:600;display:block;margin-bottom:4px;">' . esc_html( $label ) . '</label>'; | ||
|
|
||
| if ( 'single' === $type ) { | ||
| echo '<input type="text" class="widefat" id="' . esc_attr( $field_id ) . '" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $value ) . '" />'; | ||
| } else { | ||
| $rows = ( 'rich' === $type ) ? 8 : 4; | ||
| echo '<textarea class="widefat" rows="' . esc_attr( (string) $rows ) . '" id="' . esc_attr( $field_id ) . '" name="' . esc_attr( $field_name ) . '">' . esc_textarea( $value ) . '</textarea>'; | ||
| } | ||
|
|
||
| echo '</div>'; | ||
| } | ||
|
|
||
| echo '</div>'; | ||
| } |
Check warning
Code scanning / PHPMD
Code Size Rules: NPathComplexity Warning
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting
| if ( ! is_array( $item ) ) { | ||
| continue; | ||
| } | ||
| $slug = isset( $item['slug'] ) ? sanitize_key( $item['slug'] ) : ''; | ||
| $label = isset( $item['label'] ) ? sanitize_text_field( $item['label'] ) : ''; | ||
| $type = isset( $item['type'] ) ? sanitize_key( $item['type'] ) : 'textarea'; | ||
| $placeholder = isset( $item['placeholder'] ) ? preg_replace( '/[^A-Za-z0-9._:-]/', '', (string) $item['placeholder'] ) : ''; | ||
| $data_type = isset( $item['data_type'] ) ? sanitize_key( $item['data_type'] ) : ''; | ||
| if ( '' === $slug || '' === $label ) { | ||
| continue; | ||
| } | ||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
| $out[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => $type, | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => $data_type, | ||
| ); | ||
| } | ||
| return $out; | ||
| } | ||
| $slug = isset( $item['slug'] ) ? sanitize_key( $item['slug'] ) : ''; | ||
| $label = isset( $item['label'] ) ? sanitize_text_field( $item['label'] ) : ''; | ||
| $type = isset( $item['type'] ) ? sanitize_key( $item['type'] ) : 'textarea'; | ||
| $placeholder = isset( $item['placeholder'] ) ? preg_replace( '/[^A-Za-z0-9._:-]/', '', (string) $item['placeholder'] ) : ''; | ||
| $data_type = isset( $item['data_type'] ) ? sanitize_key( $item['data_type'] ) : ''; | ||
| if ( '' === $slug || '' === $label ) { | ||
| continue; | ||
| } | ||
| if ( ! in_array( $type, array( 'single', 'textarea', 'rich' ), true ) ) { | ||
| $type = 'textarea'; | ||
| } | ||
| $out[] = array( | ||
| 'slug' => $slug, | ||
| 'label' => $label, | ||
| 'type' => $type, | ||
| 'placeholder' => $placeholder, | ||
| 'data_type' => $data_type, |
There was a problem hiding this comment.
Preserve array field type when loading schema
The new repeatable array feature relies on schema entries whose type is 'array' so filter_post_data_compose_content() and Resolate_Document_Generator::build_merge_fields() can JSON‑encode posted items and decode them for template merges. However, get_term_schema() still normalizes every field type to one of single|textarea|rich and forcibly rewrites anything else to 'textarea'. When a template defines an array field and the schema is saved, this method returns it as a textarea, so the later code never enters the array branch and ignores values submitted in tpl_fields[...]. As a result array data is never persisted or exported unless the schema is manually patched. Include 'array' in the allowed types and keep the original item_schema so array fields can be recognized downstream.
Useful? React with 👍 / 👎.
Summary
Testing
composer test(fails: missing WordPress native test bootstrap)./vendor/bin/phpcs --standard=.phpcs.xml.dist .https://chatgpt.com/codex/tasks/task_e_68ee30cf252083229149dd9f656091e1