PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
← All changes | lib/schema-graph.php +226 -0 22.5.222.7.0 View file →
@@ -1,0 +1,226 @@
1 +<?php
2 +/*
3 + * License: GPLv3
4 + * License URI: https://www.gnu.org/licenses/gpl.txt
5 + * Copyright 2012-2026 Jean-Sebastien Morisset (https://wpsso.com/)
6 + */
7 +
8 +if ( ! defined( 'ABSPATH' ) ) {
9 +
10 + die( 'These aren\'t the droids you\'re looking for.' );
11 +}
12 +
13 +if ( ! defined( 'WPSSO_PLUGINDIR' ) ) {
14 +
15 + die( 'Do. Or do not. There is no try.' );
16 +}
17 +
18 +if ( ! class_exists( 'WpssoSchemaGraph' ) ) {
19 +
20 + class WpssoSchemaGraph {
21 +
22 + private static $graph_context = 'https://schema.org';
23 + private static $graph_type = 'graph';
24 + private static $graph_data = array();
25 +
26 + public function __construct() {}
27 +
28 + public static function get_type_url() {
29 +
30 + return self::$graph_context . '/' . self::$graph_type;
31 + }
32 +
33 + public static function add_data( $data ) {
34 +
35 + static $home_url = null;
36 +
37 + if ( null === $home_url ) { // Optimize and call just once.
38 +
39 + $home_url = untrailingslashit( get_home_url() );
40 + }
41 +
42 + if ( empty( $data[ '@id' ] ) ) {
43 +
44 + self::$graph_data[] = $data;
45 +
46 + return true;
47 +
48 + } else {
49 +
50 + $val =& $data[ '@id' ];
51 +
52 + if ( 0 === strpos( $val, $home_url ) ) {
53 +
54 + $val = str_replace( $home_url, '', $val ); // Shorten the @id value, if possible.
55 + }
56 +
57 + if ( ! isset( self::$graph_data[ $val ] ) ) { // If not already added.
58 +
59 + if ( count( $data ) > 1 ) { // Ignore arrays with only an @id.
60 +
61 + self::$graph_data[ $val ] = $data;
62 +
63 + return true;
64 + }
65 + }
66 + }
67 +
68 + return false;
69 + }
70 +
71 + public static function get_json_reset_data() {
72 +
73 + $json_data = self::get_json();
74 +
75 + self::reset_data();
76 +
77 + return $json_data;
78 + }
79 +
80 + public static function get_json() {
81 +
82 + $json_data = array(
83 + '@context' => self::$graph_context,
84 + '@graph' => array_values( self::$graph_data ), // Exclude the associative array key values.
85 + );
86 +
87 + self::clean_json( $json_data );
88 +
89 + return $json_data;
90 + }
91 +
92 + public static function reset_data() {
93 +
94 + self::$graph_data = array();
95 + }
96 +
97 + /*
98 + * Recursively remove null values, empty strings, and empty arrays.
99 + */
100 + public static function clean_json( array &$arr ) {
101 +
102 + foreach ( $arr as $key => $value ) {
103 +
104 + if ( null === $value ) { // Null value.
105 +
106 + unset( $arr[ $key ] );
107 +
108 + } elseif ( '' === $value ) { // Empty string.
109 +
110 + unset( $arr[ $key ] );
111 +
112 + } elseif ( array() === $value ) { // Empty array.
113 +
114 + unset( $arr[ $key ] );
115 +
116 + } elseif ( is_array( $value ) ) {
117 +
118 + self::clean_json( $arr[ $key ] );
119 + }
120 + }
121 + }
122 +
123 + public static function optimize_json( array &$json_data ) { // Pass by reference is OK.
124 +
125 + static $optim_data = array();
126 + static $recur_level = null;
127 + static $id_anchor = null;
128 + static $home_url = null;
129 +
130 + if ( isset( $json_data[ '@graph' ] ) ) { // Top level of json.
131 +
132 + $recur_level = 0;
133 +
134 + } elseif ( null !== $recur_level ) {
135 +
136 + $recur_level++;
137 + }
138 +
139 + if ( $recur_level > 32 ) { // Just in case.
140 +
141 + return;
142 + }
143 +
144 + if ( null === $id_anchor ) { // Optimize and call just once.
145 +
146 + $id_anchor = WpssoSchema::get_id_anchor();
147 + }
148 +
149 + if ( null === $home_url ) { // Optimize and call just once.
150 +
151 + $home_url = untrailingslashit( get_home_url() );
152 + }
153 +
154 + foreach ( $json_data as $key => &$val ) {
155 +
156 + if ( is_array( $val ) ) {
157 +
158 + self::optimize_json( $val );
159 +
160 + } elseif ( '@id' === $key ) {
161 +
162 + if ( 0 === strpos( $val, $home_url ) ) {
163 +
164 + $val = str_replace( $home_url, '', $val ); // Shorten the @id value, if possible.
165 + }
166 +
167 + if ( count( $json_data ) > 1 ) { // Ignore arrays with a single element (ie. the @id property).
168 +
169 + if ( false !== strpos( $val, $id_anchor ) ) { // Only optimize our own @ids.
170 +
171 + if ( empty( $optim_data[ $val ] ) ) {
172 +
173 + $optim_data[ $val ] = $json_data;
174 +
175 + foreach ( $optim_data[ $val ] as $new_key => &$new_val ) {
176 +
177 + if ( is_array( $new_val ) ) {
178 +
179 + self::optimize_json( $new_val );
180 + }
181 + }
182 + }
183 +
184 + $json_data = array( $key => $val );
185 + }
186 + }
187 +
188 + break;
189 + }
190 + }
191 +
192 + if ( isset( $json_data[ '@graph' ] ) ) { // Top level of json.
193 +
194 + $merged_graph = array_merge( array_values( $optim_data ), $json_data[ '@graph' ] );
195 +
196 + /*
197 + * Reset the static variables after merging the new data.
198 + */
199 + $optim_data = array();
200 + $recur_level = null;
201 +
202 + /*
203 + * Cleanup any empty @id arrays.
204 + */
205 + foreach ( $merged_graph as $num => $val ) {
206 +
207 + if ( is_array( $val ) ) { // Just in case.
208 +
209 + if ( ! empty( $val[ '@id' ] ) && 1 === count( $val ) ) {
210 +
211 + unset( $merged_graph[ $num ] );
212 + }
213 + }
214 + }
215 +
216 + $json_data[ '@graph' ] = $merged_graph;
217 +
218 + unset( $merged_graph, $num, $val );
219 +
220 + } elseif ( null !== $recur_level ) {
221 +
222 + $recur_level--;
223 + }
224 + }
225 + }
226 +}