true, 'show_in_rest' => false, 'auth_callback' => static fn ( $allowed, $meta_key, $post_id ): bool => current_user_can( 'edit_post', (int) $post_id ), ) ); } } /** * Tabs of a product, in display order. * * @param int $product_id Product id. * @return list */ public function tabs( int $product_id ): array { return TabSanitizer::product_tabs( get_post_meta( $product_id, self::META_TABS, true ), true ); } /** * Global tab ids hidden on a product. * * @param int $product_id Product id. * @return list */ public function hidden_globals( int $product_id ): array { return TabSanitizer::id_list( get_post_meta( $product_id, self::META_HIDDEN_GLOBALS, true ) ); } /** * Default WooCommerce tab keys hidden on a product. * * @param int $product_id Product id. * @return list */ public function hidden_defaults( int $product_id ): array { return self::default_keys( get_post_meta( $product_id, self::META_HIDDEN_DEFAULTS, true ) ); } /** * Store the tabs of a product (already sanitised); empty data removes the meta row. * * @param int $product_id Product id. * @param list $tabs Tabs. * @param list $hidden_globals Hidden global tabs. * @param list $hidden_defaults Hidden default tabs. */ public function save( int $product_id, array $tabs, array $hidden_globals, array $hidden_defaults ): void { self::put( $product_id, self::META_TABS, $tabs ); self::put( $product_id, self::META_HIDDEN_GLOBALS, $hidden_globals ); self::put( $product_id, self::META_HIDDEN_DEFAULTS, self::default_keys( $hidden_defaults ) ); } /** * Write or delete one meta value. Slashes are added because update_post_meta() unslashes. * * @param int $product_id Product id. * @param string $key Meta key. * @param array $value Value. */ private static function put( int $product_id, string $key, array $value ): void { if ( array() === $value ) { delete_post_meta( $product_id, $key ); return; } update_post_meta( $product_id, $key, wp_slash( $value ) ); } /** * Valid default tab keys from untrusted input. * * @param mixed $raw Value. * @return list */ public static function default_keys( mixed $raw ): array { if ( ! is_array( $raw ) ) { return array(); } return array_values( array_intersect( DefaultTabs::KEYS, array_map( static fn ( $v ): string => is_scalar( $v ) ? (string) $v : '', $raw ) ) ); } }