PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / includes / class-metasync-headless-seo-data.php

class-metasync-headless-seo-data.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.1, at includes/class-metasync-headless-seo-data.php

215 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A resolved SEO payload for one WordPress object.
4 *
5 * This is the object every headless delivery surface hands back. It is
6 * deliberately inert: the resolution work happens once, in
7 * Metasync_Headless_Seo_Surface, and what lands here is the finished value for
8 * every field. Getters read that state and nothing else.
9 *
10 * That split is the point. A field-by-field design — one function per field,
11 * each re-walking the fallback chain — costs a meta lookup per field and, worse,
12 * lets two fields disagree: a title resolved from OTTO alongside a canonical
13 * resolved from Yoast, because each looked independently. Resolving once and
14 * reading many times makes the payload internally consistent by construction,
15 * and matches how a GraphQL server resolves a type: parent once, then fields off
16 * the parent.
17 *
18 * Every value is already a string (or, for schema, decoded JSON), so a delivery
19 * layer never has to know which storage a value came from.
20 *
21 * @package Metasync
22 * @subpackage Metasync/includes
23 */
24
25 if (!defined('ABSPATH')) {
26 exit; # Exit if accessed directly
27 }
28
29 class Metasync_Headless_Seo_Data
30 {
31 /**
32 * Resolved values, keyed by field name. Always complete — see fields().
33 *
34 * @var array
35 */
36 private $values;
37
38 /**
39 * Every field this object carries, with the empty value for its type.
40 *
41 * A caller can rely on every key being present, so a delivery layer never
42 * has to distinguish "field missing" from "field empty". Nothing here is
43 * nullable: a missing string is '', a missing schema is an empty array.
44 *
45 * @return array
46 */
47 public static function fields()
48 {
49 return array(
50 # Core meta.
51 'title' => '',
52 'description' => '',
53 'keywords' => '',
54 'canonical' => '',
55 'robots' => '',
56
57 # Open Graph.
58 'og_title' => '',
59 'og_description' => '',
60 'og_image' => '',
61 'og_url' => '',
62 'og_type' => '',
63 'og_site_name' => '',
64 'og_locale' => '',
65
66 # Twitter.
67 'twitter_card' => '',
68 'twitter_title' => '',
69 'twitter_description' => '',
70 'twitter_image' => '',
71
72 # Structured data, decoded so a consumer does not have to parse a
73 # string that came out of post meta.
74 'schema' => array(),
75
76 # Where the frontend serves this object.
77 'public_url' => '',
78
79 # What this payload describes. Object type and id only — enough for a
80 # frontend to key a cache, and nothing a public endpoint should not
81 # be handing out.
82 'object_type' => '',
83 'object_id' => 0,
84 'object_sub_type' => '',
85 );
86 }
87
88 /**
89 * @param array $values Resolved values; missing keys fall back to the empty
90 * value for their field, unknown keys are dropped.
91 */
92 public function __construct(array $values = array())
93 {
94 $this->values = array();
95
96 foreach (self::fields() as $field => $empty) {
97 $this->values[$field] = array_key_exists($field, $values) ? $values[$field] : $empty;
98 }
99 }
100
101 /**
102 * One resolved field.
103 *
104 * @param string $field Field name from fields().
105 * @return mixed The resolved value, or null when the field does not exist.
106 */
107 public function get($field)
108 {
109 return array_key_exists($field, $this->values) ? $this->values[$field] : null;
110 }
111
112 /**
113 * Every resolved field.
114 *
115 * @return array
116 */
117 public function to_array()
118 {
119 return $this->values;
120 }
121
122 /* -----------------------------------------------------------------
123 * Named getters. Thin readers over already-resolved state — none of
124 * them consults post meta or re-runs a fallback chain.
125 * ----------------------------------------------------------------- */
126
127 /** @return string */
128 public function get_title()
129 {
130 return (string) $this->values['title'];
131 }
132
133 /** @return string */
134 public function get_description()
135 {
136 return (string) $this->values['description'];
137 }
138
139 /** @return string */
140 public function get_keywords()
141 {
142 return (string) $this->values['keywords'];
143 }
144
145 /** @return string */
146 public function get_canonical()
147 {
148 return (string) $this->values['canonical'];
149 }
150
151 /** @return string */
152 public function get_robots()
153 {
154 return (string) $this->values['robots'];
155 }
156
157 /** @return string */
158 public function get_og_title()
159 {
160 return (string) $this->values['og_title'];
161 }
162
163 /** @return string */
164 public function get_og_description()
165 {
166 return (string) $this->values['og_description'];
167 }
168
169 /** @return string */
170 public function get_og_image()
171 {
172 return (string) $this->values['og_image'];
173 }
174
175 /** @return string */
176 public function get_og_url()
177 {
178 return (string) $this->values['og_url'];
179 }
180
181 /** @return string */
182 public function get_twitter_title()
183 {
184 return (string) $this->values['twitter_title'];
185 }
186
187 /** @return string */
188 public function get_twitter_description()
189 {
190 return (string) $this->values['twitter_description'];
191 }
192
193 /** @return string */
194 public function get_twitter_image()
195 {
196 return (string) $this->values['twitter_image'];
197 }
198
199 /**
200 * Decoded JSON-LD graph.
201 *
202 * @return array
203 */
204 public function get_schema()
205 {
206 return is_array($this->values['schema']) ? $this->values['schema'] : array();
207 }
208
209 /** @return string */
210 public function get_public_url()
211 {
212 return (string) $this->values['public_url'];
213 }
214 }
215