db = $db ?? $GLOBALS['wpdb']; } /** * Listing the meta keys available as mapping targets. * * @param string $post_type Post type to inspect. * * @return string[] Meta keys, alphabetically. */ public function meta_keys( string $post_type = 'post' ): array { $cached = get_transient( self::CACHE_KEY . '_' . $post_type ); if ( is_array( $cached ) ) { return $cached; } $keys = $this->discover( $post_type ); set_transient( self::CACHE_KEY . '_' . $post_type, $keys, self::CACHE_TTL ); return $keys; } /** * Asking the database which meta keys exist on a post type. * * @param string $post_type Post type to inspect. * * @return string[] Meta keys, alphabetically. */ private function discover( string $post_type ): array { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- No core API for this; cached by the caller. $keys = $this->db->get_col( $this->db->prepare( 'SELECT DISTINCT meta.meta_key FROM %i AS meta' . ' INNER JOIN %i AS posts ON posts.ID = meta.post_id' . ' WHERE posts.post_type = %s AND meta.meta_key NOT LIKE %s' . ' ORDER BY meta.meta_key ASC LIMIT %d', $this->db->postmeta, $this->db->posts, $post_type, $this->db->esc_like( '_' ) . '%', self::LIMIT ) ); if ( ! is_array( $keys ) ) { return array(); } return array_values( array_filter( array_map( 'strval', $keys ), static fn ( string $key ): bool => '' !== $key && ! self::is_own_key( $key ) ) ); } /** * Checking whether a meta key belongs to this plugin or its predecessor. * * @param string $key Meta key. * * @return bool Whether the key is one of ours. */ private static function is_own_key( string $key ): bool { if ( Str::starts_with( $key, Options::PREFIX ) ) { return true; } return in_array( $key, MetaKeys::legacy_post_meta(), true ); } }