PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 27.6
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v27.6
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / loader.php

loader.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 27.6, at src/loader.php

303 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO;
4
5 use Throwable;
6 use WP_CLI;
7 use YoastSEO_Vendor\Symfony\Component\DependencyInjection\ContainerInterface;
8
9 /**
10 * Class that manages loading integrations if and only if all their conditionals are met.
11 */
12 class Loader {
13
14 /**
15 * The registered integrations.
16 *
17 * @var string[]
18 */
19 protected $integrations = [];
20
21 /**
22 * The registered integrations.
23 *
24 * @var string[]
25 */
26 protected $initializers = [];
27
28 /**
29 * The registered routes.
30 *
31 * @var string[]
32 */
33 protected $routes = [];
34
35 /**
36 * The registered commands.
37 *
38 * @var string[]
39 */
40 protected $commands = [];
41
42 /**
43 * The registered migrations.
44 *
45 * @var string[]
46 */
47 protected $migrations = [];
48
49 /**
50 * The dependency injection container.
51 *
52 * @var ContainerInterface
53 */
54 protected $container;
55
56 /**
57 * Loader constructor.
58 *
59 * @param ContainerInterface $container The dependency injection container.
60 */
61 public function __construct( ContainerInterface $container ) {
62 $this->container = $container;
63 }
64
65 /**
66 * Registers an integration.
67 *
68 * @param string $integration_class The class name of the integration to be loaded.
69 *
70 * @return void
71 */
72 public function register_integration( $integration_class ) {
73 $this->integrations[] = $integration_class;
74 }
75
76 /**
77 * Registers an initializer.
78 *
79 * @param string $initializer_class The class name of the initializer to be loaded.
80 *
81 * @return void
82 */
83 public function register_initializer( $initializer_class ) {
84 $this->initializers[] = $initializer_class;
85 }
86
87 /**
88 * Registers a route.
89 *
90 * @param string $route_class The class name of the route to be loaded.
91 *
92 * @return void
93 */
94 public function register_route( $route_class ) {
95 $this->routes[] = $route_class;
96 }
97
98 /**
99 * Registers a command.
100 *
101 * @param string $command_class The class name of the command to be loaded.
102 *
103 * @return void
104 */
105 public function register_command( $command_class ) {
106 $this->commands[] = $command_class;
107 }
108
109 /**
110 * Registers a migration.
111 *
112 * @param string $plugin The plugin the migration belongs to.
113 * @param string $version The version of the migration.
114 * @param string $migration_class The class name of the migration to be loaded.
115 *
116 * @return void
117 */
118 public function register_migration( $plugin, $version, $migration_class ) {
119 if ( ! \array_key_exists( $plugin, $this->migrations ) ) {
120 $this->migrations[ $plugin ] = [];
121 }
122
123 $this->migrations[ $plugin ][ $version ] = $migration_class;
124 }
125
126 /**
127 * Loads all registered classes if their conditionals are met.
128 *
129 * @return void
130 */
131 public function load() {
132 $this->load_initializers();
133
134 if ( ! \did_action( 'init' ) ) {
135 \add_action( 'init', [ $this, 'load_integrations' ] );
136 }
137 else {
138 $this->load_integrations();
139 }
140
141 \add_action( 'rest_api_init', [ $this, 'load_routes' ] );
142
143 if ( \defined( 'WP_CLI' ) && \WP_CLI ) {
144 $this->load_commands();
145 }
146 }
147
148 /**
149 * Returns all registered migrations.
150 *
151 * @param string $plugin The plugin to get the migrations for.
152 *
153 * @return string[]|false The registered migrations. False if no migrations were registered.
154 */
155 public function get_migrations( $plugin ) {
156 if ( ! \array_key_exists( $plugin, $this->migrations ) ) {
157 return false;
158 }
159
160 return $this->migrations[ $plugin ];
161 }
162
163 /**
164 * Loads all registered commands.
165 *
166 * @return void
167 */
168 protected function load_commands() {
169 foreach ( $this->commands as $class ) {
170 $command = $this->get_class( $class );
171
172 if ( $command === null ) {
173 continue;
174 }
175
176 WP_CLI::add_command( $class::get_namespace(), $command );
177 }
178 }
179
180 /**
181 * Loads all registered initializers if their conditionals are met.
182 *
183 * @return void
184 */
185 protected function load_initializers() {
186 foreach ( $this->initializers as $class ) {
187 if ( ! $this->conditionals_are_met( $class ) ) {
188 continue;
189 }
190
191 $initializer = $this->get_class( $class );
192
193 if ( $initializer === null ) {
194 continue;
195 }
196
197 $initializer->initialize();
198 }
199 }
200
201 /**
202 * Loads all registered integrations if their conditionals are met.
203 *
204 * @return void
205 */
206 public function load_integrations() {
207 foreach ( $this->integrations as $class ) {
208 if ( ! $this->conditionals_are_met( $class ) ) {
209 continue;
210 }
211
212 $integration = $this->get_class( $class );
213
214 if ( $integration === null ) {
215 continue;
216 }
217
218 $integration->register_hooks();
219 }
220 }
221
222 /**
223 * Loads all registered routes if their conditionals are met.
224 *
225 * @return void
226 */
227 public function load_routes() {
228 foreach ( $this->routes as $class ) {
229 if ( ! $this->conditionals_are_met( $class ) ) {
230 continue;
231 }
232
233 $route = $this->get_class( $class );
234
235 if ( $route === null ) {
236 continue;
237 }
238
239 $route->register_routes();
240 }
241 }
242
243 /**
244 * Checks if all conditionals of a given loadable are met.
245 *
246 * @param string $loadable_class The class name of the loadable.
247 *
248 * @return bool Whether all conditionals of the loadable are met.
249 */
250 protected function conditionals_are_met( $loadable_class ) {
251 // In production environments do not fatal if the class does not exist but log and fail gracefully.
252 if ( \YOAST_ENVIRONMENT === 'production' && ! \class_exists( $loadable_class ) ) {
253 if ( \defined( 'WP_DEBUG' ) && \WP_DEBUG ) {
254 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
255 \error_log(
256 \sprintf(
257 /* translators: %1$s expands to Yoast SEO, %2$s expands to the name of the class that could not be found. */
258 \__( '%1$s attempted to load the class %2$s but it could not be found.', 'wordpress-seo' ),
259 'Yoast SEO',
260 $loadable_class,
261 ),
262 );
263 }
264 return false;
265 }
266
267 $conditionals = $loadable_class::get_conditionals();
268 foreach ( $conditionals as $class ) {
269 $conditional = $this->get_class( $class );
270 if ( $conditional === null || ! $conditional->is_met() ) {
271 return false;
272 }
273 }
274
275 return true;
276 }
277
278 /**
279 * Gets a class from the container.
280 *
281 * @param string $class_name The class name.
282 *
283 * @return object|null The class or, in production environments, null if it does not exist.
284 *
285 * @throws Throwable If the class does not exist in development environments.
286 */
287 protected function get_class( $class_name ) {
288 try {
289 return $this->container->get( $class_name );
290 } catch ( Throwable $e ) {
291 // In production environments do not fatal if the class could not be constructed but log and fail gracefully.
292 if ( \YOAST_ENVIRONMENT === 'production' ) {
293 if ( \defined( 'WP_DEBUG' ) && \WP_DEBUG ) {
294 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
295 \error_log( $e->getMessage() );
296 }
297 return null;
298 }
299 throw $e;
300 }
301 }
302 }
303