Yoast SEO - Version 14.7

Version Description

Release Date: August 5th, 2020

Say hi to Yoast SEO 14.7, chock-full of enhancements to help you with your site's SEO. Have you heard about the addition of XML sitemaps in WordPress 5.5? The Yoast SEO plugin is completely prepared for this. We also have some great news for users of the Web Stories plugin. Read more about those changes in our release post!

Enhancements:

  • Adds support for adding metadata to Web Stories (the web-story post type) from the Web Stories plugin. Props to swissspidy
  • Shows a more specific notification about why the reindexing of SEO data is needed when the permalinks are reset or when the category base setting is changed.
  • Redirects requests to the WordPress sitemaps to the appropriate Yoast sitemap, if the Yoast sitemaps are enabled.
  • Adds the option for users to opt-in to allow Yoast to track some data about their site.
  • Optimizes script loading by removing ver parameters from scripts and styles when they're not needed.
  • Adds the Yoast logo to the Yoast block categories.
  • Compatibility with WordPress 5.5: makes sure Yoast structured data blocks are found on more keywords and have examples in the block inserter.

Bugfixes:

  • Fixes a bug where a fatal error would occur in sitemaps on sites where the home URL and site URL were different. Because the cause of this was a missing style sheet, the content of the sitemaps was still there, which means Google and other search engines could still reach the sitemaps and no SEO harm was done.
  • Fixes a bug where reindexing would not be done for indexables without a permalink.
  • Fixes a bug where an indexable's permalink remained unchanged when the categories prefix option was changed.
  • Fixes a bug where an inline link that opens in a new window would render undefined in the aria-label.
  • Fixes a bug where the indexables indexing process could not be started again without a page reload on the tools page if it failed.
  • Fixes a bug where a console error would be thrown because wpseoShortcodePluginL10n was not defined.
  • Fixes a bug where the SEO and Readability scores were no longer shown in the publish box in the classic editor.
  • Fixes a bug where clicking the Readability score link in the classic editor would trigger an error.

Other:

  • Enables the cornerstone content toggle for taxonomies.
  • Adds the option to filter our Schema by @type.
  • Removes the setting to show the date in the Google Preview. The date will now always be shown in post-type previews.
  • Moves the running of the SEO data indexing process to the Yoast Tools page.
Download this release

Release Info

Developer Yoast
Plugin Icon 128x128 Yoast SEO
Version 14.7
Comparing to
See all releases

Code changes from version 14.6 to 14.7

Files changed (86) hide show
  1. admin/ajax.php +4 -0
  2. admin/class-admin-asset-manager.php +1 -1
  3. admin/class-asset.php +8 -3
  4. admin/class-gutenberg-compatibility.php +2 -2
  5. admin/config-ui/class-configuration-storage.php +2 -0
  6. admin/config-ui/class-configuration-structure.php +5 -0
  7. admin/config-ui/fields/class-field-tracking-intro.php +25 -0
  8. admin/config-ui/fields/class-field-tracking.php +66 -0
  9. admin/formatter/class-post-metabox-formatter.php +1 -18
  10. admin/taxonomy/class-taxonomy-content-fields.php +6 -0
  11. admin/tracking/class-tracking-settings-data.php +0 -3
  12. admin/tracking/class-tracking.php +40 -9
  13. admin/views/class-view-utils.php +0 -48
  14. admin/views/class-yoast-feature-toggles.php +12 -0
  15. admin/views/tabs/metas/paper-content/general/knowledge-graph.php +3 -4
  16. admin/views/tabs/metas/paper-content/post_type/post-type.php +0 -5
  17. config/composer/actions.php +0 -263
  18. config/dependency-injection/container-compiler.php +0 -57
  19. config/dependency-injection/custom-loader.php +0 -195
  20. config/dependency-injection/loader-pass.php +0 -82
  21. config/dependency-injection/services.php +0 -70
  22. config/php-codeshift/remove-vendor-prefixing-array-key-visitor.php +0 -38
  23. config/php-codeshift/remove-vendor-prefixing-codemod.php +0 -34
  24. config/php-codeshift/remove-vendor-prefixing-comment-visitor.php +0 -37
  25. config/php-codeshift/remove-vendor-prefixing-visitor.php +0 -37
  26. config/php-scoper/dependency-injection.inc.php +0 -41
  27. config/php-scoper/guzzlehttp.inc.php +0 -56
  28. config/php-scoper/oauth2-client.inc.php +0 -54
  29. config/php-scoper/psr.inc.php +0 -32
  30. css/dist/{admin-global-1460-rtl.css → admin-global-1470-rtl.css} +0 -0
  31. css/dist/{admin-global-1460.css → admin-global-1470.css} +0 -0
  32. css/dist/{adminbar-1460-rtl.css → adminbar-1470-rtl.css} +0 -0
  33. css/dist/{adminbar-1460.css → adminbar-1470.css} +0 -0
  34. css/dist/{alerts-1460-rtl.css → alerts-1470-rtl.css} +0 -0
  35. css/dist/{alerts-1460.css → alerts-1470.css} +0 -0
  36. css/dist/{dashboard-1460-rtl.css → dashboard-1470-rtl.css} +0 -0
  37. css/dist/{dashboard-1460.css → dashboard-1470.css} +0 -0
  38. css/dist/{edit-page-1460-rtl.css → edit-page-1470-rtl.css} +0 -0
  39. css/dist/{edit-page-1460.css → edit-page-1470.css} +0 -0
  40. css/dist/{featured-image-1460-rtl.css → featured-image-1470-rtl.css} +0 -0
  41. css/dist/{featured-image-1460.css → featured-image-1470.css} +0 -0
  42. css/dist/{filter-explanation-1460-rtl.css → filter-explanation-1470-rtl.css} +0 -0
  43. css/dist/{filter-explanation-1460.css → filter-explanation-1470.css} +0 -0
  44. css/dist/{icons-1460-rtl.css → icons-1470-rtl.css} +0 -0
  45. css/dist/{icons-1460.css → icons-1470.css} +0 -0
  46. css/dist/{inside-editor-1460-rtl.css → inside-editor-1470-rtl.css} +0 -0
  47. css/dist/{inside-editor-1460.css → inside-editor-1470.css} +0 -0
  48. css/dist/{metabox-1460-rtl.css → metabox-1470-rtl.css} +1 -1
  49. css/dist/{metabox-1460.css → metabox-1470.css} +1 -1
  50. css/dist/{metabox-primary-category-1460-rtl.css → metabox-primary-category-1470-rtl.css} +0 -0
  51. css/dist/{metabox-primary-category-1460.css → metabox-primary-category-1470.css} +0 -0
  52. css/dist/monorepo-1460-rtl.css +0 -1
  53. css/dist/monorepo-1460.css +0 -1
  54. css/dist/monorepo-1470-rtl.css +1 -0
  55. css/dist/monorepo-1470.css +1 -0
  56. css/dist/{notifications-1460-rtl.css → notifications-1470-rtl.css} +0 -0
  57. css/dist/{notifications-1460.css → notifications-1470.css} +0 -0
  58. css/dist/{score_icon-1460-rtl.css → score_icon-1470-rtl.css} +0 -0
  59. css/dist/{score_icon-1460.css → score_icon-1470.css} +0 -0
  60. css/dist/{search-appearance-1460-rtl.css → search-appearance-1470-rtl.css} +0 -0
  61. css/dist/{search-appearance-1460.css → search-appearance-1470.css} +0 -0
  62. css/dist/{structured-data-blocks-1460-rtl.css → structured-data-blocks-1470-rtl.css} +0 -0
  63. css/dist/{structured-data-blocks-1460.css → structured-data-blocks-1470.css} +0 -0
  64. css/dist/{toggle-switch-1460-rtl.css → toggle-switch-1470-rtl.css} +0 -0
  65. css/dist/{toggle-switch-1460.css → toggle-switch-1470.css} +0 -0
  66. css/dist/{wpseo-dismissible-1460-rtl.css → wpseo-dismissible-1470-rtl.css} +0 -0
  67. css/dist/{wpseo-dismissible-1460.css → wpseo-dismissible-1470.css} +0 -0
  68. css/dist/{yoast-components-1460-rtl.css → yoast-components-1470-rtl.css} +0 -0
  69. css/dist/{yoast-components-1460.css → yoast-components-1470.css} +0 -0
  70. css/dist/{yoast-extensions-1460-rtl.css → yoast-extensions-1470-rtl.css} +0 -0
  71. css/dist/{yoast-extensions-1460.css → yoast-extensions-1470.css} +0 -0
  72. css/dist/{yst_plugin_tools-1460-rtl.css → yst_plugin_tools-1470-rtl.css} +0 -0
  73. css/dist/{yst_plugin_tools-1460.css → yst_plugin_tools-1470.css} +0 -0
  74. css/dist/{yst_seo_score-1460-rtl.css → yst_seo_score-1470-rtl.css} +0 -0
  75. css/dist/{yst_seo_score-1460.css → yst_seo_score-1470.css} +0 -0
  76. css/src/metabox.css +0 -1
  77. inc/class-wpseo-utils.php +0 -52
  78. inc/options/class-wpseo-option-ms.php +1 -0
  79. inc/options/class-wpseo-option-titles.php +0 -6
  80. inc/options/class-wpseo-option-wpseo.php +11 -1
  81. inc/options/class-wpseo-options.php +1 -1
  82. inc/options/class-wpseo-taxonomy-meta.php +1 -0
  83. inc/sitemaps/class-sitemaps.php +1 -2
  84. js/dist/admin-global-1460.js +0 -1
  85. js/dist/admin-global-1470.js +1 -0
  86. js/dist/{analysis-1460.js → analysis-1470.js} +2 -2
admin/ajax.php CHANGED
@@ -78,6 +78,10 @@ function wpseo_set_ignore() {
78
  $ignore_key = sanitize_text_field( filter_input( INPUT_POST, 'option' ) );
79
  WPSEO_Options::set( 'ignore_' . $ignore_key, true );
80
 
 
 
 
 
81
  die( '1' );
82
  }
83
 
78
  $ignore_key = sanitize_text_field( filter_input( INPUT_POST, 'option' ) );
79
  WPSEO_Options::set( 'ignore_' . $ignore_key, true );
80
 
81
+ if ( $ignore_key === 'indexation_warning' ) {
82
+ WPSEO_Options::set( 'indexables_indexation_reason', '' );
83
+ }
84
+
85
  die( '1' );
86
  }
87
 
admin/class-admin-asset-manager.php CHANGED
@@ -278,6 +278,7 @@ class WPSEO_Admin_Asset_Manager {
278
  'wp-annotations',
279
  'wp-api',
280
  'wp-api-fetch',
 
281
  'wp-components',
282
  'wp-compose',
283
  'wp-data',
@@ -346,7 +347,6 @@ class WPSEO_Admin_Asset_Manager {
346
  self::PREFIX . 'select2',
347
  ],
348
  'version' => '4.0.3',
349
- 'suffix' => '',
350
  ],
351
  [
352
  'name' => 'configuration-wizard',
278
  'wp-annotations',
279
  'wp-api',
280
  'wp-api-fetch',
281
+ 'wp-blocks',
282
  'wp-components',
283
  'wp-compose',
284
  'wp-data',
347
  self::PREFIX . 'select2',
348
  ],
349
  'version' => '4.0.3',
 
350
  ],
351
  [
352
  'name' => 'configuration-wizard',
admin/class-asset.php CHANGED
@@ -142,10 +142,11 @@ class WPSEO_Admin_Asset {
142
  */
143
  private $defaults = [
144
  'deps' => [],
145
- 'version' => WPSEO_VERSION,
146
  'in_footer' => true,
147
  'rtl' => true,
148
  'media' => 'all',
 
 
149
  ];
150
 
151
  /**
@@ -173,7 +174,7 @@ class WPSEO_Admin_Asset {
173
  $this->media = $args['media'];
174
  $this->in_footer = $args['in_footer'];
175
  $this->rtl = $args['rtl'];
176
- $this->suffix = isset( $args['suffix'] ) ? $args['suffix'] : '';
177
  }
178
 
179
  /**
@@ -209,7 +210,11 @@ class WPSEO_Admin_Asset {
209
  * @return string
210
  */
211
  public function get_version() {
212
- return $this->version;
 
 
 
 
213
  }
214
 
215
  /**
142
  */
143
  private $defaults = [
144
  'deps' => [],
 
145
  'in_footer' => true,
146
  'rtl' => true,
147
  'media' => 'all',
148
+ 'version' => '',
149
+ 'suffix' => '',
150
  ];
151
 
152
  /**
174
  $this->media = $args['media'];
175
  $this->in_footer = $args['in_footer'];
176
  $this->rtl = $args['rtl'];
177
+ $this->suffix = $args['suffix'];
178
  }
179
 
180
  /**
210
  * @return string
211
  */
212
  public function get_version() {
213
+ if ( ! empty( $this->version ) ) {
214
+ return $this->version;
215
+ }
216
+
217
+ return null;
218
  }
219
 
220
  /**
admin/class-gutenberg-compatibility.php CHANGED
@@ -15,14 +15,14 @@ class WPSEO_Gutenberg_Compatibility {
15
  *
16
  * @var string
17
  */
18
- const CURRENT_RELEASE = '8.5.1';
19
 
20
  /**
21
  * The minimally supported version of Gutenberg by the plugin.
22
  *
23
  * @var string
24
  */
25
- const MINIMUM_SUPPORTED = '8.5.1';
26
 
27
  /**
28
  * Holds the current version.
15
  *
16
  * @var string
17
  */
18
+ const CURRENT_RELEASE = '8.6.1';
19
 
20
  /**
21
  * The minimally supported version of Gutenberg by the plugin.
22
  *
23
  * @var string
24
  */
25
+ const MINIMUM_SUPPORTED = '8.6.1';
26
 
27
  /**
28
  * Holds the current version.
admin/config-ui/class-configuration-storage.php CHANGED
@@ -51,6 +51,8 @@ class WPSEO_Configuration_Storage {
51
  new WPSEO_Config_Field_Company_Logo(),
52
  new WPSEO_Config_Field_Person(),
53
  new WPSEO_Config_Field_Post_Type_Visibility(),
 
 
54
  ];
55
 
56
  $post_type_factory = new WPSEO_Config_Factory_Post_Type();
51
  new WPSEO_Config_Field_Company_Logo(),
52
  new WPSEO_Config_Field_Person(),
53
  new WPSEO_Config_Field_Post_Type_Visibility(),
54
+ new WPSEO_Config_Field_Tracking_Intro(),
55
+ new WPSEO_Config_Field_Tracking(),
56
  ];
57
 
58
  $post_type_factory = new WPSEO_Config_Factory_Post_Type();
admin/config-ui/class-configuration-structure.php CHANGED
@@ -50,6 +50,10 @@ class WPSEO_Configuration_Structure {
50
  'siteName',
51
  'separator',
52
  ],
 
 
 
 
53
  'newsletter' => [
54
  'mailchimpSignup',
55
  'suggestions',
@@ -84,6 +88,7 @@ class WPSEO_Configuration_Structure {
84
  );
85
 
86
  $this->add_step( 'title-template', __( 'Title settings', 'wordpress-seo' ), $this->fields['titleTemplate'] );
 
87
  $this->add_step( 'newsletter', __( 'Continue learning', 'wordpress-seo' ), $this->fields['newsletter'], true, true );
88
  $this->add_step( 'success', __( 'Success!', 'wordpress-seo' ), $this->fields['success'], true, true );
89
  }
50
  'siteName',
51
  'separator',
52
  ],
53
+ 'tracking' => [
54
+ 'trackingIntro',
55
+ 'tracking',
56
+ ],
57
  'newsletter' => [
58
  'mailchimpSignup',
59
  'suggestions',
88
  );
89
 
90
  $this->add_step( 'title-template', __( 'Title settings', 'wordpress-seo' ), $this->fields['titleTemplate'] );
91
+ $this->add_step( 'tracking', sprintf( __( 'Help us improve %s', 'wordpress-seo' ), 'Yoast SEO' ), $this->fields['tracking'] );
92
  $this->add_step( 'newsletter', __( 'Continue learning', 'wordpress-seo' ), $this->fields['newsletter'], true, true );
93
  $this->add_step( 'success', __( 'Success!', 'wordpress-seo' ), $this->fields['success'], true, true );
94
  }
admin/config-ui/fields/class-field-tracking-intro.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WPSEO plugin file.
4
+ *
5
+ * @package WPSEO\Admin\ConfigurationUI
6
+ */
7
+
8
+ /**
9
+ * Class WPSEO_Config_Field_Tracking_Intro.
10
+ */
11
+ class WPSEO_Config_Field_Tracking_Intro extends WPSEO_Config_Field {
12
+
13
+ /**
14
+ * WPSEO_Config_Field_Tracking_Intro constructor.
15
+ */
16
+ public function __construct() {
17
+ parent::__construct( 'trackingIntro', 'HTML' );
18
+
19
+ $html = '<p>' . esc_html__( 'At Yoast, we are always keen on providing the very best experience for you. To do so, we\'d like to collect some data about which other plugins and themes you have installed, and which features you use and don\'t use. Be assured that we\'ll never resell that data. And of course, as always, we won\'t collect any personal data about you or your visitors!', 'wordpress-seo' ) . '</p>';
20
+
21
+ $html .= '<p><a href="' . WPSEO_Shortlinker::get( 'https://yoa.st/usage-tracking' ) . '" target="_blank">' . esc_html__( 'Read more about our usage tracking.', 'wordpress-seo' ) . '</a></p>';
22
+
23
+ $this->set_property( 'html', $html );
24
+ }
25
+ }
admin/config-ui/fields/class-field-tracking.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WPSEO plugin file.
4
+ *
5
+ * @package WPSEO\Admin\ConfigurationUI
6
+ */
7
+
8
+ /**
9
+ * Class WPSEO_Config_Field_Tracking.
10
+ */
11
+ class WPSEO_Config_Field_Tracking extends WPSEO_Config_Field_Choice {
12
+
13
+ /**
14
+ * WPSEO_Config_Field_Tracking constructor.
15
+ */
16
+ public function __construct() {
17
+ parent::__construct( 'tracking' );
18
+
19
+ $this->set_property( 'label', __( 'Can we collect anonymous information about your website and its usage?', 'wordpress-seo' ) );
20
+
21
+ $this->add_choice( '0', __( 'No, I don\'t want to allow you to track my site data.', 'wordpress-seo' ) );
22
+ $this->add_choice( '1', __( 'Yes, you can track my site\'s data!', 'wordpress-seo' ) );
23
+ }
24
+
25
+ /**
26
+ * Set adapter.
27
+ *
28
+ * @param WPSEO_Configuration_Options_Adapter $adapter Adapter to register lookup on.
29
+ */
30
+ public function set_adapter( WPSEO_Configuration_Options_Adapter $adapter ) {
31
+ $adapter->add_custom_lookup(
32
+ $this->get_identifier(),
33
+ [ $this, 'get_data' ],
34
+ [ $this, 'set_data' ]
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Gets the option that is set for this field.
40
+ *
41
+ * @return string The value for the environment_type wpseo option.
42
+ */
43
+ public function get_data() {
44
+ $tracking = WPSEO_Options::get( 'tracking' );
45
+ if ( $tracking ) {
46
+ return '1';
47
+ }
48
+ return '0';
49
+ }
50
+
51
+ /**
52
+ * Set new data.
53
+ *
54
+ * @param string $tracking The site's environment type.
55
+ *
56
+ * @return bool Returns whether the value is successfully set.
57
+ */
58
+ public function set_data( $tracking ) {
59
+ $return = true;
60
+ if ( $this->get_data() !== $tracking ) {
61
+ $return = WPSEO_Options::set( 'tracking', $tracking );
62
+ }
63
+
64
+ return $return;
65
+ }
66
+ }
admin/formatter/class-post-metabox-formatter.php CHANGED
@@ -227,23 +227,6 @@ class WPSEO_Post_Metabox_Formatter implements WPSEO_Metabox_Formatter_Interface
227
  * @return string
228
  */
229
  private function get_metadesc_date() {
230
- $date = '';
231
-
232
- if ( $this->is_show_date_enabled() ) {
233
- $date = $this->date->format_translated( $this->post->post_date, 'M j, Y' );
234
- }
235
-
236
- return $date;
237
- }
238
-
239
- /**
240
- * Returns whether or not showing the date in the snippet preview is enabled.
241
- *
242
- * @return bool
243
- */
244
- private function is_show_date_enabled() {
245
- $key = sprintf( 'showdate-%s', $this->post->post_type );
246
-
247
- return WPSEO_Options::get( $key, true );
248
  }
249
  }
227
  * @return string
228
  */
229
  private function get_metadesc_date() {
230
+ return $this->date->format_translated( $this->post->post_date, 'M j, Y' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
  }
admin/taxonomy/class-taxonomy-content-fields.php CHANGED
@@ -47,6 +47,12 @@ class WPSEO_Taxonomy_Content_Fields extends WPSEO_Taxonomy_Fields {
47
  'hidden',
48
  ''
49
  ),
 
 
 
 
 
 
50
  ];
51
  /**
52
  * Filter: 'wpseo_taxonomy_content_fields' - Adds the possibility to register additional content fields.
47
  'hidden',
48
  ''
49
  ),
50
+ 'is_cornerstone' => $this->get_field_config(
51
+ '',
52
+ '',
53
+ 'hidden',
54
+ ''
55
+ ),
56
  ];
57
  /**
58
  * Filter: 'wpseo_taxonomy_content_fields' - Adds the possibility to register additional content fields.
admin/tracking/class-tracking-settings-data.php CHANGED
@@ -115,13 +115,10 @@ class WPSEO_Tracking_Settings_Data implements WPSEO_Collection {
115
  'company_or_person_user_id',
116
  'stripcategorybase',
117
  'noindex-post',
118
- 'showdate-post',
119
  'display-metabox-pt-post',
120
  'noindex-page',
121
- 'showdate-page',
122
  'display-metabox-pt-page',
123
  'noindex-attachment',
124
- 'showdate-attachment',
125
  'display-metabox-pt-attachment',
126
  'display-metabox-tax-category',
127
  'noindex-tax-category',
115
  'company_or_person_user_id',
116
  'stripcategorybase',
117
  'noindex-post',
 
118
  'display-metabox-pt-post',
119
  'noindex-page',
 
120
  'display-metabox-pt-page',
121
  'noindex-attachment',
 
122
  'display-metabox-pt-attachment',
123
  'display-metabox-tax-category',
124
  'noindex-tax-category',
admin/tracking/class-tracking.php CHANGED
@@ -45,6 +45,10 @@ class WPSEO_Tracking implements WPSEO_WordPress_Integration {
45
  * @param int $threshold The limit for the option.
46
  */
47
  public function __construct( $endpoint, $threshold ) {
 
 
 
 
48
  $this->endpoint = $endpoint;
49
  $this->threshold = $threshold;
50
  $this->current_time = time();
@@ -54,6 +58,10 @@ class WPSEO_Tracking implements WPSEO_WordPress_Integration {
54
  * Registers all hooks to WordPress.
55
  */
56
  public function register_hooks() {
 
 
 
 
57
  // Send tracking data on `admin_init`.
58
  add_action( 'admin_init', [ $this, 'send' ], 1 );
59
 
@@ -137,15 +145,6 @@ class WPSEO_Tracking implements WPSEO_WordPress_Integration {
137
  protected function should_send_tracking( $ignore_time_treshhold = false ) {
138
  global $pagenow;
139
 
140
- /**
141
- * Filter: 'wpseo_enable_tracking' - Enables the data tracking of Yoast SEO Premium.
142
- *
143
- * @api string $is_enabled The enabled state. Default is false.
144
- */
145
- if ( apply_filters( 'wpseo_enable_tracking', false ) === false ) {
146
- return false;
147
- }
148
-
149
  // Only send tracking on the main site of a multi-site instance. This returns true on non-multisite installs.
150
  if ( ! is_main_site() ) {
151
  return false;
@@ -192,4 +191,36 @@ class WPSEO_Tracking implements WPSEO_WordPress_Integration {
192
 
193
  return $collector;
194
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
45
  * @param int $threshold The limit for the option.
46
  */
47
  public function __construct( $endpoint, $threshold ) {
48
+ if ( ! $this->tracking_enabled() ) {
49
+ return;
50
+ }
51
+
52
  $this->endpoint = $endpoint;
53
  $this->threshold = $threshold;
54
  $this->current_time = time();
58
  * Registers all hooks to WordPress.
59
  */
60
  public function register_hooks() {
61
+ if ( ! $this->tracking_enabled() ) {
62
+ return;
63
+ }
64
+
65
  // Send tracking data on `admin_init`.
66
  add_action( 'admin_init', [ $this, 'send' ], 1 );
67
 
145
  protected function should_send_tracking( $ignore_time_treshhold = false ) {
146
  global $pagenow;
147
 
 
 
 
 
 
 
 
 
 
148
  // Only send tracking on the main site of a multi-site instance. This returns true on non-multisite installs.
149
  if ( ! is_main_site() ) {
150
  return false;
191
 
192
  return $collector;
193
  }
194
+
195
+ /**
196
+ * See if we should run tracking at all.
197
+ *
198
+ * @return bool True when we can track, false when we can't.
199
+ */
200
+ private function tracking_enabled() {
201
+ // Check if we're allowing tracking.
202
+ $tracking = WPSEO_Options::get( 'tracking' );
203
+
204
+ if ( $tracking === false ) {
205
+ return false;
206
+ }
207
+
208
+ // Save this state.
209
+ if ( $tracking === null ) {
210
+ /**
211
+ * Filter: 'wpseo_enable_tracking' - Enables the data tracking of Yoast SEO Premium and add-ons.
212
+ *
213
+ * @api string $is_enabled The enabled state. Default is false.
214
+ */
215
+ $tracking = apply_filters( 'wpseo_enable_tracking', false );
216
+
217
+ WPSEO_Options::set( 'tracking', $tracking );
218
+ }
219
+
220
+ if ( $tracking === false ) {
221
+ return false;
222
+ }
223
+
224
+ return true;
225
+ }
226
  }
admin/views/class-view-utils.php CHANGED
@@ -63,52 +63,4 @@ class Yoast_View_Utils {
63
 
64
  return $help_panel;
65
  }
66
-
67
- /**
68
- * Shows the search appearance settings for a post type.
69
- *
70
- * @param string|object $post_type The post type to show the search appearance settings for.
71
- * @param bool $paper_style Whether or not the paper style should be shown.
72
- *
73
- * @return void
74
- */
75
- public function show_post_type_settings( $post_type, $paper_style = false ) {
76
- if ( ! is_object( $post_type ) ) {
77
- $post_type = get_post_type_object( $post_type );
78
- }
79
-
80
- $show_post_type_help = $this->search_results_setting_help( $post_type );
81
- $noindex_option_name = 'noindex-' . $post_type->name;
82
-
83
- $this->form->index_switch(
84
- $noindex_option_name,
85
- $post_type->labels->name,
86
- $show_post_type_help->get_button_html() . $show_post_type_help->get_panel_html()
87
- );
88
-
89
- $this->form->show_hide_switch(
90
- 'showdate-' . $post_type->name,
91
- __( 'Date in Google Preview', 'wordpress-seo' )
92
- );
93
-
94
- $this->form->show_hide_switch(
95
- 'display-metabox-pt-' . $post_type->name,
96
- __( 'Show SEO settings for content type', 'wordpress-seo' )
97
- );
98
-
99
- $recommended_replace_vars = new WPSEO_Admin_Recommended_Replace_Vars();
100
- $editor_specific_replace_vars = new WPSEO_Admin_Editor_Specific_Replace_Vars();
101
-
102
- $editor = new WPSEO_Replacevar_Editor(
103
- $this->form,
104
- [
105
- 'title' => 'title-' . $post_type->name,
106
- 'description' => 'metadesc-' . $post_type->name,
107
- 'page_type_recommended' => $recommended_replace_vars->determine_for_post_type( $post_type->name ),
108
- 'page_type_specific' => $editor_specific_replace_vars->determine_for_post_type( $post_type->name ),
109
- 'paper_style' => $paper_style,
110
- ]
111
- );
112
- $editor->render();
113
- }
114
  }
63
 
64
  return $help_panel;
65
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
admin/views/class-yoast-feature-toggles.php CHANGED
@@ -143,6 +143,18 @@ class Yoast_Feature_Toggles {
143
  ),
144
  'order' => 90,
145
  ],
 
 
 
 
 
 
 
 
 
 
 
 
146
  (object) [
147
  'name' => __( 'REST API: Head endpoint', 'wordpress-seo' ),
148
  'setting' => 'enable_headless_rest_endpoints',
143
  ),
144
  'order' => 90,
145
  ],
146
+ (object) [
147
+ 'name' => __( 'Usage tracking', 'wordpress-seo' ),
148
+ 'label' => __( 'Usage tracking', 'wordpress-seo' ),
149
+ 'setting' => 'tracking',
150
+ 'read_more_label' => sprintf(
151
+ /* translators: 1: Yoast SEO */
152
+ __( 'Allow us to track some data about your site to improve our plugin.', 'wordpress-seo' ),
153
+ 'Yoast SEO'
154
+ ),
155
+ 'read_more_url' => 'https://yoa.st/usage-tracking',
156
+ 'order' => 95,
157
+ ],
158
  (object) [
159
  'name' => __( 'REST API: Head endpoint', 'wordpress-seo' ),
160
  'setting' => 'enable_headless_rest_endpoints',
admin/views/tabs/metas/paper-content/general/knowledge-graph.php CHANGED
@@ -44,6 +44,7 @@ $knowledge_graph_help = new WPSEO_Admin_Help_Panel(
44
  $yform->select( 'company_or_person', __( 'Organization or person', 'wordpress-seo' ), $yoast_free_kg_select_options, 'styled', false );
45
  ?>
46
  <div id="knowledge-graph-company">
 
47
  <?php
48
 
49
  /*
@@ -54,11 +55,9 @@ $knowledge_graph_help = new WPSEO_Admin_Help_Panel(
54
  $yoast_seo_company_logo = WPSEO_Options::get( 'company_logo', '' );
55
  if ( empty( $yoast_seo_company_name ) || empty( $yoast_seo_company_logo ) ) :
56
  ?>
57
- <div id="knowledge-graph-company-warning"></div>
58
- <?php endif; ?>
59
 
60
- <h3><?php esc_html_e( 'Organization', 'wordpress-seo' ); ?></h3>
61
- <?php
62
  $yform->textinput( 'company_name', __( 'Organization name', 'wordpress-seo' ), [ 'autocomplete' => 'organization' ] );
63
  $yform->media_input( 'company_logo', __( 'Organization logo', 'wordpress-seo' ) );
64
  ?>
44
  $yform->select( 'company_or_person', __( 'Organization or person', 'wordpress-seo' ), $yoast_free_kg_select_options, 'styled', false );
45
  ?>
46
  <div id="knowledge-graph-company">
47
+ <h3><?php esc_html_e( 'Organization', 'wordpress-seo' ); ?></h3>
48
  <?php
49
 
50
  /*
55
  $yoast_seo_company_logo = WPSEO_Options::get( 'company_logo', '' );
56
  if ( empty( $yoast_seo_company_name ) || empty( $yoast_seo_company_logo ) ) :
57
  ?>
58
+ <div id="knowledge-graph-company-warning"></div>
59
+ <?php endif;
60
 
 
 
61
  $yform->textinput( 'company_name', __( 'Organization name', 'wordpress-seo' ), [ 'autocomplete' => 'organization' ] );
62
  $yform->media_input( 'company_logo', __( 'Organization logo', 'wordpress-seo' ) );
63
  ?>
admin/views/tabs/metas/paper-content/post_type/post-type.php CHANGED
@@ -21,11 +21,6 @@ $yform->index_switch(
21
  $show_post_type_help->get_button_html() . $show_post_type_help->get_panel_html()
22
  );
23
 
24
- $yform->show_hide_switch(
25
- 'showdate-' . $wpseo_post_type->name,
26
- __( 'Date in Google Preview', 'wordpress-seo' )
27
- );
28
-
29
  $yform->show_hide_switch(
30
  'display-metabox-pt-' . $wpseo_post_type->name,
31
  /* translators: %s expands to an indexable object's name, like a post type or taxonomy */
21
  $show_post_type_help->get_button_html() . $show_post_type_help->get_panel_html()
22
  );
23
 
 
 
 
 
 
24
  $yform->show_hide_switch(
25
  'display-metabox-pt-' . $wpseo_post_type->name,
26
  /* translators: %s expands to an indexable object's name, like a post type or taxonomy */
config/composer/actions.php DELETED
@@ -1,263 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\Composer
6
- */
7
-
8
- namespace Yoast\WP\SEO\Composer;
9
-
10
- use Composer\Script\Event;
11
- use Exception;
12
- use Symfony\Component\DependencyInjection\ContainerBuilder;
13
- use Yoast\WP\SEO\Dependency_Injection\Container_Compiler;
14
-
15
- /**
16
- * Class to handle Composer actions and events.
17
- */
18
- class Actions {
19
-
20
- /**
21
- * Prefixes dependencies if composer install is ran with dev mode.
22
- *
23
- * Used in composer in the post-install script hook.
24
- *
25
- * @codeCoverageIgnore
26
- *
27
- * @param Event $event Composer event that triggered this script.
28
- *
29
- * @return void
30
- */
31
- public static function prefix_dependencies( Event $event ) {
32
- $io = $event->getIO();
33
-
34
- if ( ! $event->isDevMode() ) {
35
- $io->write( 'Not prefixing dependencies, due to not being in dev move.' );
36
-
37
- return;
38
- }
39
-
40
- if ( ! \file_exists( __DIR__ . '/../../vendor/bin/php-scoper' ) ) {
41
- $io->write( 'Not prefixing dependencies, due to PHP scoper not being installed' );
42
-
43
- return;
44
- }
45
-
46
- $io->write( 'Prefixing dependencies...' );
47
-
48
- $event_dispatcher = $event->getComposer()->getEventDispatcher();
49
- $event_dispatcher->dispatchScript( 'prefix-dependencies', $event->isDevMode() );
50
- }
51
-
52
- /**
53
- * Provides a coding standards option choice.
54
- *
55
- * @param Event $event Composer event.
56
- */
57
- public static function check_coding_standards( Event $event ) {
58
- $io = $event->getIO();
59
-
60
- $choices = [
61
- '1' => [ 'label' => 'Check staged files for coding standard warnings & errors.', 'command' => 'check-staged-cs' ],
62
- '2' => [ 'label' => 'Check current branch\'s changed files for coding standard warnings & errors.', 'command' => 'check-branch-cs' ],
63
- '3' => [ 'label' => 'Check for all coding standard errors.', 'command' => 'check-cs' ],
64
- '4' => [ 'label' => 'Check for all coding standard warnings & errors.', 'command' => 'check-cs-warnings' ],
65
- '5' => [ 'label' => 'Fix auto-fixable coding standards.', 'command' => 'fix-cs' ],
66
- '6' => [ 'label' => '[Premium] Check for coding standard warnings and errors.', 'command' => 'premium-check-cs' ],
67
- '7' => [ 'label' => '[Premium] Fix auto-fixable coding standards.', 'command' => 'premium-fix-cs' ],
68
- '8' => [ 'label' => 'Load coding standards configuration.', 'command' => 'config-yoastcs' ],
69
- ];
70
-
71
- $args = $event->getArguments();
72
- if ( empty( $args ) ) {
73
- foreach ( $choices as $choice => $data ) {
74
- $io->write( sprintf( '%d. %s', $choice, $data['label'] ) );
75
- }
76
-
77
- $choice = $io->ask( 'What do you want to do? ' );
78
- }
79
- else {
80
- $choice = $args[0];
81
- }
82
-
83
- if ( isset( $choices[ $choice ] ) ) {
84
- $event_dispatcher = $event->getComposer()->getEventDispatcher();
85
- $event_dispatcher->dispatchScript( $choices[ $choice ]['command'] );
86
- }
87
- else {
88
- $io->write( 'Unknown choice.' );
89
- }
90
- }
91
-
92
- /**
93
- * Compiles the dependency injection container.
94
- *
95
- * Used the composer compile-dependency-injection-container command.
96
- *
97
- * @codeCoverageIgnore
98
- *
99
- * @param Event $event Composer event that triggered this script.
100
- *
101
- * @return void
102
- */
103
- public static function compile_dependency_injection_container( Event $event ) {
104
- $io = $event->getIO();
105
-
106
- if ( ! \class_exists( ContainerBuilder::class ) ) {
107
- $io->write( 'Not compiling dependency injection container, due to the container builder not being installed' );
108
-
109
- return;
110
- }
111
-
112
- $io->write( 'Compiling the dependency injection container...' );
113
-
114
- // Pas true as debug to force a recheck of the container.
115
- Container_Compiler::compile( true );
116
-
117
- $io->write( 'The dependency injection container has been compiled.' );
118
- }
119
-
120
- /**
121
- * Runs PHPCS on the staged files.
122
- *
123
- * Used the composer check-staged-cs command.
124
- *
125
- * @codeCoverageIgnore
126
- *
127
- * @return void
128
- */
129
- public static function check_staged_cs() {
130
- self::check_cs_for_changed_files( '--staged' );
131
- }
132
-
133
- /**
134
- * Runs PHPCS on the staged files.
135
- *
136
- * Used the composer check-staged-cs command.
137
- *
138
- * @codeCoverageIgnore
139
- *
140
- * @param Event $event Composer event that triggered this script.
141
- *
142
- * @return void
143
- */
144
- public static function check_branch_cs( Event $event ) {
145
- $args = $event->getArguments();
146
- if ( empty( $args ) ) {
147
- self::check_cs_for_changed_files( 'trunk' );
148
-
149
- return;
150
- }
151
- self::check_cs_for_changed_files( $args[0] );
152
- }
153
-
154
- /**
155
- * Runs PHPCS on changed files compared to some git reference.
156
- *
157
- * @param string $compare The git reference.
158
- *
159
- * @codeCoverageIgnore
160
- *
161
- * @return void
162
- */
163
- private static function check_cs_for_changed_files( $compare ) {
164
- \exec( 'git diff --name-only --diff-filter=d ' . \escapeshellarg( $compare ), $files );
165
- $files = \array_filter(
166
- $files,
167
- function( $file ) {
168
- return \substr( $file, -4 ) === '.php';
169
- }
170
- );
171
-
172
- if ( empty( $files ) ) {
173
- echo 'No files to compare! Exiting.' . PHP_EOL;
174
-
175
- return;
176
- }
177
-
178
- \system( 'composer check-cs -- ' . \implode( ' ', \array_map( 'escapeshellarg', $files ) ) );
179
- }
180
-
181
- /**
182
- * Generates a migration.
183
- *
184
- * @param Event $event Composer event that triggered this script.
185
- *
186
- * @return void
187
- *
188
- * @throws Exception If no migration name is provided.
189
- */
190
- public static function generate_migration( Event $event ) {
191
- $args = $event->getArguments();
192
- if ( empty( $args[0] ) ) {
193
- throw new Exception( 'You must provide an argument with the migration name.' );
194
- }
195
- $name = $args[0];
196
- $timestamp = \gmdate( 'YmdHis', \time() );
197
-
198
- // Camelcase the name.
199
- $name = \preg_replace( '/\\s+/', '_', $name );
200
- $parts = \explode( '_', $name );
201
- $name = '';
202
- foreach ( $parts as $word ) {
203
- $name .= \ucfirst( $word );
204
- }
205
-
206
- $correct_class_name_regex = '/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/';
207
- if ( ! \preg_match( $correct_class_name_regex, $name ) ) {
208
- throw new Exception( "$name is not a valid migration name." );
209
- }
210
- if ( \class_exists( $name ) ) {
211
- throw new Exception( "A class with the name $name already exists." );
212
- }
213
-
214
- $file_name = $timestamp . '_' . $name . '.php';
215
-
216
- $template = <<<TPL
217
- <?php
218
- /**
219
- * Yoast SEO Plugin File.
220
- *
221
- * @package Yoast\WP\SEO\Config\Migrations
222
- */
223
-
224
- namespace Yoast\WP\SEO\Config\Migrations;
225
-
226
- use Yoast\WP\Lib\Migrations\Migration;
227
-
228
- /**
229
- * {$name} class.
230
- */
231
- class {$name} extends Migration {
232
-
233
- /**
234
- * The plugin this migration belongs to.
235
- *
236
- * @var string
237
- */
238
- public static \$plugin = 'free';
239
-
240
- /**
241
- * Migration up.
242
- *
243
- * @return void
244
- */
245
- public function up() {
246
-
247
- }
248
-
249
- /**
250
- * Migration down.
251
- *
252
- * @return void
253
- */
254
- public function down() {
255
-
256
- }
257
- }
258
-
259
- TPL;
260
-
261
- \file_put_contents( __DIR__ . '/../../src/config/migrations/' . $file_name, $template );
262
- }
263
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/dependency-injection/container-compiler.php DELETED
@@ -1,57 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\Dependency_Injection
6
- */
7
-
8
- namespace Yoast\WP\SEO\Dependency_Injection;
9
-
10
- use Exception;
11
- use Symfony\Component\Config\ConfigCache;
12
- use Symfony\Component\DependencyInjection\ContainerBuilder;
13
- use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
14
-
15
- /**
16
- * This class is responsible for compiling the dependency injection container.
17
- */
18
- class Container_Compiler {
19
-
20
- /**
21
- * Compiles the dependency injection container.
22
- *
23
- * @param boolean $debug If false the container will only be re-compiled if it does not yet already exist.
24
- *
25
- * @throws Exception If compiling the container fails.
26
- *
27
- * @return void
28
- */
29
- public static function compile( $debug ) {
30
- $file = __DIR__ . '/../../src/generated/container.php';
31
- $cache = new ConfigCache( $file, $debug );
32
-
33
- if ( ! $cache->isFresh() ) {
34
- if ( ! \defined( 'WPSEO_VERSION' ) ) {
35
- \define( 'WPSEO_VERSION', 'COMPILING' );
36
- }
37
-
38
- $container_builder = new ContainerBuilder();
39
- $container_builder->addCompilerPass( new Loader_Pass() );
40
- $loader = new Custom_Loader( $container_builder );
41
- $loader->load( 'config/dependency-injection/services.php' );
42
- $container_builder->compile();
43
-
44
- $dumper = new PhpDumper( $container_builder );
45
- $code = $dumper->dump(
46
- [
47
- 'class' => 'Cached_Container',
48
- 'namespace' => 'Yoast\WP\SEO\Generated',
49
- ]
50
- );
51
- $code = \str_replace( 'Symfony\\Component\\DependencyInjection', 'YoastSEO_Vendor\\Symfony\\Component\\DependencyInjection', $code );
52
- $code = \str_replace( 'Symfony\\\\Component\\\\DependencyInjection', 'YoastSEO_Vendor\\\\Symfony\\\\Component\\\\DependencyInjection', $code );
53
-
54
- $cache->write( $code, $container_builder->getResources() );
55
- }
56
- }
57
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/dependency-injection/custom-loader.php DELETED
@@ -1,195 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\Dependency_Injection
6
- */
7
-
8
- namespace Yoast\WP\SEO\Dependency_Injection;
9
-
10
- use ReflectionException;
11
- use Symfony\Component\Config\FileLocator;
12
- use Symfony\Component\Config\Resource\GlobResource;
13
- use Symfony\Component\DependencyInjection\ContainerBuilder;
14
- use Symfony\Component\DependencyInjection\Definition;
15
- use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
16
- use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
17
-
18
- /**
19
- * This class is mostly a direct copy-paste of the symfony PhpFileLoader class.
20
- * It's been adapted to allow automatic discovery based on not just PSR-4 but also the Yoast standards.
21
- */
22
- class Custom_Loader extends PhpFileLoader {
23
-
24
- /**
25
- * Custom_Loader constructor.
26
- *
27
- * @param ContainerBuilder $container The ContainerBuilder to load classes for.
28
- */
29
- public function __construct( ContainerBuilder $container ) {
30
- parent::__construct( $container, new FileLocator( __DIR__ . '/../..' ) );
31
- }
32
-
33
- /**
34
- * Transforms a path to a class name using the class map.
35
- *
36
- * @param string $path The path of the class.
37
- *
38
- * @return bool|string The classname.
39
- */
40
- private function getClassFromClassMap( $path ) {
41
- static $class_map;
42
-
43
- if ( ! $class_map ) {
44
- $class_map = require __DIR__ . '/../../vendor/composer/autoload_classmap.php';
45
- }
46
-
47
- foreach ( $class_map as $class => $class_path ) {
48
- if ( $path === $class_path ) {
49
- return $class;
50
- }
51
- }
52
-
53
- return false;
54
- }
55
-
56
- /**
57
- * Registers a set of classes as services using PSR-4 for discovery.
58
- *
59
- * @param Definition $prototype A definition to use as template.
60
- * @param string $namespace The namespace prefix of classes in the scanned directory.
61
- * @param string $resource The directory to look for classes, glob-patterns allowed.
62
- * @param string $exclude A globed path of files to exclude.
63
- *
64
- * @throws InvalidArgumentException If invalid arguments are supplied.
65
- *
66
- * @return void
67
- */
68
- public function registerClasses( Definition $prototype, $namespace, $resource, $exclude = null ) {
69
- if ( \substr( $namespace, -1 ) !== '\\' ) {
70
- throw new InvalidArgumentException( \sprintf( 'Namespace prefix must end with a "\\": %s.', $namespace ) );
71
- }
72
- if ( ! \preg_match( '/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+\\\\)++$/', $namespace ) ) {
73
- throw new InvalidArgumentException( \sprintf( 'Namespace is not a valid PSR-4 prefix: %s.', $namespace ) );
74
- }
75
-
76
- $classes = $this->findClasses( $namespace, $resource, $exclude );
77
- // Prepare for deep cloning.
78
- // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- Reason: There's no way for user input to get in between serialize and unserialize.
79
- $serialized_prototype = \serialize( $prototype );
80
- $interfaces = [];
81
- $singly_implemented = [];
82
-
83
- foreach ( $classes as $class => $error_message ) {
84
- if ( \interface_exists( $class, false ) ) {
85
- $interfaces[] = $class;
86
- }
87
- else {
88
- // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize -- Reason: There's no way for user input to get in between serialize and unserialize.
89
- $this->setDefinition( $class, $definition = \unserialize( $serialized_prototype ) );
90
- if ( $error_message !== null ) {
91
- $definition->addError( $error_message );
92
-
93
- continue;
94
- }
95
- foreach ( \class_implements( $class, false ) as $interface ) {
96
- $singly_implemented[ $interface ] = isset( $singly_implemented[ $interface ] ) ? false : $class;
97
- }
98
- }
99
- }
100
- foreach ( $interfaces as $interface ) {
101
- if ( ! empty( $singly_implemented[ $interface ] ) ) {
102
- $this->container->setAlias( $interface, $singly_implemented[ $interface ] )
103
- ->setPublic( false );
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Finds classes based on a given pattern and exclude pattern.
110
- *
111
- * @param string $namespace The namespace prefix of classes in the scanned directory.
112
- * @param string $pattern The directory to look for classes, glob-patterns allowed.
113
- * @param string $exclude A globed path of files to exclude.
114
- *
115
- * @throws InvalidArgumentException If invalid arguments were supplied.
116
- *
117
- * @return array The found classes.
118
- */
119
- private function findClasses( $namespace, $pattern, $exclude ) {
120
- $parameter_bag = $this->container->getParameterBag();
121
-
122
- $exclude_paths = [];
123
- $exclude_prefix = null;
124
- if ( $exclude ) {
125
- $exclude = $parameter_bag->unescapeValue( $parameter_bag->resolveValue( $exclude ) );
126
- foreach ( $this->glob( $exclude, true, $resource ) as $path => $info ) {
127
- if ( $exclude_prefix === null ) {
128
- $exclude_prefix = $resource->getPrefix();
129
- }
130
-
131
- // Normalize Windows slashes.
132
- $exclude_paths[ \str_replace( '\\', '/', $path ) ] = true;
133
- }
134
- }
135
-
136
- $pattern = $parameter_bag->unescapeValue( $parameter_bag->resolveValue( $pattern ) );
137
- $classes = [];
138
- $ext_regexp = \defined( 'HHVM_VERSION' ) ? '/\\.(?:php|hh)$/' : '/\\.php$/';
139
- $prefix_len = null;
140
- foreach ( $this->glob( $pattern, true, $resource ) as $path => $info ) {
141
- if ( $prefix_len === null ) {
142
- $prefix_len = \strlen( $resource->getPrefix() );
143
-
144
- if ( $exclude_prefix && \strpos( $exclude_prefix, $resource->getPrefix() ) !== 0 ) {
145
- throw new InvalidArgumentException( \sprintf( 'Invalid "exclude" pattern when importing classes for "%s": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $namespace, $exclude, $pattern ) );
146
- }
147
- }
148
-
149
- if ( isset( $exclude_paths[ \str_replace( '\\', '/', $path ) ] ) ) {
150
- continue;
151
- }
152
-
153
- if ( ! \preg_match( $ext_regexp, $path, $m ) || ! $info->isReadable() ) {
154
- continue;
155
- }
156
- $class = $this->getClassFromClassMap( $path );
157
-
158
- if ( ! $class || ! \preg_match( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $class ) ) {
159
- continue;
160
- }
161
-
162
- try {
163
- $r = $this->container->getReflectionClass( $class );
164
- } catch ( ReflectionException $e ) {
165
- $classes[ $class ] = \sprintf(
166
- 'While discovering services from namespace "%s", an error was thrown when processing the class "%s": "%s".',
167
- $namespace,
168
- $class,
169
- $e->getMessage()
170
- );
171
- continue;
172
- }
173
- // Check to make sure the expected class exists.
174
- if ( ! $r ) {
175
- throw new InvalidArgumentException( \sprintf( 'Expected to find class "%s" in file "%s" while importing services from resource "%s", but it was not found! Check the namespace prefix used with the resource.', $class, $path, $pattern ) );
176
- }
177
-
178
- if ( $r->isInstantiable() || $r->isInterface() ) {
179
- $classes[ $class ] = null;
180
- }
181
- }
182
-
183
- // Track only for new & removed files.
184
- if ( $resource instanceof GlobResource ) {
185
- $this->container->addResource( $resource );
186
- }
187
- else {
188
- foreach ( $resource as $path ) {
189
- $this->container->fileExists( $path, false );
190
- }
191
- }
192
-
193
- return $classes;
194
- }
195
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/dependency-injection/loader-pass.php DELETED
@@ -1,82 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\Dependency_Injection
6
- */
7
-
8
- namespace Yoast\WP\SEO\Dependency_Injection;
9
-
10
- use ReflectionClass;
11
- use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
12
- use Symfony\Component\DependencyInjection\ContainerBuilder;
13
- use Symfony\Component\DependencyInjection\Definition;
14
- use Yoast\WP\Lib\Migrations\Migration;
15
- use Yoast\WP\SEO\Commands\Command_Interface;
16
- use Yoast\WP\SEO\Initializers\Initializer_Interface;
17
- use Yoast\WP\SEO\Integrations\Integration_Interface;
18
- use Yoast\WP\SEO\Loader;
19
- use Yoast\WP\SEO\Routes\Route_Interface;
20
-
21
- /**
22
- * A pass is a step in the compilation process of the container.
23
- *
24
- * This step will automatically ensure all classes implementing the Integration interface
25
- * are registered with the Loader class.
26
- */
27
- class Loader_Pass implements CompilerPassInterface {
28
-
29
- /**
30
- * Checks all definitions to ensure all classes implementing the Integration interface
31
- * are registered with the Loader class.
32
- *
33
- * @param ContainerBuilder $container The container.
34
- */
35
- public function process( ContainerBuilder $container ) {
36
- if ( ! $container->hasDefinition( Loader::class ) ) {
37
- return;
38
- }
39
-
40
- $loader_definition = $container->getDefinition( Loader::class );
41
- $definitions = $container->getDefinitions();
42
-
43
- foreach ( $definitions as $definition ) {
44
- $this->process_definition( $definition, $loader_definition );
45
- }
46
- }
47
-
48
- /**
49
- * Processes a definition in the container.
50
- *
51
- * @param Definition $definition The definition to process.
52
- * @param Definition $loader_definition The loader definition.
53
- */
54
- private function process_definition( Definition $definition, Definition $loader_definition ) {
55
- $class = $definition->getClass();
56
-
57
- if ( \is_subclass_of( $class, Initializer_Interface::class ) ) {
58
- $loader_definition->addMethodCall( 'register_initializer', [ $class ] );
59
- }
60
-
61
- if ( \is_subclass_of( $class, Integration_Interface::class ) ) {
62
- $loader_definition->addMethodCall( 'register_integration', [ $class ] );
63
- }
64
-
65
- if ( \is_subclass_of( $class, Route_Interface::class ) ) {
66
- $loader_definition->addMethodCall( 'register_route', [ $class ] );
67
- }
68
-
69
- if ( \is_subclass_of( $class, Command_Interface::class ) ) {
70
- $loader_definition->addMethodCall( 'register_command', [ $class ] );
71
- }
72
-
73
- if ( \is_subclass_of( $class, Migration::class ) ) {
74
- $reflect = new ReflectionClass( $class );
75
- $path = $reflect->getFileName();
76
- $file = \basename( $path, '.php' );
77
- $version = \explode( '_', $file )[0];
78
- $plugin = $class::$plugin;
79
- $loader_definition->addMethodCall( 'register_migration', [ $plugin, $version, $class ] );
80
- }
81
- }
82
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/dependency-injection/services.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\Dependency_Injection
6
- */
7
-
8
- namespace Yoast\WP\SEO\Dependency_Injection;
9
-
10
- use Symfony\Component\DependencyInjection\Definition;
11
- use WPSEO_Admin_Asset_Manager;
12
- use WPSEO_Breadcrumbs;
13
- use WPSEO_Frontend;
14
- use WPSEO_Replace_Vars;
15
- use Yoast\WP\Lib\Migrations\Adapter;
16
- use Yoast\WP\SEO\WordPress\Wrapper;
17
- use YoastSEO_Vendor\Symfony\Component\DependencyInjection\ContainerInterface;
18
-
19
- /**
20
- * @var $container \Symfony\Component\DependencyInjection\ContainerBuilder
21
- */
22
- // WordPress factory functions.
23
- $container->register( 'wpdb', 'wpdb' )->setFactory( [ Wrapper::class, 'get_wpdb' ] );
24
-
25
- // Legacy classes.
26
- $container->register( WPSEO_Replace_Vars::class, WPSEO_Replace_Vars::class )->setFactory( [ Wrapper::class, 'get_replace_vars' ] )->setPublic( true );
27
- $container->register( WPSEO_Admin_Asset_Manager::class, WPSEO_Admin_Asset_Manager::class )->setFactory( [ Wrapper::class, 'get_admin_asset_manager' ] )->setPublic( true );
28
-
29
- // Backwards-compatibility classes in the global namespace.
30
- $container->register( WPSEO_Breadcrumbs::class, WPSEO_Breadcrumbs::class )->setAutowired( true )->setPublic( true );
31
- $container->register( WPSEO_Frontend::class, WPSEO_Frontend::class )->setAutowired( true )->setPublic( true );
32
-
33
- // The container itself.
34
- $container->setAlias( ContainerInterface::class, 'service_container' );
35
-
36
- // Required for the migrations framework.
37
- $container->register( Adapter::class, Adapter::class )->setAutowired( true )->setPublic( true );
38
-
39
- $excluded_files = [
40
- 'main.php',
41
- ];
42
-
43
- $excluded_directories = [
44
- 'models',
45
- 'loaders',
46
- 'wordpress',
47
- 'generated',
48
- 'orm',
49
- 'backwards-compatibility',
50
- 'surfaces/values',
51
- 'presenters',
52
- ];
53
-
54
- $excluded = \implode( ',', \array_merge( $excluded_directories, $excluded_files ) );
55
-
56
- $base_definition = new Definition();
57
-
58
- $base_definition
59
- ->setAutowired( true )
60
- ->setAutoconfigured( true )
61
- ->setPublic( true );
62
-
63
- /**
64
- * @var $loader \Yoast\WP\SEO\Dependency_Injection\Custom_Loader
65
- */
66
- $loader->registerClasses( $base_definition, 'Yoast\\WP\\SEO\\', 'src/*', 'src/{' . $excluded . '}' );
67
-
68
- if ( \file_exists( __DIR__ . '/../../premium/config/dependency-injection/services.php' ) ) {
69
- include __DIR__ . '/../../premium/config/dependency-injection/services.php';
70
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-codeshift/remove-vendor-prefixing-array-key-visitor.php DELETED
@@ -1,38 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\PHP_CodeShift
6
- */
7
-
8
- namespace Yoast\WP\SEO\PHP_CodeShift;
9
-
10
- use PhpParser\Node;
11
- use PhpParser\Node\Expr\ArrayItem;
12
- use PhpParser\Node\Scalar\String_;
13
- use PhpParser\NodeVisitorAbstract;
14
-
15
- /**
16
- * Class Vendor_Prefixing_Visitor
17
- */
18
- class Remove_Vendor_Prefixing_Array_Key_Visitor extends NodeVisitorAbstract {
19
-
20
- /**
21
- * Removes vendor prefixes from array keys.
22
- *
23
- * @param Node $node The node being visited.
24
- *
25
- * @return Node The possibly modified node.
26
- */
27
- public function leaveNode( Node $node ) {
28
- if ( ! $node instanceof ArrayItem ) {
29
- return $node;
30
- }
31
-
32
- if ( $node->key instanceof String_ && \strpos( $node->key->value, \YOAST_VENDOR_NS_PREFIX ) !== false ) {
33
- $node->key->value = \str_replace( \YOAST_VENDOR_NS_PREFIX . '\\', '', $node->key->value );
34
- }
35
-
36
- return $node;
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-codeshift/remove-vendor-prefixing-codemod.php DELETED
@@ -1,34 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\PHP_CodeShift
6
- */
7
-
8
- namespace Yoast\WP\SEO\PHP_CodeShift;
9
-
10
- use Codeshift\AbstractCodemod;
11
-
12
- /**
13
- * Class Vendor_Prefixing_Codemod
14
- */
15
- class Remove_Vendor_Prefixing_Codemod extends AbstractCodemod {
16
-
17
- /**
18
- * Sets up the environment required to do the code modifications.
19
- */
20
- public function init() {
21
- \define( 'YoastSEO_Vendor\RUCKUSING_BASE', __DIR__ . '/../../fake-ruckusing' );
22
-
23
- \define( 'YOAST_VENDOR_NS_PREFIX', 'YoastSEO_Vendor' );
24
- \define( 'YOAST_VENDOR_DEFINE_PREFIX', 'YOASTSEO_VENDOR__' );
25
- \define( 'YOAST_VENDOR_PREFIX_DIRECTORY', 'vendor_prefixed' );
26
-
27
- $visitor = new Remove_Vendor_Prefixing_Visitor();
28
- $comment_visitor = new Remove_Vendor_Prefixing_Comment_Visitor();
29
- $array_key_visitor = new Remove_Vendor_Prefixing_Array_Key_Visitor();
30
- $this->addTraversalTransform( $visitor, $comment_visitor, $array_key_visitor );
31
- }
32
- }
33
-
34
- return 'Yoast\WP\SEO\PHP_CodeShift\Remove_Vendor_Prefixing_Codemod';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-codeshift/remove-vendor-prefixing-comment-visitor.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\PHP_CodeShift
6
- */
7
-
8
- namespace Yoast\WP\SEO\PHP_CodeShift;
9
-
10
- use PhpParser\Comment\Doc;
11
- use PhpParser\Node;
12
- use PhpParser\NodeVisitorAbstract;
13
-
14
- /**
15
- * Class Vendor_Prefixing_Visitor
16
- */
17
- class Remove_Vendor_Prefixing_Comment_Visitor extends NodeVisitorAbstract {
18
-
19
- /**
20
- * Removes vendor prefixes from comments.
21
- *
22
- * @param Node $node The node being visited.
23
- *
24
- * @return Node The possibly modified node.
25
- */
26
- public function leaveNode( Node $node ) {
27
- $comment = $node->getDocComment();
28
-
29
- if ( $comment && \strpos( $comment->getText(), \YOAST_VENDOR_NS_PREFIX ) !== false ) {
30
- $updated_text = \str_replace( \YOAST_VENDOR_NS_PREFIX . '\\', '', $comment->getText() );
31
- $updated_comment = new Doc( $updated_text, $comment->getLine(), $comment->getFilePos(), $comment->getTokenPos() );
32
- $node->setDocComment( $updated_comment );
33
- }
34
-
35
- return $node;
36
- }
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-codeshift/remove-vendor-prefixing-visitor.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
- /**
3
- * Yoast SEO Plugin File.
4
- *
5
- * @package Yoast\YoastSEO\PHP_CodeShift
6
- */
7
-
8
- namespace Yoast\WP\SEO\PHP_CodeShift;
9
-
10
- use PhpParser\Node;
11
- use PhpParser\Node\Name;
12
- use PhpParser\NodeVisitorAbstract;
13
-
14
- /**
15
- * Class Vendor_Prefixing_Visitor
16
- */
17
- class Remove_Vendor_Prefixing_Visitor extends NodeVisitorAbstract {
18
-
19
- /**
20
- * Removes vendor prefixes from use statements.
21
- *
22
- * @param Node $node The node being visited.
23
- *
24
- * @return Node The possibly modified node.
25
- */
26
- public function leaveNode( Node $node ) {
27
- if ( ! $node instanceof Name ) {
28
- return $node;
29
- }
30
-
31
- if ( $node->getFirst() !== \YOAST_VENDOR_NS_PREFIX ) {
32
- return $node;
33
- }
34
-
35
- return $node->slice( 1 );
36
- }
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-scoper/dependency-injection.inc.php DELETED
@@ -1,41 +0,0 @@
1
- <?php
2
-
3
- declare( strict_types=1 );
4
-
5
- use Isolated\Symfony\Component\Finder\Finder;
6
-
7
- return array(
8
-
9
- /*
10
- * By default when running php-scoper add-prefix, it will prefix all relevant code found in the current working
11
- * directory. You can however define which files should be scoped by defining a collection of Finders in the
12
- * following configuration key.
13
- *
14
- * For more see: https://github.com/humbug/php-scoper#finders-and-paths
15
- */
16
- 'finders' => [
17
- Finder::create()->files()->in( 'vendor/symfony/dependency-injection' )->name( [
18
- 'Container.php', 'ContainerInterface.php', 'ResettableContainerInterface.php', 'LICENSE', 'composer.json'
19
- ] ),
20
- Finder::create()->files()->in( 'vendor/symfony/dependency-injection/Argument' )->name( [ 'RewindableGenerator.php' ] ),
21
- Finder::create()->files()->in( 'vendor/symfony/dependency-injection/Exception' )->name( [
22
- 'InvalidArgumentException.php', 'LogicException.php', 'RuntimeException.php',
23
- 'ServiceCircularReferenceException.php', 'ServiceNotFoundException.php', 'EnvNotFoundException.php',
24
- 'ParameterCircularReferenceException.php', 'ExceptionInterface.php'
25
- ] ),
26
- Finder::create()->files()->in( 'vendor/symfony/dependency-injection/ParameterBag' )->name( [
27
- 'FrozenParameterBag.php', 'ParameterBagInterface.php', 'EnvPlaceholderParameterBag.php', 'ParameterBag.php'
28
- ] ),
29
- ],
30
-
31
- /*
32
- * When scoping PHP files, there will be scenarios where some of the code being scoped indirectly references the
33
- * original namespace. These will include, for example, strings or string manipulations. PHP-Scoper has limited
34
- * support for prefixing such strings. To circumvent that, you can define patchers to manipulate the file to your
35
- * heart contents.
36
- *
37
- * For more see: https://github.com/humbug/php-scoper#patchers
38
- */
39
- 'patchers' => [],
40
-
41
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config/php-scoper/guzzlehttp.inc.php DELETED
@@ -1,56 +0,0 @@
1
- <?php
2
-
3
- declare( strict_types=1 );
4
-
5
- use Isolated\Symfony\Component\Finder\Finder;
6
-
7
- return array(
8
-
9
- /*
10
- * By default when running php-scoper add-prefix, it will prefix all relevant code found in the current working
11
- * directory. You can however define which files should be scoped by defining a collection of Finders in the
12 </