• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / b04fef060e49bb34d12e67b9178365f0e886a7ff

22 May 2024 02:52PM UTC coverage: 51.977% (-0.2%) from 52.19%
b04fef060e49bb34d12e67b9178365f0e886a7ff

Pull #21398

github

web-flow
Merge 7ba27f7c1 into c65fca879
Pull Request #21398: 192 wc editor create two way sync for the post metadata

7555 of 14065 branches covered (53.71%)

Branch coverage included in aggregate %.

15 of 185 new or added lines in 25 files covered. (8.11%)

1 existing line in 1 file now uncovered.

28741 of 55766 relevant lines covered (51.54%)

40281.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/woocommerce-editor/framework/woocommerce-editor-script-data.php
1
<?php
2

3
namespace Yoast\WP\SEO\WooCommerce_Editor\Framework;
4

5
use Exception;
6
use WP_Post;
7
use WP_Screen;
8
use WPSEO_Admin_Recommended_Replace_Vars;
9
use WPSEO_Language_Utils;
10
use WPSEO_Meta;
11
use WPSEO_Metabox_Formatter;
12
use WPSEO_Plugin_Availability;
13
use WPSEO_Post_Metabox_Formatter;
14
use WPSEO_Replace_Vars;
15
use WPSEO_Utils;
16
use Yoast\WP\SEO\Actions\Alert_Dismissal_Action;
17
use Yoast\WP\SEO\Helpers\Asset_Helper;
18
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
19
use Yoast\WP\SEO\Helpers\Short_Link_Helper;
20
use Yoast\WP\SEO\Introductions\Infrastructure\Wistia_Embed_Permission_Repository;
21
use Yoast\WP\SEO\Promotions\Application\Promotion_Manager;
22
use Yoast\WP\SEO\Surfaces\Meta_Surface;
23

24
/**
25
 * Collects the "script" data that is passed to the editor integration JS side.
26
 */
27
class WooCommerce_Editor_Script_Data {
28

29
        /**
30
         * Holds the Alert_Dismissal_Action instance.
31
         *
32
         * @var Alert_Dismissal_Action
33
         */
34
        private $alert_dismissal_action;
35

36
        /**
37
         * Holds the Asset_Helper instance.
38
         *
39
         * @var Asset_Helper
40
         */
41
        private $asset_helper;
42

43
        /**
44
         * Holds the Meta_Surface instance.
45
         *
46
         * @var Meta_Surface
47
         */
48
        private $meta_surface;
49

50
        /**
51
         * Holds the WPSEO_Plugin_Availability instance.
52
         *
53
         * @var WPSEO_Plugin_Availability
54
         */
55
        private $plugin_availability;
56

57
        /**
58
         * Holds the Post_Type_Helper instance.
59
         *
60
         * @var Post_Type_Helper
61
         */
62
        private $post_type_helper;
63

64
        /**
65
         * Holds the Promotion_Manager instance.
66
         *
67
         * @var Promotion_Manager
68
         */
69
        private $promotion_manager;
70

71
        /**
72
         * Holds the WPSEO_Admin_Recommended_Replace_Vars instance.
73
         *
74
         * @var WPSEO_Admin_Recommended_Replace_Vars
75
         */
76
        private $recommended_replace_vars;
77

78
        /**
79
         * Holds the WPSEO_Replace_Vars instance.
80
         *
81
         * @var WPSEO_Replace_Vars
82
         */
83
        private $replace_vars;
84

85
        /**
86
         * Holds the Short_Link_Helper instance.
87
         *
88
         * @var Short_Link_Helper
89
         */
90
        private $shortlink_helper;
91

92
        /**
93
         * Holds the Wistia_Embed_Permission_Repository instance.
94
         *
95
         * @var Wistia_Embed_Permission_Repository
96
         */
97
        private $wistia_embed_permission_repository;
98

99
        /**
100
         * Constructs the instance.
101
         *
102
         * @param Alert_Dismissal_Action             $alert_dismissal_action             The Alert_Dismissal_Action.
103
         * @param Asset_Helper                       $asset_helper                       The Asset_Helper.
104
         * @param Meta_Surface                       $meta_surface                       The Meta_Surface.
105
         * @param Post_Type_Helper                   $post_type_helper                   The Post_Type_Helper.
106
         * @param Promotion_Manager                  $promotion_manager                  The Promotion_Manager.
107
         * @param WPSEO_Replace_Vars                 $replace_vars                       The WPSEO_Replace_Vars.
108
         * @param Short_Link_Helper                  $shortlink_helper                   The Short_Link_Helper.
109
         * @param Wistia_Embed_Permission_Repository $wistia_embed_permission_repository The Wistia embed permission
110
         *                                                                               repository.
111
         *
112
         * @constructor
113
         */
114
        public function __construct(
×
115
                Alert_Dismissal_Action $alert_dismissal_action,
116
                Asset_Helper $asset_helper,
117
                Meta_Surface $meta_surface,
118
                Post_Type_Helper $post_type_helper,
119
                Promotion_Manager $promotion_manager,
120
                WPSEO_Replace_Vars $replace_vars,
121
                Short_Link_Helper $shortlink_helper,
122
                Wistia_Embed_Permission_Repository $wistia_embed_permission_repository
123
        ) {
124
                $this->alert_dismissal_action             = $alert_dismissal_action;
×
125
                $this->asset_helper                       = $asset_helper;
×
126
                $this->meta_surface                       = $meta_surface;
×
127
                $this->plugin_availability                = new WPSEO_Plugin_Availability();
×
128
                $this->post_type_helper                   = $post_type_helper;
×
129
                $this->promotion_manager                  = $promotion_manager;
×
130
                $this->recommended_replace_vars           = new WPSEO_Admin_Recommended_Replace_Vars();
×
131
                $this->replace_vars                       = $replace_vars;
×
132
                $this->shortlink_helper                   = $shortlink_helper;
×
133
                $this->wistia_embed_permission_repository = $wistia_embed_permission_repository;
×
134
        }
135

136
        /**
137
         * Collects the script data.
138
         *
139
         * @param WP_Post $post    The post object.
140
         * @param int     $user_id The user ID.
141
         *
142
         * @return array<string,string|int|bool|array> The script data.
143
         */
144
        public function get_data_for( WP_Post $post, int $user_id ): array {
×
145
                $is_block_editor           = WP_Screen::get()->is_block_editor();
×
146
                $is_woocommerce_seo_active = $this->plugin_availability->is_active( 'wpseo-woocommerce/wpseo-woocommerce.php' );
×
147

148
                try {
149
                        $wistia_embed_permission = $this->wistia_embed_permission_repository->get_value_for_user( $user_id );
×
150
                } catch ( Exception $e ) {
×
151
                        $wistia_embed_permission = false;
×
152
                }
153

154
                return [
155
                        'media'                  => [ 'choose_image' => \__( 'Use Image', 'wordpress-seo' ) ],
×
156
                        'metabox'                => $this->get_metabox_script_data( $post ),
×
157
                        'userLanguageCode'       => WPSEO_Language_Utils::get_language( \get_user_locale( $user_id ) ),
×
158
                        'isPost'                 => true,
159
                        'isBlockEditor'          => $is_block_editor,
×
160
                        'isElementorEditor'      => false,
161
                        'isWooCommerceSeoActive' => $is_woocommerce_seo_active,
×
162
                        'isWooCommerceActive'    => true,
163
                        'woocommerceUpsell'      => ! $is_woocommerce_seo_active,
×
164
                        'postId'                 => $post->ID,
×
165
                        'postStatus'             => $post->post_status,
×
166
                        'postType'               => $post->post_type,
×
167
                        'analysis'               => [
168
                                'plugins' => [
169
                                        'replaceVars' => [
170
                                                'no_parent_text'           => \__( '(no parent)', 'wordpress-seo' ),
×
171
                                                'replace_vars'             => $this->get_replace_vars( $post ),
×
172
                                                'hidden_replace_vars'      => $this->replace_vars->get_hidden_replace_vars(),
×
173
                                                'recommended_replace_vars' => $this->get_recommended_replace_vars( $post ),
×
174
                                                'scope'                    => 'post',
×
175
                                                'has_taxonomies'           => $this->get_post_type_has_taxonomies( $post->post_type ),
×
176
                                        ],
177
                                        'shortcodes'  => [
178
                                                'wpseo_shortcode_tags'          => $this->get_valid_shortcode_tags(),
×
179
                                                'wpseo_filter_shortcodes_nonce' => \wp_create_nonce( 'wpseo-filter-shortcodes' ),
×
180
                                        ],
181
                                ],
182
                                'worker'  => [
183
                                        'url'                     => $this->asset_helper->get_asset_url( 'yoast-seo-analysis-worker' ),
×
184
                                        'dependencies'            => $this->asset_helper->get_dependency_urls_by_handle( 'yoast-seo-analysis-worker' ),
×
185
                                        'keywords_assessment_url' => $this->asset_helper->get_asset_url( 'yoast-seo-used-keywords-assessment' ),
×
186
                                        'log_level'               => WPSEO_Utils::get_analysis_worker_log_level(),
×
187
                                        'enabled_features'        => WPSEO_Utils::retrieve_enabled_features(),
×
188
                                ],
189
                        ],
190
                        'dismissedAlerts'        => $this->alert_dismissal_action->all_dismissed(),
×
191
                        'currentPromotions'      => $this->promotion_manager->get_current_promotions(),
×
192
                        'usedKeywordsNonce'      => \wp_create_nonce( 'wpseo-keyword-usage-and-post-types' ),
×
193
                        'linkParams'             => $this->shortlink_helper->get_query_params(),
×
194
                        'pluginUrl'              => \plugins_url( '', \WPSEO_FILE ),
×
195
                        'wistiaEmbedPermission'  => $wistia_embed_permission,
×
196
                        /**
197
                         * Used to filter out the default metadata values when updating the Core store' metadata.
198
                         * Because the `wc/v3/products` endpoint only provides the metadata that is retrieved from the database,
199
                         * and we filter out the default values, the default values are not present in the Core store.
200
                         * Therefore, we need to prevent the default values syncing to the Core store, so the user does not get
201
                         * presented with the update option when there is actually no change.
202
                         */
NEW
203
                        'defaultMetadata'        => \array_merge(
×
NEW
204
                                WPSEO_Meta::$defaults,
×
205
                                [
NEW
206
                                        WPSEO_Meta::$meta_prefix . 'primary_product_cat' => '',
×
207
                                ]
208
                        ),
209
                ];
210
        }
211

212
        /**
213
         * Passes variables to js for use with the post-scraper.
214
         *
215
         * @param WP_Post $post The post object.
216
         *
217
         * @return array<string,string|int|bool|array>
218
         */
219
        private function get_metabox_script_data( WP_Post $post ): array {
×
220
                $post_formatter = new WPSEO_Metabox_Formatter(
×
221
                        new WPSEO_Post_Metabox_Formatter( $post, [], \get_sample_permalink( $post->ID )[0] )
×
222
                );
223

224
                $values = $post_formatter->get_values();
×
225

226
                /** This filter is documented in admin/filters/class-cornerstone-filter.php. */
227
                $post_types = \apply_filters( 'wpseo_cornerstone_post_types', $this->post_type_helper->get_accessible_post_types() );
×
228
                if ( $values['cornerstoneActive'] && ! \in_array( $post->post_type, $post_types, true ) ) {
×
229
                        $values['cornerstoneActive'] = false;
×
230
                }
231
                if ( $values['semrushIntegrationActive'] && $post->post_type === 'attachment' ) {
×
232
                        $values['semrushIntegrationActive'] = 0;
×
233
                }
234
                if ( $values['wincherIntegrationActive'] && $post->post_type === 'attachment' ) {
×
235
                        $values['wincherIntegrationActive'] = 0;
×
236
                }
237

238
                return $values;
×
239
        }
240

241
        /**
242
         * Prepares the replace vars for localization.
243
         *
244
         * @param WP_Post $post The post object.
245
         *
246
         * @return array<string,string|int|bool|array> Replace vars.
247
         */
248
        private function get_replace_vars( WP_Post $post ): array {
×
249
                $cached_replacement_vars = [];
×
250

251
                $vars_to_cache = [
252
                        'date',
×
253
                        'id',
254
                        'sitename',
255
                        'sitedesc',
256
                        'sep',
257
                        'page',
258
                        'currentdate',
259
                        'currentyear',
260
                        'currentmonth',
261
                        'currentday',
262
                        'post_year',
263
                        'post_month',
264
                        'post_day',
265
                        'name',
266
                        'author_first_name',
267
                        'author_last_name',
268
                        'permalink',
269
                        'post_content',
270
                        'category_title',
271
                        'tag',
272
                        'category',
273
                ];
274

275
                foreach ( $vars_to_cache as $var ) {
×
276
                        $cached_replacement_vars[ $var ] = \wpseo_replace_vars( '%%' . $var . '%%', $post );
×
277
                }
278

279
                // Merge custom replace variables with the WordPress ones.
280
                return \array_merge( $cached_replacement_vars, $this->get_custom_replace_vars( $post ) );
×
281
        }
282

283
        /**
284
         * Gets the custom replace variables for custom taxonomies and fields.
285
         *
286
         * @param WP_Post $post The post to check for custom taxonomies and fields.
287
         *
288
         * @return array<string,string|int|bool|array> Array containing all the replacement variables.
289
         */
290
        private function get_custom_replace_vars( WP_Post $post ): array {
×
291
                return [
292
                        'custom_fields'     => $this->get_custom_fields_replace_vars( $post ),
×
293
                        'custom_taxonomies' => $this->get_custom_taxonomies_replace_vars( $post ),
×
294
                ];
295
        }
296

297
        /**
298
         * Gets the custom replace variables for custom fields.
299
         *
300
         * @param WP_Post $post The post to check for custom fields.
301
         *
302
         * @return array<string,string|int|bool|array> Array containing all the replacement variables.
303
         */
304
        private function get_custom_fields_replace_vars( WP_Post $post ): array {
×
305
                $custom_replace_vars = [];
×
306

307
                // If no post object is passed, return the empty custom_replace_vars array.
308
                if ( ! \is_object( $post ) ) {
×
309
                        return $custom_replace_vars;
×
310
                }
311

312
                $custom_fields = \get_post_custom( $post->ID );
×
313

314
                // If $custom_fields is an empty string or generally not an array, return early.
315
                if ( ! \is_array( $custom_fields ) ) {
×
316
                        return $custom_replace_vars;
×
317
                }
318

319
                $meta = $this->meta_surface->for_post( $post->ID );
×
320

321
                if ( ! $meta ) {
×
322
                        return $custom_replace_vars;
×
323
                }
324

325
                // Simply concatenate all fields containing replace vars so we can handle them all with a single regex find.
326
                $replace_vars_fields = \implode(
×
327
                        ' ',
×
328
                        [
329
                                $meta->presentation->title,
×
330
                                $meta->presentation->meta_description,
×
331
                        ]
332
                );
333

334
                \preg_match_all( '/%%cf_([A-Za-z0-9_]+)%%/', $replace_vars_fields, $matches );
×
335
                $fields_to_include = $matches[1];
×
336
                foreach ( $custom_fields as $custom_field_name => $custom_field ) {
×
337
                        // Skip private custom fields.
338
                        if ( \substr( $custom_field_name, 0, 1 ) === '_' ) {
×
339
                                continue;
×
340
                        }
341

342
                        // Skip custom fields that are not used, new ones will be fetched dynamically.
343
                        if ( ! \in_array( $custom_field_name, $fields_to_include, true ) ) {
×
344
                                continue;
×
345
                        }
346

347
                        // Skip custom field values that are serialized.
348
                        if ( \is_serialized( $custom_field[0] ) ) {
×
349
                                continue;
×
350
                        }
351

352
                        $custom_replace_vars[ $custom_field_name ] = $custom_field[0];
×
353
                }
354

355
                return $custom_replace_vars;
×
356
        }
357

358
        /**
359
         * Gets the custom replace variables for custom taxonomies.
360
         *
361
         * @param WP_Post $post The post to check for custom taxonomies.
362
         *
363
         * @return array<string,string|int|bool|array> Array containing all the replacement variables.
364
         */
365
        private function get_custom_taxonomies_replace_vars( WP_Post $post ): array {
×
366
                $taxonomies          = \get_object_taxonomies( $post, 'objects' );
×
367
                $custom_replace_vars = [];
×
368

369
                foreach ( $taxonomies as $taxonomy_name => $taxonomy ) {
×
370

371
                        if ( \is_string( $taxonomy ) ) { // If attachment, see https://core.trac.wordpress.org/ticket/37368 .
×
372
                                $taxonomy_name = $taxonomy;
×
373
                                $taxonomy      = \get_taxonomy( $taxonomy_name );
×
374
                        }
375

376
                        if ( $taxonomy->_builtin && $taxonomy->public ) {
×
377
                                continue;
×
378
                        }
379

380
                        $custom_replace_vars[ $taxonomy_name ] = [
×
381
                                'name'        => $taxonomy->name,
×
382
                                'description' => $taxonomy->description,
×
383
                        ];
384
                }
385

386
                return $custom_replace_vars;
×
387
        }
388

389
        /**
390
         * Prepares the recommended replace vars for localization.
391
         *
392
         * @param WP_Post $post The post object.
393
         *
394
         * @return array<int,string> Recommended replacement variables.
395
         */
396
        private function get_recommended_replace_vars( WP_Post $post ): array {
×
397
                // What is recommended depends on the current context.
398
                $post_type = $this->recommended_replace_vars->determine_for_post( $post );
×
399

400
                return $this->recommended_replace_vars->get_recommended_replacevars_for( $post_type );
×
401
        }
402

403
        /**
404
         * Determines whether the post type has registered taxonomies.
405
         *
406
         * @param string $post_type The post type to check.
407
         *
408
         * @return bool Whether the post type has taxonomies.
409
         */
410
        private function get_post_type_has_taxonomies( string $post_type ): bool {
×
411
                return ! empty( \get_object_taxonomies( $post_type ) );
×
412
        }
413

414
        /**
415
         * Returns an array with shortcode tags for all registered shortcodes.
416
         *
417
         * @return array<int,string>
418
         */
419
        private function get_valid_shortcode_tags(): array {
×
420
                $shortcode_tags = [];
×
421

422
                foreach ( $GLOBALS['shortcode_tags'] as $tag => $description ) {
×
423
                        $shortcode_tags[] = $tag;
×
424
                }
425

426
                return $shortcode_tags;
×
427
        }
428
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc