PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.2
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 / actions / importing / aioseo-posts-importing-action.php

aioseo-posts-importing-action.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.2, at src/actions/importing/aioseo-posts-importing-action.php

619 lines 21.8 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\Actions\Importing;
4
5 use wpdb;
6 use Yoast\WP\SEO\Conditionals\AIOSEO_V4_Importer_Conditional;
7 use Yoast\WP\SEO\Helpers\Indexable_Helper;
8 use Yoast\WP\SEO\Helpers\Image_Helper;
9 use Yoast\WP\SEO\Helpers\Indexable_To_Postmeta_Helper;
10 use Yoast\WP\SEO\Helpers\Options_Helper;
11 use Yoast\WP\SEO\Helpers\Sanitization_Helper;
12 use Yoast\WP\SEO\Helpers\Wpdb_Helper;
13 use Yoast\WP\SEO\Models\Indexable;
14 use Yoast\WP\SEO\Repositories\Indexable_Repository;
15 use Yoast\WP\SEO\Services\Importing\Aioseo_Replacevar_Handler;
16 use Yoast\WP\SEO\Services\Importing\Aioseo_Robots_Provider_Service;
17 use Yoast\WP\SEO\Services\Importing\Aioseo_Robots_Transformer_Service;
18 use Yoast\WP\SEO\Services\Importing\Aioseo_Social_Images_Provider_Service;
19
20 /**
21 * Importing action for AIOSEO post data.
22 *
23 * @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
24 */
25 class Aioseo_Posts_Importing_Action extends Abstract_Importing_Action {
26
27 use Import_Cursor_Manager_Trait;
28
29 /**
30 * The plugin of the action.
31 */
32 const PLUGIN = 'aioseo';
33
34 /**
35 * The type of the action.
36 */
37 const TYPE = 'posts';
38
39 /**
40 * The map of aioseo to yoast meta.
41 *
42 * @var array
43 */
44 protected $aioseo_to_yoast_map = [
45 'title' => [
46 'yoast_name' => 'title',
47 'transform_method' => 'simple_import_post',
48 ],
49 'description' => [
50 'yoast_name' => 'description',
51 'transform_method' => 'simple_import_post',
52 ],
53 'og_title' => [
54 'yoast_name' => 'open_graph_title',
55 'transform_method' => 'simple_import_post',
56 ],
57 'og_description' => [
58 'yoast_name' => 'open_graph_description',
59 'transform_method' => 'simple_import_post',
60 ],
61 'twitter_title' => [
62 'yoast_name' => 'twitter_title',
63 'transform_method' => 'simple_import_post',
64 'twitter_import' => true,
65 ],
66 'twitter_description' => [
67 'yoast_name' => 'twitter_description',
68 'transform_method' => 'simple_import_post',
69 'twitter_import' => true,
70 ],
71 'canonical_url' => [
72 'yoast_name' => 'canonical',
73 'transform_method' => 'url_import_post',
74 ],
75 'keyphrases' => [
76 'yoast_name' => 'primary_focus_keyword',
77 'transform_method' => 'keyphrase_import',
78 ],
79 'og_image_url' => [
80 'yoast_name' => 'open_graph_image',
81 'social_image_import' => true,
82 'social_setting_prefix_aioseo' => 'og_',
83 'social_setting_prefix_yoast' => 'open_graph_',
84 'transform_method' => 'social_image_url_import',
85 ],
86 'twitter_image_url' => [
87 'yoast_name' => 'twitter_image',
88 'social_image_import' => true,
89 'social_setting_prefix_aioseo' => 'twitter_',
90 'social_setting_prefix_yoast' => 'twitter_',
91 'transform_method' => 'social_image_url_import',
92 ],
93 'robots_noindex' => [
94 'yoast_name' => 'is_robots_noindex',
95 'transform_method' => 'post_robots_noindex_import',
96 'robots_import' => true,
97 ],
98 'robots_nofollow' => [
99 'yoast_name' => 'is_robots_nofollow',
100 'transform_method' => 'post_general_robots_import',
101 'robots_import' => true,
102 'robot_type' => 'nofollow',
103 ],
104 'robots_noarchive' => [
105 'yoast_name' => 'is_robots_noarchive',
106 'transform_method' => 'post_general_robots_import',
107 'robots_import' => true,
108 'robot_type' => 'noarchive',
109 ],
110 'robots_nosnippet' => [
111 'yoast_name' => 'is_robots_nosnippet',
112 'transform_method' => 'post_general_robots_import',
113 'robots_import' => true,
114 'robot_type' => 'nosnippet',
115 ],
116 'robots_noimageindex' => [
117 'yoast_name' => 'is_robots_noimageindex',
118 'transform_method' => 'post_general_robots_import',
119 'robots_import' => true,
120 'robot_type' => 'noimageindex',
121 ],
122 ];
123
124 /**
125 * Represents the indexables repository.
126 *
127 * @var Indexable_Repository
128 */
129 protected $indexable_repository;
130
131 /**
132 * The WordPress database instance.
133 *
134 * @var wpdb
135 */
136 protected $wpdb;
137
138 /**
139 * The image helper.
140 *
141 * @var Image_Helper
142 */
143 protected $image_helper;
144
145 /**
146 * The indexable_to_postmeta helper.
147 *
148 * @var Indexable_To_Postmeta_Helper
149 */
150 protected $indexable_to_postmeta;
151
152 /**
153 * The indexable helper.
154 *
155 * @var Indexable_Helper
156 */
157 protected $indexable_helper;
158
159 /**
160 * The wpdb helper.
161 *
162 * @var Wpdb_Helper
163 */
164 protected $wpdb_helper;
165
166 /**
167 * The social images provider service.
168 *
169 * @var Aioseo_Social_Images_Provider_Service
170 */
171 protected $social_images_provider;
172
173 /**
174 * Class constructor.
175 *
176 * @param Indexable_Repository $indexable_repository The indexables repository.
177 * @param wpdb $wpdb The WordPress database instance.
178 * @param Indexable_Helper $indexable_helper The indexable helper.
179 * @param Indexable_To_Postmeta_Helper $indexable_to_postmeta The indexable_to_postmeta helper.
180 * @param Options_Helper $options The options helper.
181 * @param Image_Helper $image The image helper.
182 * @param Sanitization_Helper $sanitization The sanitization helper.
183 * @param Wpdb_Helper $wpdb_helper The wpdb_helper helper.
184 * @param Aioseo_Replacevar_Handler $replacevar_handler The replacevar handler.
185 * @param Aioseo_Robots_Provider_Service $robots_provider The robots provider service.
186 * @param Aioseo_Robots_Transformer_Service $robots_transformer The robots transfomer service.
187 * @param Aioseo_Social_Images_Provider_Service $social_images_provider The social images provider service.
188 */
189 public function __construct(
190 Indexable_Repository $indexable_repository,
191 wpdb $wpdb,
192 Indexable_Helper $indexable_helper,
193 Indexable_To_Postmeta_Helper $indexable_to_postmeta,
194 Options_Helper $options,
195 Image_Helper $image,
196 Sanitization_Helper $sanitization,
197 Wpdb_Helper $wpdb_helper,
198 Aioseo_Replacevar_Handler $replacevar_handler,
199 Aioseo_Robots_Provider_Service $robots_provider,
200 Aioseo_Robots_Transformer_Service $robots_transformer,
201 Aioseo_Social_Images_Provider_Service $social_images_provider ) {
202 parent::__construct( $options, $sanitization, $replacevar_handler, $robots_provider, $robots_transformer );
203
204 $this->indexable_repository = $indexable_repository;
205 $this->wpdb = $wpdb;
206 $this->image = $image;
207 $this->indexable_helper = $indexable_helper;
208 $this->indexable_to_postmeta = $indexable_to_postmeta;
209 $this->wpdb_helper = $wpdb_helper;
210 $this->social_images_provider = $social_images_provider;
211 }
212
213 /**
214 * Retrieves the AIOSEO table name along with the db prefix.
215 *
216 * @return string The AIOSEO table name along with the db prefix.
217 */
218 protected function get_table() {
219 return $this->wpdb->prefix . 'aioseo_posts';
220 }
221
222 /**
223 * Determines if the AIOSEO database table exists.
224 *
225 * @return bool True if the table is found.
226 */
227 protected function aioseo_exists() {
228 return $this->wpdb_helper->table_exists( $this->get_table() ) === true;
229 }
230
231 /**
232 * Returns whether the AISOEO post importing action is enabled.
233 *
234 * @return bool True if the AISOEO post importing action is enabled.
235 */
236 public function is_enabled() {
237 $aioseo_importer_conditional = \YoastSEO()->classes->get( AIOSEO_V4_Importer_Conditional::class );
238
239 return $aioseo_importer_conditional->is_met();
240 }
241
242 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Reason: They are already prepared.
243
244 /**
245 * Returns the total number of unimported objects.
246 *
247 * @return int The total number of unimported objects.
248 */
249 public function get_total_unindexed() {
250 if ( ! $this->aioseo_exists() ) {
251 return 0;
252 }
253
254 $limit = false;
255 $just_detect = true;
256 $indexables_to_create = $this->wpdb->get_col( $this->query( $limit, $just_detect ) );
257
258 $number_of_indexables_to_create = \count( $indexables_to_create );
259 $completed = $number_of_indexables_to_create === 0;
260 $this->set_completed( $completed );
261
262 return $number_of_indexables_to_create;
263 }
264
265 /**
266 * Returns the limited number of unimported objects.
267 *
268 * @param int $limit The maximum number of unimported objects to be returned.
269 *
270 * @return int|false The limited number of unindexed posts. False if the query fails.
271 */
272 public function get_limited_unindexed_count( $limit ) {
273 if ( ! $this->aioseo_exists() ) {
274 return 0;
275 }
276
277 $just_detect = true;
278 $indexables_to_create = $this->wpdb->get_col( $this->query( $limit, $just_detect ) );
279
280 $number_of_indexables_to_create = \count( $indexables_to_create );
281 $completed = $number_of_indexables_to_create === 0;
282 $this->set_completed( $completed );
283
284 return $number_of_indexables_to_create;
285 }
286
287 /**
288 * Imports AIOSEO meta data and creates the respective Yoast indexables and postmeta.
289 *
290 * @return Indexable[]|false An array of created indexables or false if aioseo data was not found.
291 */
292 public function index() {
293 if ( ! $this->aioseo_exists() ) {
294 return false;
295 }
296
297 $limit = $this->get_limit();
298 $aioseo_indexables = $this->wpdb->get_results( $this->query( $limit ), ARRAY_A );
299 $created_indexables = [];
300
301 $completed = \count( $aioseo_indexables ) === 0;
302 $this->set_completed( $completed );
303
304 // Let's build the list of fields to check their defaults, to identify whether we're gonna import AIOSEO data in the indexable or not.
305 $check_defaults_fields = [];
306 foreach ( $this->aioseo_to_yoast_map as $yoast_mapping ) {
307 // We don't want to check all the imported fields.
308 if ( ! \in_array( $yoast_mapping['yoast_name'], [ 'open_graph_image', 'twitter_image' ], true ) ) {
309 $check_defaults_fields[] = $yoast_mapping['yoast_name'];
310 }
311 }
312
313 $last_indexed_aioseo_id = 0;
314 foreach ( $aioseo_indexables as $aioseo_indexable ) {
315 $last_indexed_aioseo_id = $aioseo_indexable['id'];
316
317 $indexable = $this->indexable_repository->find_by_id_and_type( $aioseo_indexable['post_id'], 'post' );
318
319 // Let's ensure that the current post id represents something that we want to index (eg. *not* shop_order).
320 if ( ! \is_a( $indexable, 'Yoast\WP\SEO\Models\Indexable' ) ) {
321 continue;
322 }
323
324 if ( $this->indexable_helper->check_if_default_indexable( $indexable, $check_defaults_fields ) ) {
325 $indexable = $this->map( $indexable, $aioseo_indexable );
326 $indexable->save();
327
328 // To ensure that indexables can be rebuild after a reset, we have to store the data in the postmeta table too.
329 $this->indexable_to_postmeta->map_to_postmeta( $indexable );
330 }
331
332 $last_indexed_aioseo_id = $aioseo_indexable['id'];
333
334 $created_indexables[] = $indexable;
335 }
336
337 $cursor_id = $this->get_cursor_id();
338 $this->set_cursor( $this->options, $cursor_id, $last_indexed_aioseo_id );
339
340 return $created_indexables;
341 }
342
343 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
344
345 /**
346 * Maps AIOSEO meta data to Yoast meta data.
347 *
348 * @param Indexable $indexable The Yoast indexable.
349 * @param array $aioseo_indexable The AIOSEO indexable.
350 *
351 * @return Indexable The created indexables.
352 */
353 public function map( $indexable, $aioseo_indexable ) {
354 foreach ( $this->aioseo_to_yoast_map as $aioseo_key => $yoast_mapping ) {
355 // For robots import.
356 if ( isset( $yoast_mapping['robots_import'] ) && $yoast_mapping['robots_import'] ) {
357 $yoast_mapping['subtype'] = $indexable->object_sub_type;
358 $indexable->{$yoast_mapping['yoast_name']} = $this->transform_import_data( $yoast_mapping['transform_method'], $aioseo_indexable, $aioseo_key, $yoast_mapping, $indexable );
359
360 continue;
361 }
362
363 // For social images, like open graph and twitter image.
364 if ( isset( $yoast_mapping['social_image_import'] ) && $yoast_mapping['social_image_import'] ) {
365 $image_url = $this->transform_import_data( $yoast_mapping['transform_method'], $aioseo_indexable, $aioseo_key, $yoast_mapping, $indexable );
366
367 // Update the indexable's social image only where there's actually a url to import, so as not to lose the social images that we came up with when we originally built the indexable.
368 if ( ! empty( $image_url ) ) {
369 $indexable->{$yoast_mapping['yoast_name']} = $image_url;
370
371 $image_source_key = $yoast_mapping['social_setting_prefix_yoast'] . 'image_source';
372 $indexable->$image_source_key = 'imported';
373
374 $image_id_key = $yoast_mapping['social_setting_prefix_yoast'] . 'image_id';
375 $indexable->$image_id_key = $this->image->get_attachment_by_url( $image_url );
376
377 if ( $yoast_mapping['yoast_name'] === 'open_graph_image' ) {
378 $indexable->open_graph_image_meta = null;
379 }
380 }
381 continue;
382 }
383
384 // For twitter import, take the respective open graph data if the appropriate setting is enabled.
385 if ( isset( $yoast_mapping['twitter_import'] ) && $yoast_mapping['twitter_import'] && $aioseo_indexable['twitter_use_og'] ) {
386 $aioseo_indexable['twitter_title'] = $aioseo_indexable['og_title'];
387 $aioseo_indexable['twitter_description'] = $aioseo_indexable['og_description'];
388 }
389
390 if ( ! empty( $aioseo_indexable[ $aioseo_key ] ) ) {
391 $indexable->{$yoast_mapping['yoast_name']} = $this->transform_import_data( $yoast_mapping['transform_method'], $aioseo_indexable, $aioseo_key, $yoast_mapping, $indexable );
392 }
393 }
394
395 return $indexable;
396 }
397
398 /**
399 * Transforms the data to be imported.
400 *
401 * @param string $transform_method The method that is going to be used for transforming the data.
402 * @param array $aioseo_indexable The data of the AIOSEO indexable data that is being imported.
403 * @param string $aioseo_key The name of the specific set of data that is going to be transformed.
404 * @param array $yoast_mapping Extra details for the import of the specific data that is going to be transformed.
405 * @param Indexable $indexable The Yoast indexable that we are going to import the transformed data into.
406 *
407 * @return string|bool|null The transformed data to be imported.
408 */
409 protected function transform_import_data( $transform_method, $aioseo_indexable, $aioseo_key, $yoast_mapping, $indexable ) {
410 return \call_user_func( [ $this, $transform_method ], $aioseo_indexable, $aioseo_key, $yoast_mapping, $indexable );
411 }
412
413 /**
414 * Returns the number of objects that will be imported in a single importing pass.
415 *
416 * @return int The limit.
417 */
418 public function get_limit() {
419 /**
420 * Filter 'wpseo_aioseo_post_indexation_limit' - Allow filtering the number of posts indexed during each indexing pass.
421 *
422 * @api int The maximum number of posts indexed.
423 */
424 $limit = \apply_filters( 'wpseo_aioseo_post_indexation_limit', 25 );
425
426 if ( ! \is_int( $limit ) || $limit < 1 ) {
427 $limit = 25;
428 }
429
430 return $limit;
431 }
432
433 /**
434 * Creates a query for gathering AiOSEO data from the database.
435 *
436 * @param int $limit The maximum number of unimported objects to be returned.
437 * @param bool $just_detect Whether we want to just detect if there are unimported objects. If false, we want to actually import them too.
438 *
439 * @return string The query to use for importing or counting the number of items to import.
440 */
441 public function query( $limit = false, $just_detect = false ) {
442 $table = $this->get_table();
443
444 $select_statement = 'id';
445 if ( ! $just_detect ) {
446 // If we want to import too, we need the actual needed data from AIOSEO indexables.
447 $needed_data = \array_keys( $this->aioseo_to_yoast_map );
448 \array_push( $needed_data, 'id', 'post_id', 'robots_default', 'og_image_custom_url', 'og_image_type', 'twitter_image_custom_url', 'twitter_image_type', 'twitter_use_og' );
449
450 $select_statement = \implode( ', ', $needed_data );
451 }
452
453 $cursor_id = $this->get_cursor_id();
454 $cursor = $this->get_cursor( $this->options, $cursor_id );
455
456 /**
457 * Filter 'wpseo_aioseo_post_cursor' - Allow filtering the value of the aioseo post import cursor.
458 *
459 * @api int The value of the aioseo post import cursor.
460 */
461 $cursor = \apply_filters( 'wpseo_aioseo_post_import_cursor', $cursor );
462
463 $replacements = [ $cursor ];
464
465 $limit_statement = '';
466 if ( ! empty( $limit ) ) {
467 $replacements[] = $limit;
468 $limit_statement = ' LIMIT %d';
469 }
470
471 // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: There is no unescaped user input.
472 return $this->wpdb->prepare(
473 "SELECT {$select_statement} FROM {$table} WHERE id > %d ORDER BY id{$limit_statement}",
474 $replacements
475 );
476 // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
477 }
478
479 /**
480 * Minimally transforms data to be imported.
481 *
482 * @param array $aioseo_data All of the AIOSEO data to be imported.
483 * @param string $aioseo_key The AIOSEO key that contains the setting we're working with.
484 *
485 * @return string The transformed meta data.
486 */
487 public function simple_import_post( $aioseo_data, $aioseo_key ) {
488 return $this->simple_import( $aioseo_data[ $aioseo_key ] );
489 }
490
491 /**
492 * Transforms URL to be imported.
493 *
494 * @param array $aioseo_data All of the AIOSEO data to be imported.
495 * @param string $aioseo_key The AIOSEO key that contains the setting we're working with.
496 *
497 * @return string The transformed URL.
498 */
499 public function url_import_post( $aioseo_data, $aioseo_key ) {
500 return $this->url_import( $aioseo_data[ $aioseo_key ] );
501 }
502
503 /**
504 * Plucks the keyphrase to be imported from the AIOSEO array of keyphrase meta data.
505 *
506 * @param array $aioseo_data All of the AIOSEO data to be imported.
507 * @param string $aioseo_key The AIOSEO key that contains the setting we're working with, aka keyphrases.
508 *
509 * @return string|null The plucked keyphrase.
510 */
511 public function keyphrase_import( $aioseo_data, $aioseo_key ) {
512 $meta_data = \json_decode( $aioseo_data[ $aioseo_key ], true );
513 if ( ! isset( $meta_data['focus']['keyphrase'] ) ) {
514 return null;
515 }
516
517 return $this->sanitization->sanitize_text_field( $meta_data['focus']['keyphrase'] );
518 }
519
520 /**
521 * Imports the post's noindex setting.
522 *
523 * @param bool $aioseo_robots_settings AIOSEO's set of robot settings for the post.
524 *
525 * @return bool|null The value of Yoast's noindex setting for the post.
526 */
527 public function post_robots_noindex_import( $aioseo_robots_settings ) {
528 // If robot settings defer to default settings, we have null in the is_robots_noindex field.
529 if ( isset( $aioseo_robots_settings['robots_default'] ) && $aioseo_robots_settings['robots_default'] ) {
530 return null;
531 }
532
533 return $aioseo_robots_settings['robots_noindex'];
534 }
535
536 /**
537 * Imports the post's robots setting.
538 *
539 * @param bool $aioseo_robots_settings AIOSEO's set of robot settings for the post.
540 * @param string $aioseo_key The AIOSEO key that contains the robot setting we're working with.
541 * @param array $mapping The mapping of the setting we're working with.
542 *
543 * @return bool|null The value of Yoast's noindex setting for the post.
544 */
545 public function post_general_robots_import( $aioseo_robots_settings, $aioseo_key, $mapping ) {
546 $mapping['type'] = 'postTypes';
547 $mapping['option_name'] = 'aioseo_options_dynamic';
548
549 if ( isset( $aioseo_robots_settings['robots_default'] ) && $aioseo_robots_settings['robots_default'] ) {
550 // Let's first get the subtype's setting value and then transform it taking into consideration whether it defers to global defaults.
551 $subtype_setting = $this->robots_provider->get_subtype_robot_setting( $mapping );
552 return $this->robots_transformer->transform_robot_setting( $mapping['robot_type'], $subtype_setting, $mapping );
553 }
554
555 return $aioseo_robots_settings[ $aioseo_key ];
556 }
557
558 /**
559 * Imports the og and twitter image url.
560 *
561 * @param bool $aioseo_social_image_settings AIOSEO's set of social image settings for the post.
562 * @param string $aioseo_key The AIOSEO key that contains the robot setting we're working with.
563 * @param array $mapping The mapping of the setting we're working with.
564 * @param Indexable $indexable The Yoast indexable we're importing into.
565 *
566 * @return bool|null The url of the social image we're importing, null if there's none.
567 */
568 public function social_image_url_import( $aioseo_social_image_settings, $aioseo_key, $mapping, $indexable ) {
569 if ( $mapping['social_setting_prefix_aioseo'] === 'twitter_' && $aioseo_social_image_settings['twitter_use_og'] ) {
570 $mapping['social_setting_prefix_aioseo'] = 'og_';
571 }
572
573 $social_setting = \rtrim( $mapping['social_setting_prefix_aioseo'], '_' );
574
575 $image_type = $aioseo_social_image_settings[ $mapping['social_setting_prefix_aioseo'] . 'image_type' ];
576
577 if ( $image_type === 'default' ) {
578 $image_type = $this->social_images_provider->get_default_social_image_source( $social_setting );
579 }
580
581 switch ( $image_type ) {
582 case 'attach':
583 $image_url = $this->social_images_provider->get_first_attached_image( $indexable->object_id );
584 break;
585 case 'auto':
586 $image_url = $this->social_images_provider->get_auto_image( $indexable->object_id );
587 break;
588 case 'content':
589 $image_url = $this->social_images_provider->get_first_image_in_content( $indexable->object_id );
590 break;
591 case 'custom_image':
592 $image_url = $aioseo_social_image_settings[ $mapping['social_setting_prefix_aioseo'] . 'image_custom_url' ];
593 break;
594 case 'featured':
595 return null; // Our auto-calculation when the indexable is built/updated will take care of it, so it's not needed to transfer any data now.
596 case 'author':
597 return null;
598 case 'custom':
599 return null;
600 case 'default':
601 $image_url = $this->social_images_provider->get_default_custom_social_image( $social_setting );
602 break;
603 default:
604 $image_url = $aioseo_social_image_settings[ $mapping['social_setting_prefix_aioseo'] . 'image_url' ];
605 break;
606 }
607
608 if ( empty( $image_url ) ) {
609 $image_url = $this->social_images_provider->get_default_custom_social_image( $social_setting );
610 }
611
612 if ( empty( $image_url ) ) {
613 return null;
614 }
615
616 return $this->sanitization->sanitize_url( $image_url, null );
617 }
618 }
619