$post_data Post data being assembled. * @param array> $custom_fields Custom fields from Kordiam. * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return array|null Updated post data, or null to skip the story. */ public static function apply( array $post_data, array $custom_fields, string $scope = self::SCOPE_STORY ): ?array { foreach ( $custom_fields as $custom_field ) { $field_id = self::field_id( $custom_field ); if ( 0 === $field_id ) { continue; } $option_key = self::option_key( $field_id, $scope ); if ( Options::is_do_not_import( $option_key ) ) { return null; } $target = Options::get_string( $option_key ); if ( '' === $target || Options::is_no_sync( $option_key ) ) { continue; } $value = self::value_for( $custom_field, $scope ); if ( null === $value ) { continue; } $post_data = self::write( $post_data, $target, $value ); } return $post_data; } /** * Reading a custom field's Kordiam ID. * * @param array $custom_field Custom field data. * * @return int Field ID, or 0 when absent. */ public static function field_id( array $custom_field ): int { $field_id = $custom_field['customFieldId'] ?? null; return is_numeric( $field_id ) ? (int) $field_id : 0; } /** * Building the option key holding a field's mapping. * * @param int $field_id Kordiam field ID. * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return string Unprefixed option key. */ public static function option_key( int $field_id, string $scope = self::SCOPE_STORY ): string { $prefix = self::SCOPE_PUBLICATION === $scope ? 'publication_custom_field_import_' : 'custom_field_import_'; return $prefix . $field_id; } /** * Building the option key holding a scope's field definitions. * * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return string Unprefixed option key. */ public static function definitions_option_key( string $scope = self::SCOPE_STORY ): string { return self::SCOPE_PUBLICATION === $scope ? 'publication_custom_fields_list' : 'custom_fields_list'; } /** * Resolving the value a custom field contributes. * * @param array $custom_field Custom field data. * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return string|null The value, or null when it cannot be resolved. */ private static function value_for( array $custom_field, string $scope ): ?string { $type = isset( $custom_field['type'] ) && is_numeric( $custom_field['type'] ) ? (int) $custom_field['type'] : 0; if ( self::TYPE_TEXT === $type ) { $value = $custom_field['value'] ?? null; return is_scalar( $value ) && '' !== trim( (string) $value ) ? (string) $value : null; } if ( self::TYPE_SINGLE_SELECTION === $type ) { return self::selected_option_label( $custom_field, $scope ); } return null; } /** * Resolving a selection to the label of the option chosen. * * @param array $custom_field Custom field data. * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return string|null The label, or null when it cannot be resolved. */ private static function selected_option_label( array $custom_field, string $scope ): ?string { $selected = $custom_field['selectedOption'][0] ?? null; if ( ! is_numeric( $selected ) ) { return null; } $selected_id = (int) $selected; $field_id = self::field_id( $custom_field ); foreach ( self::definitions( $scope ) as $definition ) { if ( ! isset( $definition['id'] ) || ! is_numeric( $definition['id'] ) ) { continue; } if ( (int) $definition['id'] !== $field_id ) { continue; } $options = $definition['options'] ?? null; if ( ! is_array( $options ) ) { return null; } foreach ( $options as $option ) { if ( ! is_array( $option ) || ! isset( $option['id'] ) || ! is_numeric( $option['id'] ) ) { continue; } if ( (int) $option['id'] === $selected_id && isset( $option['name'] ) && is_scalar( $option['name'] ) ) { return (string) $option['name']; } } return null; } return null; } /** * Reading the cached field definitions for a scope. * * @param string $scope SCOPE_STORY or SCOPE_PUBLICATION. * * @return array> Definitions. */ private static function definitions( string $scope ): array { return CustomFieldRegistry::cached( $scope ); } /** * Writing a resolved value into post data (title, URL alias, or meta). * * @param array $post_data Post data being assembled. * @param string $target Mapping target. * @param string $value Value to write. * * @return array Updated post data. */ private static function write( array $post_data, string $target, string $value ): array { if ( 'title' === $target ) { $post_data['post_title'] = $value; return $post_data; } if ( 'url_alias' === $target ) { $sanitised = sanitize_title( $value ); if ( '' !== $sanitised ) { $post_data['post_name'] = $sanitised; } return $post_data; } if ( ! isset( $post_data['meta_input'] ) || ! is_array( $post_data['meta_input'] ) ) { $post_data['meta_input'] = array(); } // Unlike post_title and post_name, meta_input is not sanitised by WordPress. $post_data['meta_input'][ $target ] = MetaValue::sanitise( $value ); return $post_data; } }