PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.4.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.4.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / seo / class-global-seo-post-types.php

class-global-seo-post-types.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.4.0, at includes/seo/class-global-seo-post-types.php

104 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Global SEO Post Type Policy
4 *
5 * Single source of truth for which post types are valid Global SEO targets,
6 * shared by the admin post-type discovery (which populates the UI), the REST
7 * validator, and the MCP ability validator so all three agree. Previously the
8 * UI hid ineligible types while the write paths accepted any public type,
9 * letting direct REST/ability calls persist settings for types the UI
10 * classifies as unsuitable.
11 *
12 * @package ThinkRank
13 * @subpackage SEO
14 * @since 1.20.1
15 */
16
17 declare(strict_types=1);
18
19 namespace ThinkRank\SEO;
20
21 // Prevent direct access.
22 if (!defined('ABSPATH')) {
23 exit;
24 }
25
26 /**
27 * Global SEO post-type eligibility policy.
28 *
29 * @since 1.20.1
30 */
31 class Global_SEO_Post_Types {
32
33 /**
34 * Whether a post type may receive Global SEO settings.
35 *
36 * Policy: the type must be public; a non-built-in type must also be
37 * front-end viewable (excludes builder/utility CPTs that register
38 * `public => true` only for previews); and it must not be on the filterable
39 * `thinkrank_global_seo_excluded_post_types` deny list.
40 *
41 * @param \WP_Post_Type|string $post_type Post type object or name.
42 * @return bool
43 */
44 public static function is_allowed($post_type): bool {
45 $object = is_string($post_type) ? get_post_type_object($post_type) : $post_type;
46
47 if (!$object instanceof \WP_Post_Type || empty($object->public)) {
48 return false;
49 }
50
51 // Builder/utility CPTs that register public => true for preview purposes
52 // but aren't front-end viewable content (e.g. Elementor's "Floating
53 // Elements"). Built-in types (post/page/attachment) are always kept.
54 if ($object->_builtin === false && !is_post_type_viewable($object)) {
55 return false;
56 }
57
58 return !in_array($object->name, self::excluded_post_types($object), true);
59 }
60
61 /**
62 * Builder and utility CPTs that are not optimizable content.
63 *
64 * These register `public => true` for preview purposes but are layout
65 * fragments, not pages anyone gives a title and a meta description.
66 *
67 * Shared rather than duplicated: the per-post SEO metabox discovers post
68 * types by the same public/`show_ui` rule and used to keep its own
69 * exclusion list, which named only WordPress internals. The two policies
70 * disagreed — a builder template CPT was denied Global SEO while still
71 * getting a full metabox — so both now read this one list (#621).
72 *
73 * @since 2.2.1
74 *
75 * Deliberately untyped: this is passed straight to a public filter whose
76 * existing contract accepts whatever the caller has (a `WP_Post_Type`, or
77 * null when the list is wanted without a subject).
78 *
79 * @param mixed $post_type_object Post type being judged, passed to the filter.
80 * @return string[] Post type names to exclude.
81 */
82 public static function excluded_post_types($post_type_object = null): array {
83 // Filterable so integrators can tune it without patching core. The
84 // post-type object is passed as the second argument (matches the admin
85 // discovery filter usage).
86 $excluded = apply_filters('thinkrank_global_seo_excluded_post_types', [
87 'elementor_library', 'oceanwp_library', 'ae_global_templates',
88 'e-floating-buttons', 'elementor_component',
89 // Divi: the library plus every Theme Builder template type.
90 'et_pb_layout', 'et_theme_builder', 'et_template',
91 'et_header_layout', 'et_body_layout', 'et_footer_layout',
92 // Beaver Builder: saved templates (rows, columns, modules) and
93 // Beaver Themer's layouts. Same clutter Divi's Theme Builder
94 // templates caused before they were listed here (#449).
95 'fl-builder-template', 'fl-theme-layout',
96 // Bricks: saved templates plus the header/footer/section layouts
97 // its Theme Builder stores as the same CPT (#257).
98 'bricks_template',
99 ], $post_type_object);
100
101 return array_values(array_filter((array) $excluded, 'is_string'));
102 }
103 }
104