From 983e7d137ae31dc0bc259497cdbac97547386321 Mon Sep 17 00:00:00 2001 From: Pichinov-Jose Date: Sat, 5 Sep 2026 21:20:34 +0200 Subject: [PATCH 1/2] Make the custom fields limit configurable (setting + filter) The number of custom fields exposed per object type is capped by the hard-coded CustomFields::MAX_FIELDS = 200. Sites relying heavily on custom fields (ACF & similar) silently lose every field past the cap: the fields disappear from the schema and any mapping bound to them stops syncing, with nothing to raise the limit. Keep 200 as the default and make the limit configurable: - CustomFields::getLimit() reads the new "Custom Fields Limit" setting (option splash_custom_fields_limit) and passes it through a splash_custom_fields_limit filter, falling back to MAX_FIELDS; - the custom fields parser and the settings page descriptions use the effective limit instead of the constant. Measured on a live catalog with ~500 eligible fields: schema builds in under 400 ms with a limit of 1200, for a ~300 KB serialized schema. Co-Authored-By: Claude Fable 5 --- includes/class-splash-wordpress-settings.php | 18 +++++++++++++----- src/Dictionary/CustomFields.php | 19 ++++++++++++++++++- src/Objects/Post/CustomTrait.php | 2 +- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/includes/class-splash-wordpress-settings.php b/includes/class-splash-wordpress-settings.php index 8209977..beeecb3 100644 --- a/includes/class-splash-wordpress-settings.php +++ b/includes/class-splash-wordpress-settings.php @@ -467,10 +467,18 @@ private function settings_fields() array( 'id' => 'cf_product', 'label' => __('Custom Fields', 'splash-wordpress-plugin'), - 'description' => sprintf(__('Enable Custom Fields for Products. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'description' => sprintf(__('Enable Custom Fields for Products. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::getLimit()), 'type' => 'checkbox', 'default' => '1' ), + array( + 'id' => 'custom_fields_limit', + 'label' => __('Custom Fields Limit', 'splash-wordpress-plugin'), + 'description' => sprintf(__('Maximum number of custom fields exposed per object type. Raise it if your site defines many custom fields (ACF & similar). Default: %d.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'type' => 'number', + 'default' => \Splash\Local\Dictionary\CustomFields::MAX_FIELDS, + 'placeholder' => (string) \Splash\Local\Dictionary\CustomFields::MAX_FIELDS + ), ) ); $settings['orders'] = array( @@ -486,13 +494,13 @@ private function settings_fields() ), array( 'id' => 'cf_order', 'label' => __('Orders Custom Fields', 'splash-wordpress-plugin'), - 'description' => sprintf(__('Enable Custom Fields for Orders. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'description' => sprintf(__('Enable Custom Fields for Orders. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::getLimit()), 'type' => 'checkbox', 'default' => '0' ), array( 'id' => 'cf_invoice', 'label' => __('Invoices Custom Fields', 'splash-wordpress-plugin'), - 'description' => sprintf(__('Enable Custom Fields for Invoices. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'description' => sprintf(__('Enable Custom Fields for Invoices. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::getLimit()), 'type' => 'checkbox', 'default' => '0' ), array( @@ -532,13 +540,13 @@ private function settings_fields() array( 'id' => 'cf_post', 'label' => __('Posts Custom Fields', 'splash-wordpress-plugin'), - 'description' => sprintf(__('Enable Custom Fields for Posts. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'description' => sprintf(__('Enable Custom Fields for Posts. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::getLimit()), 'type' => 'checkbox', 'default' => '0' ), array( 'id' => 'cf_page', 'label' => __('Pages Custom Fields', 'splash-wordpress-plugin'), - 'description' => sprintf(__('Enable Custom Fields for Pages. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::MAX_FIELDS), + 'description' => sprintf(__('Enable Custom Fields for Pages. Limited to the first %d custom fields.', 'splash-wordpress-plugin'), \Splash\Local\Dictionary\CustomFields::getLimit()), 'type' => 'checkbox', 'default' => '0' ), diff --git a/src/Dictionary/CustomFields.php b/src/Dictionary/CustomFields.php index 91c6ae4..1671025 100644 --- a/src/Dictionary/CustomFields.php +++ b/src/Dictionary/CustomFields.php @@ -21,7 +21,24 @@ class CustomFields { /** - * Maximum Number of Custom Fields Exposed per Object Type + * Default Maximum Number of Custom Fields Exposed per Object Type */ public const MAX_FIELDS = 200; + + /** + * Get Maximum Number of Custom Fields Exposed per Object Type + * + * Sites with many custom fields (ACF & similar) can raise the limit from + * the plugin settings page (Custom Fields Limit) or via the + * splash_custom_fields_limit filter. Defaults to MAX_FIELDS. + * + * @return int + */ + public static function getLimit(): int + { + $limit = (int) get_option('splash_custom_fields_limit', self::MAX_FIELDS); + $limit = (int) apply_filters('splash_custom_fields_limit', ($limit > 0) ? $limit : self::MAX_FIELDS); + + return ($limit > 0) ? $limit : self::MAX_FIELDS; + } } diff --git a/src/Objects/Post/CustomTrait.php b/src/Objects/Post/CustomTrait.php index 59cd703..9467317 100644 --- a/src/Objects/Post/CustomTrait.php +++ b/src/Objects/Post/CustomTrait.php @@ -69,7 +69,7 @@ protected function buildCustomFields(): void } //====================================================================// // Limit max Number of Custom Fields - if (\Splash\Local\Dictionary\CustomFields::MAX_FIELDS <= count($metaKeys)) { + if (\Splash\Local\Dictionary\CustomFields::getLimit() <= count($metaKeys)) { unset($metaKeys[ $index ]); } } From ffd114b5a74f65b36e4c9aa7f00bdd7ac83d6a99 Mon Sep 17 00:00:00 2001 From: Pichinov-Jose Date: Sun, 6 Sep 2026 04:13:30 +0200 Subject: [PATCH 2/2] Scope custom fields discovery to the object's own post type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WordPress get_meta_keys() scans the whole postmeta table, so every object type was offered every meta of the site: order metas showed up as Product custom fields, and meta keys with invalid identifiers (spaces) triggered schema warnings on unrelated objects. Restrict discovery to the metas actually attached to the object's post type — 'product' also includes its variations. Objects without a known post type keep the legacy site-wide behaviour. Co-Authored-By: Claude Fable 5 --- src/Objects/Post/CustomTrait.php | 49 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/Objects/Post/CustomTrait.php b/src/Objects/Post/CustomTrait.php index 9467317..e54cf5e 100644 --- a/src/Objects/Post/CustomTrait.php +++ b/src/Objects/Post/CustomTrait.php @@ -45,14 +45,10 @@ protected function buildCustomFields(): void if (!get_option("splash_cf_".$shortClass)) { return; } - //====================================================================// - // Require Posts Functions - require_once(ABSPATH."wp-admin/includes/post.php"); - //====================================================================// // Load List of Custom Fields /** @var string[] $metaKeys */ - $metaKeys = get_meta_keys(); + $metaKeys = $this->getObjectMetaKeys(); //====================================================================// // Filter List of Custom Fields @@ -93,6 +89,49 @@ protected function buildCustomFields(): void } } + /** + * Get Distinct Meta Keys used by this Object's Post Type + * + * WordPress core get_meta_keys() scans the whole postmeta table, so every + * object type was offered every meta of the site: order metas showed up as + * Product custom fields, and metas with invalid identifiers triggered + * schema warnings on unrelated objects. Restrict discovery to the metas + * actually attached to this object's post type ("product" also includes + * its variations). Objects without a known post type keep the legacy + * site-wide behaviour. + * + * @return string[] + */ + private function getObjectMetaKeys(): array + { + global $wpdb; + + $postType = isset($this->postType) ? (string) $this->postType : ""; + if ("" === $postType) { + //====================================================================// + // Legacy Mode => Site Wide Discovery + require_once(ABSPATH."wp-admin/includes/post.php"); + + /** @var string[] $metaKeys */ + $metaKeys = get_meta_keys(); + + return $metaKeys; + } + $postTypes = array($postType); + if ("product" === $postType) { + $postTypes[] = "product_variation"; + } + /** @var string[] $metaKeys */ + $metaKeys = $wpdb->get_col(sprintf( + "SELECT DISTINCT pm.meta_key FROM %s pm JOIN %s p ON p.ID = pm.post_id WHERE p.post_type IN ('%s') ORDER BY pm.meta_key", + $wpdb->postmeta, + $wpdb->posts, + implode("','", array_map("esc_sql", $postTypes)) + )); + + return $metaKeys; + } + //====================================================================// // Fields Reading Functions //====================================================================//