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..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 @@ -69,7 +65,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 ]); } } @@ -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 //====================================================================//