Version Description
Download this release
Release Info
Developer | Yoast |
Plugin | Yoast SEO |
Version | 8.0 |
Comparing to | |
See all releases |
Code changes from version 7.9.1 to 8.0
- admin/ajax.php +15 -0
- admin/class-admin-asset-dev-server-location.php +1 -20
- admin/class-admin-asset-manager.php +86 -35
- admin/class-admin-gutenberg-compatibility-notification.php +89 -0
- admin/class-admin.php +7 -1
- admin/class-cornerstone-field.php +0 -57
- admin/class-cornerstone.php +1 -1
- admin/class-expose-shortlinks.php +32 -0
- admin/class-gutenberg-compatibility.php +101 -0
- admin/class-keyword-synonyms-modal.php +7 -2
- admin/class-multiple-keywords-modal.php +66 -0
- admin/class-structured-data-blocks.php +50 -0
- admin/class-yoast-form.php +13 -2
- admin/class-yoast-network-admin.php +299 -0
- admin/class-yoast-network-settings-api.php +157 -0
- admin/formatter/class-metabox-formatter.php +36 -2
- admin/menu/class-admin-menu.php +19 -150
- admin/menu/class-base-menu.php +258 -0
- admin/menu/class-network-admin-menu.php +47 -35
- admin/metabox/class-metabox-add-keyword-tab.php +0 -69
- admin/metabox/{class-metabox-keyword-synonyms-button.php → class-metabox-keyword-synonyms-config.php} +9 -15
- admin/metabox/class-metabox-multiple-keywords-config.php +44 -0
- admin/metabox/class-metabox-section-react.php +99 -0
- admin/metabox/class-metabox-tab-section.php +9 -0
- admin/metabox/class-metabox.php +24 -212
- admin/pages/network.php +6 -139
- admin/taxonomy/class-taxonomy-content-fields.php +6 -25
- admin/taxonomy/class-taxonomy-fields-presenter.php +0 -38
- admin/taxonomy/class-taxonomy-metabox.php +5 -61
- admin/taxonomy/class-taxonomy.php +1 -2
- admin/views/tabs/network/general.php +51 -0
- admin/views/tabs/network/restore-site.php +34 -0
- css/dist/{admin-global-791-rtl.min.css → admin-global-800-rtl.min.css} +0 -0
- css/dist/{admin-global-791.min.css → admin-global-800.min.css} +0 -0
- css/dist/{adminbar-791-rtl.min.css → adminbar-800-rtl.min.css} +0 -0
- css/dist/{adminbar-791.min.css → adminbar-800.min.css} +0 -0
- css/dist/{alerts-791-rtl.min.css → alerts-800-rtl.min.css} +0 -0
- css/dist/{alerts-791.min.css → alerts-800.min.css} +0 -0
- css/dist/{dashboard-791-rtl.min.css → dashboard-800-rtl.min.css} +0 -0
- css/dist/{dashboard-791.min.css → dashboard-800.min.css} +0 -0
- css/dist/{edit-page-791-rtl.min.css → edit-page-800-rtl.min.css} +0 -0
- css/dist/{edit-page-791.min.css → edit-page-800.min.css} +0 -0
- css/dist/{featured-image-791-rtl.min.css → featured-image-800-rtl.min.css} +0 -0
- css/dist/{featured-image-791.min.css → featured-image-800.min.css} +0 -0
- css/dist/{filter-explanation-791-rtl.min.css → filter-explanation-800-rtl.min.css} +0 -0
- css/dist/{filter-explanation-791.min.css → filter-explanation-800.min.css} +0 -0
- css/dist/{inside-editor-791-rtl.min.css → inside-editor-800-rtl.min.css} +0 -0
- css/dist/{inside-editor-791.min.css → inside-editor-800.min.css} +0 -0
- css/dist/metabox-791-rtl.min.css +0 -1
- css/dist/metabox-791.min.css +0 -1
- css/dist/metabox-800-rtl.min.css +1 -0
- css/dist/metabox-800.min.css +1 -0
- css/dist/{metabox-primary-category-791-rtl.min.css → metabox-primary-category-800-rtl.min.css} +0 -0
- css/dist/{metabox-primary-category-791.min.css → metabox-primary-category-800.min.css} +0 -0
- css/dist/{search-appearance-791-rtl.min.css → search-appearance-800-rtl.min.css} +0 -0
- css/dist/{search-appearance-791.min.css → search-appearance-800.min.css} +0 -0
- css/dist/snippet-791-rtl.min.css +0 -1
- css/dist/snippet-791.min.css +0 -1
- css/dist/structured-data-blocks-800-rtl.min.css +1 -0
- css/dist/structured-data-blocks-800.min.css +1 -0
- css/dist/{toggle-switch-791-rtl.min.css → toggle-switch-800-rtl.min.css} +0 -0
- css/dist/{toggle-switch-791.min.css → toggle-switch-800.min.css} +0 -0
- css/dist/{wpseo-dismissible-791-rtl.min.css → wpseo-dismissible-800-rtl.min.css} +0 -0
- css/dist/{wpseo-dismissible-791.min.css → wpseo-dismissible-800.min.css} +0 -0
- css/dist/{yoast-components-791-rtl.min.css → yoast-components-800-rtl.min.css} +0 -0
- css/dist/{yoast-components-791.min.css → yoast-components-800.min.css} +0 -0
- css/dist/{yoast-extensions-791-rtl.min.css → yoast-extensions-800-rtl.min.css} +0 -0
- css/dist/{yoast-extensions-791.min.css → yoast-extensions-800.min.css} +0 -0
- css/dist/{yst_plugin_tools-791-rtl.min.css → yst_plugin_tools-800-rtl.min.css} +0 -0
- css/dist/{yst_plugin_tools-791.min.css → yst_plugin_tools-800.min.css} +0 -0
- css/dist/{yst_seo_score-791-rtl.min.css → yst_seo_score-800-rtl.min.css} +0 -0
- css/dist/{yst_seo_score-791.min.css → yst_seo_score-800.min.css} +0 -0
- inc/class-wpseo-admin-bar-menu.php +626 -0
- inc/class-wpseo-meta.php +32 -47
- inc/class-wpseo-utils.php +17 -0
- inc/interface-wpseo-wordpress-ajax-integration.php +19 -0
- inc/options/class-wpseo-option.php +12 -2
- inc/options/class-wpseo-options.php +1 -1
- inc/sitemaps/class-sitemaps-cache-validator.php +2 -0
- inc/sitemaps/class-sitemaps-router.php +6 -1
- inc/wpseo-non-ajax-functions.php +85 -303
- js/dist/analysis-791.min.js +0 -13
admin/ajax.php
CHANGED
@@ -332,6 +332,21 @@ function ajax_get_term_keyword_usage() {
|
|
332 |
|
333 |
add_action( 'wp_ajax_get_term_keyword_usage', 'ajax_get_term_keyword_usage' );
|
334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
// Crawl Issue Manager AJAX hooks.
|
336 |
new WPSEO_GSC_Ajax();
|
337 |
|
332 |
|
333 |
add_action( 'wp_ajax_get_term_keyword_usage', 'ajax_get_term_keyword_usage' );
|
334 |
|
335 |
+
/**
|
336 |
+
* Registers hooks for all AJAX integrations.
|
337 |
+
*
|
338 |
+
* @return void
|
339 |
+
*/
|
340 |
+
function wpseo_register_ajax_integrations() {
|
341 |
+
$integrations = array( new Yoast_Network_Admin() );
|
342 |
+
|
343 |
+
foreach ( $integrations as $integration ) {
|
344 |
+
$integration->register_ajax_hooks();
|
345 |
+
}
|
346 |
+
}
|
347 |
+
|
348 |
+
wpseo_register_ajax_integrations();
|
349 |
+
|
350 |
// Crawl Issue Manager AJAX hooks.
|
351 |
new WPSEO_GSC_Ajax();
|
352 |
|
admin/class-admin-asset-dev-server-location.php
CHANGED
@@ -11,25 +11,6 @@
|
|
11 |
final class WPSEO_Admin_Asset_Dev_Server_Location implements WPSEO_Admin_Asset_Location {
|
12 |
const DEFAULT_URL = 'http://localhost:8080';
|
13 |
|
14 |
-
/**
|
15 |
-
* @var array
|
16 |
-
*/
|
17 |
-
private static $dev_server_script = array(
|
18 |
-
'analysis',
|
19 |
-
'commons',
|
20 |
-
'configuration-wizard',
|
21 |
-
'search-appearance',
|
22 |
-
'wp-seo-dashboard-widget',
|
23 |
-
'wp-seo-help-center',
|
24 |
-
'wp-seo-metabox',
|
25 |
-
'wp-seo-modal',
|
26 |
-
'wp-seo-post-scraper',
|
27 |
-
'wp-seo-replacevar-plugin',
|
28 |
-
'wp-seo-term-scraper',
|
29 |
-
'wp-seo-modal',
|
30 |
-
'wp-seo-wp-globals-backport',
|
31 |
-
);
|
32 |
-
|
33 |
/**
|
34 |
* @var string
|
35 |
*/
|
@@ -63,7 +44,7 @@ final class WPSEO_Admin_Asset_Dev_Server_Location implements WPSEO_Admin_Asset_L
|
|
63 |
$flat_version = $asset_manager->flatten_version( WPSEO_VERSION );
|
64 |
$version_less_source = str_replace( '-' . $flat_version, '', $asset->get_src() );
|
65 |
|
66 |
-
if (
|
67 |
return $this->get_default_url( $asset, $type );
|
68 |
}
|
69 |
|
11 |
final class WPSEO_Admin_Asset_Dev_Server_Location implements WPSEO_Admin_Asset_Location {
|
12 |
const DEFAULT_URL = 'http://localhost:8080';
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
/**
|
15 |
* @var string
|
16 |
*/
|
44 |
$flat_version = $asset_manager->flatten_version( WPSEO_VERSION );
|
45 |
$version_less_source = str_replace( '-' . $flat_version, '', $asset->get_src() );
|
46 |
|
47 |
+
if ( false !== strpos( $version_less_source, 'select2' ) ) {
|
48 |
return $this->get_default_url( $asset, $type );
|
49 |
}
|
50 |
|
admin/class-admin-asset-manager.php
CHANGED
@@ -193,9 +193,10 @@ class WPSEO_Admin_Asset_Manager {
|
|
193 |
$backport_wp_dependencies = array( self::PREFIX . 'react-dependencies' );
|
194 |
|
195 |
// If Gutenberg is present we can borrow their globals for our own.
|
196 |
-
if (
|
197 |
$backport_wp_dependencies[] = 'wp-element';
|
198 |
$backport_wp_dependencies[] = 'wp-data';
|
|
|
199 |
|
200 |
/*
|
201 |
* The version of TinyMCE that Gutenberg uses is incompatible with
|
@@ -210,15 +211,24 @@ class WPSEO_Admin_Asset_Manager {
|
|
210 |
wp_register_script( 'tinymce-latest', includes_url( 'js/tinymce/' ) . 'wp-tinymce.php', array( 'jquery' ), false, true );
|
211 |
}
|
212 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
|
214 |
return array(
|
215 |
array(
|
216 |
'name' => 'react-dependencies',
|
217 |
// Load webpack-commons for bundle support.
|
218 |
'src' => 'commons-' . $flat_version,
|
219 |
-
'deps' => array(
|
220 |
-
self::PREFIX . 'babel-polyfill',
|
221 |
-
),
|
222 |
),
|
223 |
array(
|
224 |
'name' => 'search-appearance',
|
@@ -255,7 +265,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
255 |
'jquery-ui-progressbar',
|
256 |
self::PREFIX . 'select2',
|
257 |
self::PREFIX . 'select2-translations',
|
258 |
-
self::PREFIX . '
|
259 |
),
|
260 |
),
|
261 |
array(
|
@@ -264,23 +274,29 @@ class WPSEO_Admin_Asset_Manager {
|
|
264 |
'deps' => array(
|
265 |
'jquery',
|
266 |
'jquery-ui-core',
|
267 |
-
self::PREFIX . '
|
268 |
),
|
269 |
),
|
270 |
array(
|
271 |
-
'name' => '
|
272 |
-
'src' => 'wp-seo-
|
273 |
-
'deps' => array( 'jquery'
|
274 |
),
|
275 |
array(
|
276 |
-
'name' => '
|
277 |
-
'src' => 'wp-seo-
|
278 |
-
'deps' => array(
|
|
|
|
|
|
|
279 |
),
|
280 |
array(
|
281 |
'name' => 'admin-global-script',
|
282 |
'src' => 'wp-seo-admin-global-' . $flat_version,
|
283 |
-
'deps' => array(
|
|
|
|
|
|
|
284 |
),
|
285 |
array(
|
286 |
'name' => 'metabox',
|
@@ -298,13 +314,15 @@ class WPSEO_Admin_Asset_Manager {
|
|
298 |
'src' => 'wp-seo-featured-image-' . $flat_version,
|
299 |
'deps' => array(
|
300 |
'jquery',
|
301 |
-
self::PREFIX . '
|
302 |
),
|
303 |
),
|
304 |
array(
|
305 |
'name' => 'admin-gsc',
|
306 |
'src' => 'wp-seo-admin-gsc-' . $flat_version,
|
307 |
-
'deps' => array(
|
|
|
|
|
308 |
'in_footer' => false,
|
309 |
),
|
310 |
array(
|
@@ -316,6 +334,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
316 |
'wp-util',
|
317 |
self::PREFIX . 'wp-globals-backport',
|
318 |
self::PREFIX . 'analysis',
|
|
|
319 |
),
|
320 |
),
|
321 |
array(
|
@@ -331,7 +350,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
331 |
'name' => 'replacevar-plugin',
|
332 |
'src' => 'wp-seo-replacevar-plugin-' . $flat_version,
|
333 |
'deps' => array(
|
334 |
-
self::PREFIX . '
|
335 |
self::PREFIX . 'analysis',
|
336 |
),
|
337 |
),
|
@@ -339,7 +358,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
339 |
'name' => 'shortcode-plugin',
|
340 |
'src' => 'wp-seo-shortcode-plugin-' . $flat_version,
|
341 |
'deps' => array(
|
342 |
-
self::PREFIX . '
|
343 |
self::PREFIX . 'analysis',
|
344 |
),
|
345 |
),
|
@@ -350,8 +369,8 @@ class WPSEO_Admin_Asset_Manager {
|
|
350 |
'jquery',
|
351 |
'jquery-ui-core',
|
352 |
'jquery-ui-progressbar',
|
353 |
-
self::PREFIX . 'babel-polyfill',
|
354 |
self::PREFIX . 'analysis',
|
|
|
355 |
),
|
356 |
),
|
357 |
array(
|
@@ -360,7 +379,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
360 |
'deps' => array(
|
361 |
'jquery',
|
362 |
'wp-util',
|
363 |
-
self::PREFIX . '
|
364 |
),
|
365 |
),
|
366 |
array(
|
@@ -390,15 +409,6 @@ class WPSEO_Admin_Asset_Manager {
|
|
390 |
self::PREFIX . 'wp-globals-backport',
|
391 |
),
|
392 |
),
|
393 |
-
// Register for backwards-compatiblity.
|
394 |
-
array(
|
395 |
-
'name' => 'polyfill',
|
396 |
-
'src' => 'wp-seo-babel-polyfill-' . $flat_version,
|
397 |
-
),
|
398 |
-
array(
|
399 |
-
'name' => 'babel-polyfill',
|
400 |
-
'src' => 'wp-seo-babel-polyfill-' . $flat_version,
|
401 |
-
),
|
402 |
array(
|
403 |
'name' => 'reindex-links',
|
404 |
'src' => 'wp-seo-reindex-links-' . $flat_version,
|
@@ -406,17 +416,24 @@ class WPSEO_Admin_Asset_Manager {
|
|
406 |
'jquery',
|
407 |
'jquery-ui-core',
|
408 |
'jquery-ui-progressbar',
|
|
|
409 |
),
|
410 |
),
|
411 |
array(
|
412 |
'name' => 'edit-page-script',
|
413 |
'src' => 'wp-seo-edit-page-' . $flat_version,
|
414 |
-
'deps' => array(
|
|
|
|
|
|
|
415 |
),
|
416 |
array(
|
417 |
'name' => 'quick-edit-handler',
|
418 |
'src' => 'wp-seo-quick-edit-handler-' . $flat_version,
|
419 |
-
'deps' => array(
|
|
|
|
|
|
|
420 |
'in_footer' => true,
|
421 |
),
|
422 |
array(
|
@@ -425,6 +442,7 @@ class WPSEO_Admin_Asset_Manager {
|
|
425 |
'deps' => array(
|
426 |
'wp-api',
|
427 |
'jquery',
|
|
|
428 |
),
|
429 |
),
|
430 |
array(
|
@@ -439,12 +457,20 @@ class WPSEO_Admin_Asset_Manager {
|
|
439 |
array(
|
440 |
'name' => 'filter-explanation',
|
441 |
'src' => 'wp-seo-filter-explanation-' . $flat_version,
|
442 |
-
'deps' => array(
|
|
|
|
|
|
|
443 |
),
|
444 |
array(
|
445 |
'name' => 'analysis',
|
446 |
'src' => 'analysis-' . $flat_version,
|
447 |
),
|
|
|
|
|
|
|
|
|
|
|
448 |
);
|
449 |
}
|
450 |
|
@@ -499,10 +525,6 @@ class WPSEO_Admin_Asset_Manager {
|
|
499 |
'name' => 'scoring',
|
500 |
'src' => 'yst_seo_score-' . $flat_version,
|
501 |
),
|
502 |
-
array(
|
503 |
-
'name' => 'snippet',
|
504 |
-
'src' => 'snippet-' . $flat_version,
|
505 |
-
),
|
506 |
array(
|
507 |
'name' => 'adminbar',
|
508 |
'src' => 'adminbar-' . $flat_version,
|
@@ -538,6 +560,35 @@ class WPSEO_Admin_Asset_Manager {
|
|
538 |
'name' => 'search-appearance',
|
539 |
'src' => 'search-appearance-' . $flat_version,
|
540 |
),
|
|
|
|
|
|
|
|
|
|
|
541 |
);
|
542 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
543 |
}
|
193 |
$backport_wp_dependencies = array( self::PREFIX . 'react-dependencies' );
|
194 |
|
195 |
// If Gutenberg is present we can borrow their globals for our own.
|
196 |
+
if ( $this->should_load_gutenberg_assets() ) {
|
197 |
$backport_wp_dependencies[] = 'wp-element';
|
198 |
$backport_wp_dependencies[] = 'wp-data';
|
199 |
+
$backport_wp_dependencies[] = 'wp-components';
|
200 |
|
201 |
/*
|
202 |
* The version of TinyMCE that Gutenberg uses is incompatible with
|
211 |
wp_register_script( 'tinymce-latest', includes_url( 'js/tinymce/' ) . 'wp-tinymce.php', array( 'jquery' ), false, true );
|
212 |
}
|
213 |
}
|
214 |
+
else {
|
215 |
+
if ( wp_script_is( 'lodash', 'registered' ) ) {
|
216 |
+
$backport_wp_dependencies[] = 'lodash';
|
217 |
+
}
|
218 |
+
else {
|
219 |
+
if ( ! wp_script_is( self::PREFIX . 'lodash', 'registered' ) ) {
|
220 |
+
wp_register_script( self::PREFIX . 'lodash', plugins_url( 'js/vendor/lodash.min.js', WPSEO_FILE ) );
|
221 |
+
wp_add_inline_script( self::PREFIX . 'lodash', 'window.lodash = _.noConflict();', 'after' );
|
222 |
+
}
|
223 |
+
$backport_wp_dependencies[] = self::PREFIX . 'lodash';
|
224 |
+
}
|
225 |
+
}
|
226 |
|
227 |
return array(
|
228 |
array(
|
229 |
'name' => 'react-dependencies',
|
230 |
// Load webpack-commons for bundle support.
|
231 |
'src' => 'commons-' . $flat_version,
|
|
|
|
|
|
|
232 |
),
|
233 |
array(
|
234 |
'name' => 'search-appearance',
|
265 |
'jquery-ui-progressbar',
|
266 |
self::PREFIX . 'select2',
|
267 |
self::PREFIX . 'select2-translations',
|
268 |
+
self::PREFIX . 'react-dependencies',
|
269 |
),
|
270 |
),
|
271 |
array(
|
274 |
'deps' => array(
|
275 |
'jquery',
|
276 |
'jquery-ui-core',
|
277 |
+
self::PREFIX . 'react-dependencies',
|
278 |
),
|
279 |
),
|
280 |
array(
|
281 |
+
'name' => 'network-admin-script',
|
282 |
+
'src' => 'wp-seo-network-admin-' . $flat_version,
|
283 |
+
'deps' => array( 'jquery' ),
|
284 |
),
|
285 |
array(
|
286 |
+
'name' => 'bulk-editor',
|
287 |
+
'src' => 'wp-seo-bulk-editor-' . $flat_version,
|
288 |
+
'deps' => array(
|
289 |
+
'jquery',
|
290 |
+
self::PREFIX . 'react-dependencies',
|
291 |
+
),
|
292 |
),
|
293 |
array(
|
294 |
'name' => 'admin-global-script',
|
295 |
'src' => 'wp-seo-admin-global-' . $flat_version,
|
296 |
+
'deps' => array(
|
297 |
+
'jquery',
|
298 |
+
self::PREFIX . 'react-dependencies',
|
299 |
+
),
|
300 |
),
|
301 |
array(
|
302 |
'name' => 'metabox',
|
314 |
'src' => 'wp-seo-featured-image-' . $flat_version,
|
315 |
'deps' => array(
|
316 |
'jquery',
|
317 |
+
self::PREFIX . 'react-dependencies',
|
318 |
),
|
319 |
),
|
320 |
array(
|
321 |
'name' => 'admin-gsc',
|
322 |
'src' => 'wp-seo-admin-gsc-' . $flat_version,
|
323 |
+
'deps' => array(
|
324 |
+
self::PREFIX . 'react-dependencies',
|
325 |
+
),
|
326 |
'in_footer' => false,
|
327 |
),
|
328 |
array(
|
334 |
'wp-util',
|
335 |
self::PREFIX . 'wp-globals-backport',
|
336 |
self::PREFIX . 'analysis',
|
337 |
+
self::PREFIX . 'react-dependencies',
|
338 |
),
|
339 |
),
|
340 |
array(
|
350 |
'name' => 'replacevar-plugin',
|
351 |
'src' => 'wp-seo-replacevar-plugin-' . $flat_version,
|
352 |
'deps' => array(
|
353 |
+
self::PREFIX . 'react-dependencies',
|
354 |
self::PREFIX . 'analysis',
|
355 |
),
|
356 |
),
|
358 |
'name' => 'shortcode-plugin',
|
359 |
'src' => 'wp-seo-shortcode-plugin-' . $flat_version,
|
360 |
'deps' => array(
|
361 |
+
self::PREFIX . 'react-dependencies',
|
362 |
self::PREFIX . 'analysis',
|
363 |
),
|
364 |
),
|
369 |
'jquery',
|
370 |
'jquery-ui-core',
|
371 |
'jquery-ui-progressbar',
|
|
|
372 |
self::PREFIX . 'analysis',
|
373 |
+
self::PREFIX . 'react-dependencies',
|
374 |
),
|
375 |
),
|
376 |
array(
|
379 |
'deps' => array(
|
380 |
'jquery',
|
381 |
'wp-util',
|
382 |
+
self::PREFIX . 'react-dependencies',
|
383 |
),
|
384 |
),
|
385 |
array(
|
409 |
self::PREFIX . 'wp-globals-backport',
|
410 |
),
|
411 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
array(
|
413 |
'name' => 'reindex-links',
|
414 |
'src' => 'wp-seo-reindex-links-' . $flat_version,
|
416 |
'jquery',
|
417 |
'jquery-ui-core',
|
418 |
'jquery-ui-progressbar',
|
419 |
+
self::PREFIX . 'react-dependencies',
|
420 |
),
|
421 |
),
|
422 |
array(
|
423 |
'name' => 'edit-page-script',
|
424 |
'src' => 'wp-seo-edit-page-' . $flat_version,
|
425 |
+
'deps' => array(
|
426 |
+
'jquery',
|
427 |
+
self::PREFIX . 'react-dependencies',
|
428 |
+
),
|
429 |
),
|
430 |
array(
|
431 |
'name' => 'quick-edit-handler',
|
432 |
'src' => 'wp-seo-quick-edit-handler-' . $flat_version,
|
433 |
+
'deps' => array(
|
434 |
+
'jquery',
|
435 |
+
self::PREFIX . 'react-dependencies',
|
436 |
+
),
|
437 |
'in_footer' => true,
|
438 |
),
|
439 |
array(
|
442 |
'deps' => array(
|
443 |
'wp-api',
|
444 |
'jquery',
|
445 |
+
self::PREFIX . 'react-dependencies',
|
446 |
),
|
447 |
),
|
448 |
array(
|
457 |
array(
|
458 |
'name' => 'filter-explanation',
|
459 |
'src' => 'wp-seo-filter-explanation-' . $flat_version,
|
460 |
+
'deps' => array(
|
461 |
+
'jquery',
|
462 |
+
self::PREFIX . 'react-dependencies',
|
463 |
+
),
|
464 |
),
|
465 |
array(
|
466 |
'name' => 'analysis',
|
467 |
'src' => 'analysis-' . $flat_version,
|
468 |
),
|
469 |
+
array(
|
470 |
+
'name' => 'structured-data-blocks',
|
471 |
+
'src' => 'wp-seo-structured-data-blocks-' . $flat_version,
|
472 |
+
'deps' => array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
|
473 |
+
),
|
474 |
);
|
475 |
}
|
476 |
|
525 |
'name' => 'scoring',
|
526 |
'src' => 'yst_seo_score-' . $flat_version,
|
527 |
),
|
|
|
|
|
|
|
|
|
528 |
array(
|
529 |
'name' => 'adminbar',
|
530 |
'src' => 'adminbar-' . $flat_version,
|
560 |
'name' => 'search-appearance',
|
561 |
'src' => 'search-appearance-' . $flat_version,
|
562 |
),
|
563 |
+
array(
|
564 |
+
'name' => 'structured-data-blocks',
|
565 |
+
'src' => 'structured-data-blocks-' . $flat_version,
|
566 |
+
'deps' => array( 'wp-edit-blocks' ),
|
567 |
+
),
|
568 |
);
|
569 |
}
|
570 |
+
|
571 |
+
/**
|
572 |
+
* Checks if the Gutenberg assets must be loaded.
|
573 |
+
*
|
574 |
+
* @return bool True wheter Gutenberg assets must be loaded.
|
575 |
+
*/
|
576 |
+
protected function should_load_gutenberg_assets() {
|
577 |
+
// When Gutenberg is not active, just return false.
|
578 |
+
if ( ! function_exists( 'gutenberg_register_scripts_and_styles' ) ) {
|
579 |
+
return false;
|
580 |
+
}
|
581 |
+
|
582 |
+
// When working in the classic editor shipped with Gutenberg, the assets shouldn't be loaded. Fixes IE11 bug.
|
583 |
+
if ( isset( $_GET['classic-editor'] ) ) {
|
584 |
+
return false;
|
585 |
+
}
|
586 |
+
|
587 |
+
// When classic editor plugin and Gutenberg are active, the Gutenberg assets shouldn't be loaded.
|
588 |
+
if ( function_exists( 'classic_editor_is_gutenberg_active' ) && classic_editor_is_gutenberg_active() ) {
|
589 |
+
return false;
|
590 |
+
}
|
591 |
+
|
592 |
+
return true;
|
593 |
+
}
|
594 |
}
|
admin/class-admin-gutenberg-compatibility-notification.php
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Admin
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Handles the Gutenberg Compatibility notification showing and hiding.
|
10 |
+
*/
|
11 |
+
class WPSEO_Admin_Gutenberg_Compatibility_Notification implements WPSEO_WordPress_Integration {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Notification ID to use.
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
+
private $notification_id = 'wpseo-outdated-gutenberg-plugin';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var WPSEO_Gutenberg_Compatibility
|
22 |
+
*/
|
23 |
+
private $compatibility_checker;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var Yoast_Notification_Center
|
27 |
+
*/
|
28 |
+
private $notification_center;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* WPSEO_Admin_Gutenberg_Compatibility_Notification constructor.
|
32 |
+
*/
|
33 |
+
public function __construct() {
|
34 |
+
$this->compatibility_checker = new WPSEO_Gutenberg_Compatibility();
|
35 |
+
$this->notification_center = Yoast_Notification_Center::get();
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Registers all hooks to WordPress.
|
40 |
+
*
|
41 |
+
* @return void
|
42 |
+
*/
|
43 |
+
public function register_hooks() {
|
44 |
+
add_action( 'admin_init', array( $this, 'manage_notification' ) );
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Manages if the notification should be shown or removed.
|
49 |
+
*
|
50 |
+
* @return void
|
51 |
+
*/
|
52 |
+
public function manage_notification() {
|
53 |
+
if ( ! $this->compatibility_checker->is_installed() || $this->compatibility_checker->is_fully_compatible() ) {
|
54 |
+
$this->notification_center->remove_notification_by_id( $this->notification_id );
|
55 |
+
|
56 |
+
return;
|
57 |
+
}
|
58 |
+
|
59 |
+
$this->add_notification();
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Adds the notification to the notificaton center.
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*/
|
67 |
+
private function add_notification() {
|
68 |
+
$level = $this->compatibility_checker->is_below_minimum() ? Yoast_Notification::ERROR : Yoast_Notification::WARNING;
|
69 |
+
|
70 |
+
$message = sprintf(
|
71 |
+
/* translators: %1$s expands to Yoast SEO, %2$s expands to the installed version, %3$s expands to Gutenberg */
|
72 |
+
__( '%1$s detected you are using version %2$s of %3$s, please update to the latest version to prevent compatibility issues.', 'wordpress-seo' ),
|
73 |
+
'Yoast SEO',
|
74 |
+
$this->compatibility_checker->get_installed_version(),
|
75 |
+
'Gutenberg'
|
76 |
+
);
|
77 |
+
|
78 |
+
$notification = new Yoast_Notification(
|
79 |
+
$message,
|
80 |
+
array(
|
81 |
+
'id' => $this->notification_id,
|
82 |
+
'type' => $level,
|
83 |
+
'priority' => 1,
|
84 |
+
)
|
85 |
+
);
|
86 |
+
|
87 |
+
$this->notification_center->add_notification( $notification );
|
88 |
+
}
|
89 |
+
}
|
admin/class-admin.php
CHANGED
@@ -48,7 +48,10 @@ class WPSEO_Admin {
|
|
48 |
);
|
49 |
|
50 |
if ( WPSEO_Metabox::is_post_overview( $pagenow ) || WPSEO_Metabox::is_post_edit( $pagenow ) ) {
|
51 |
-
$this->admin_features['primary_category']
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
if ( filter_input( INPUT_GET, 'page' ) === 'wpseo_tools' && filter_input( INPUT_GET, 'tool' ) === null ) {
|
@@ -92,11 +95,14 @@ class WPSEO_Admin {
|
|
92 |
|
93 |
new Yoast_Modal();
|
94 |
|
|
|
95 |
$integrations[] = new WPSEO_Yoast_Columns();
|
96 |
$integrations[] = new WPSEO_License_Page_Manager();
|
97 |
$integrations[] = new WPSEO_Statistic_Integration();
|
98 |
$integrations[] = new WPSEO_Capability_Manager_Integration( WPSEO_Capability_Manager_Factory::get() );
|
99 |
$integrations[] = new WPSEO_Admin_Media_Purge_Notification();
|
|
|
|
|
100 |
$integrations = array_merge( $integrations, $this->initialize_seo_links() );
|
101 |
|
102 |
/** @var WPSEO_WordPress_Integration $integration */
|
48 |
);
|
49 |
|
50 |
if ( WPSEO_Metabox::is_post_overview( $pagenow ) || WPSEO_Metabox::is_post_edit( $pagenow ) ) {
|
51 |
+
$this->admin_features['primary_category'] = new WPSEO_Primary_Term_Admin();
|
52 |
+
if ( defined( 'YOAST_FEATURE_GUTENBERG_STRUCTURED_DATA_BLOCKS' ) ) {
|
53 |
+
$this->admin_features['structured_data_blocks'] = new WPSEO_Structured_Data_Blocks();
|
54 |
+
}
|
55 |
}
|
56 |
|
57 |
if ( filter_input( INPUT_GET, 'page' ) === 'wpseo_tools' && filter_input( INPUT_GET, 'tool' ) === null ) {
|
95 |
|
96 |
new Yoast_Modal();
|
97 |
|
98 |
+
$integrations[] = new Yoast_Network_Admin();
|
99 |
$integrations[] = new WPSEO_Yoast_Columns();
|
100 |
$integrations[] = new WPSEO_License_Page_Manager();
|
101 |
$integrations[] = new WPSEO_Statistic_Integration();
|
102 |
$integrations[] = new WPSEO_Capability_Manager_Integration( WPSEO_Capability_Manager_Factory::get() );
|
103 |
$integrations[] = new WPSEO_Admin_Media_Purge_Notification();
|
104 |
+
$integrations[] = new WPSEO_Admin_Gutenberg_Compatibility_Notification();
|
105 |
+
$integrations[] = new WPSEO_Expose_Shortlinks();
|
106 |
$integrations = array_merge( $integrations, $this->initialize_seo_links() );
|
107 |
|
108 |
/** @var WPSEO_WordPress_Integration $integration */
|
admin/class-cornerstone-field.php
DELETED
@@ -1,57 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WPSEO plugin file.
|
4 |
-
*
|
5 |
-
* @package WPSEO\Admin
|
6 |
-
*/
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Adds a checkbox to the focus keyword section.
|
10 |
-
*/
|
11 |
-
class WPSEO_Cornerstone_Field {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Returns a label with a checkbox in it. Make it possible to mark the page as cornerstone content.
|
15 |
-
*
|
16 |
-
* @param WP_POST $post The post object.
|
17 |
-
*
|
18 |
-
* @return string The HTML to show.
|
19 |
-
*/
|
20 |
-
public function get_html( $post ) {
|
21 |
-
|
22 |
-
$post_types = apply_filters( 'wpseo_cornerstone_post_types', WPSEO_Post_Type::get_accessible_post_types() );
|
23 |
-
if ( ! is_array( $post_types ) || ! isset( $post_types[ get_post_type( $post ) ] ) ) {
|
24 |
-
return '';
|
25 |
-
}
|
26 |
-
|
27 |
-
$return = '';
|
28 |
-
$return .= sprintf(
|
29 |
-
'<input id="%1$s" class="wpseo-cornerstone-checkbox" type="checkbox" value="1" name="%1$s" %2$s/>',
|
30 |
-
WPSEO_Cornerstone::FIELD_NAME,
|
31 |
-
checked( $this->get_meta_value( $post->ID ), '1', false )
|
32 |
-
);
|
33 |
-
|
34 |
-
$return .= sprintf( '<label for="%1$s">', WPSEO_Cornerstone::FIELD_NAME );
|
35 |
-
|
36 |
-
$return .= sprintf(
|
37 |
-
/* translators: 1: link open tag; 2: link close tag. */
|
38 |
-
__( 'This article is %1$scornerstone content%2$s', 'wordpress-seo' ),
|
39 |
-
'<a href="' . WPSEO_Shortlinker::get( 'https://yoa.st/metabox-help-cornerstone' ) . '" target="_blank">',
|
40 |
-
'</a>'
|
41 |
-
);
|
42 |
-
$return .= '</label>';
|
43 |
-
|
44 |
-
return $return;
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Gets the meta value from the database.
|
49 |
-
*
|
50 |
-
* @param int $post_id The post id to get the meta value for.
|
51 |
-
*
|
52 |
-
* @return null|string The meta value from the database.
|
53 |
-
*/
|
54 |
-
protected function get_meta_value( $post_id ) {
|
55 |
-
return WPSEO_Meta::get_value( WPSEO_Cornerstone::META_NAME, $post_id );
|
56 |
-
}
|
57 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin/class-cornerstone.php
CHANGED
@@ -55,7 +55,7 @@ class WPSEO_Cornerstone {
|
|
55 |
* @return bool True when checkbox is checked.
|
56 |
*/
|
57 |
protected function is_cornerstone_content() {
|
58 |
-
return filter_input( INPUT_POST, self::FIELD_NAME ) === '
|
59 |
}
|
60 |
|
61 |
/**
|
55 |
* @return bool True when checkbox is checked.
|
56 |
*/
|
57 |
protected function is_cornerstone_content() {
|
58 |
+
return filter_input( INPUT_POST, self::FIELD_NAME ) === 'true';
|
59 |
}
|
60 |
|
61 |
/**
|
admin/class-expose-shortlinks.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Admin
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Exposes shortlinks in a global, so that we can pass them to our Javascript components.
|
10 |
+
*/
|
11 |
+
class WPSEO_Expose_Shortlinks implements WPSEO_WordPress_Integration {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Registers all hooks to WordPress
|
15 |
+
*/
|
16 |
+
public function register_hooks() {
|
17 |
+
add_filter( 'wpseo_admin_l10n', array( $this, 'expose_shortlinks' ) );
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param array $input The array to add shortlinks to.
|
22 |
+
*
|
23 |
+
* @return array
|
24 |
+
*/
|
25 |
+
public function expose_shortlinks( $input ) {
|
26 |
+
$input['shortlinks.focus_keyword_info'] = WPSEO_Shortlinker::get( 'https://yoa.st/focus-keyword' );
|
27 |
+
$input['shortlinks.snippet_preview_info'] = WPSEO_Shortlinker::get( 'https://yoa.st/snippet-preview' );
|
28 |
+
$input['shortlinks.cornerstone_content_info'] = WPSEO_Shortlinker::get( 'https://yoa.st/1i9' );
|
29 |
+
|
30 |
+
return $input;
|
31 |
+
}
|
32 |
+
}
|
admin/class-gutenberg-compatibility.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Gutenberg_Compatibility
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class WPSEO_Gutenberg_Compatibility
|
10 |
+
*/
|
11 |
+
class WPSEO_Gutenberg_Compatibility {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* The currently released version of Gutenberg.
|
15 |
+
*/
|
16 |
+
const CURRENT_RELEASE = '3.5.0';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* The minimally supported version of Gutenberg by the plugin.
|
20 |
+
*/
|
21 |
+
const MINIMUM_SUPPORTED = '2.8.0';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
protected $current_version;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* WPSEO_Gutenberg_Compatibility constructor.
|
30 |
+
*/
|
31 |
+
public function __construct() {
|
32 |
+
$this->current_version = $this->detect_installed_gutenberg_version();
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Determines whether or not Gutenberg is installed.
|
37 |
+
*
|
38 |
+
* @return bool Whether or not Gutenberg is installed.
|
39 |
+
*/
|
40 |
+
public function is_installed() {
|
41 |
+
return $this->current_version !== '';
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Determines whether or not the currently installed version of Gutenberg is below the minimum supported version.
|
46 |
+
*
|
47 |
+
* @return bool True if the currently installed version is below the minimum supported version. False otherwise.
|
48 |
+
*/
|
49 |
+
public function is_below_minimum() {
|
50 |
+
return version_compare( $this->current_version, $this->get_minimum_supported_version(), '<' );
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Gets the currently installed version.
|
55 |
+
*
|
56 |
+
* @return string The currently installed version.
|
57 |
+
*/
|
58 |
+
public function get_installed_version() {
|
59 |
+
return $this->current_version;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Determines whether or not the currently installed version of Gutenberg is the latest, fully compatible version.
|
64 |
+
*
|
65 |
+
* @return bool Whether or not the currently installed version is fully compatible.
|
66 |
+
*/
|
67 |
+
public function is_fully_compatible() {
|
68 |
+
return version_compare( $this->current_version, $this->get_latest_release(), '>=' );
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Gets the latest released version of Gutenberg.
|
73 |
+
*
|
74 |
+
* @return string The latest release.
|
75 |
+
*/
|
76 |
+
protected function get_latest_release() {
|
77 |
+
return self::CURRENT_RELEASE;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Gets the minimum supported version of Gutenberg.
|
82 |
+
*
|
83 |
+
* @return string The minumum supported release.
|
84 |
+
*/
|
85 |
+
protected function get_minimum_supported_version() {
|
86 |
+
return self::MINIMUM_SUPPORTED;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Detects the currently installed Gutenberg version.
|
91 |
+
*
|
92 |
+
* @return string The currently installed Gutenberg version. Empty if the version couldn't be detected.
|
93 |
+
*/
|
94 |
+
protected function detect_installed_gutenberg_version() {
|
95 |
+
if ( defined( 'GUTENBERG_VERSION' ) ) {
|
96 |
+
return GUTENBERG_VERSION;
|
97 |
+
}
|
98 |
+
|
99 |
+
return '';
|
100 |
+
}
|
101 |
+
}
|
admin/class-keyword-synonyms-modal.php
CHANGED
@@ -27,12 +27,14 @@ class WPSEO_Keyword_Synonyms_Modal {
|
|
27 |
'link' => WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ),
|
28 |
'other' => sprintf(
|
29 |
/* translators: %s expands to 'Yoast SEO Premium'. */
|
30 |
-
__( 'Other benefits of %s for you:', 'wordpress-seo' ),
|
|
|
31 |
),
|
32 |
'buylink' => WPSEO_Shortlinker::get( 'https://yoa.st/keyword-synonyms-popup' ),
|
33 |
'buy' => sprintf(
|
34 |
/* translators: %s expands to 'Yoast SEO Premium'. */
|
35 |
-
__( 'Get %s now!', 'wordpress-seo' ),
|
|
|
36 |
),
|
37 |
'small' => __( '1 year free updates and upgrades included!', 'wordpress-seo' ),
|
38 |
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ),
|
@@ -46,6 +48,7 @@ class WPSEO_Keyword_Synonyms_Modal {
|
|
46 |
*/
|
47 |
public function get_translations_for_js() {
|
48 |
$translations = $this->get_translations();
|
|
|
49 |
return array(
|
50 |
'locale' => WPSEO_Utils::get_user_locale(),
|
51 |
'intl' => $translations,
|
@@ -54,6 +57,8 @@ class WPSEO_Keyword_Synonyms_Modal {
|
|
54 |
|
55 |
/**
|
56 |
* Prints the localized Keyword Synonyms modal translations for JS.
|
|
|
|
|
57 |
*/
|
58 |
public function enqueue_translations() {
|
59 |
wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'admin-global-script', 'yoastKeywordSynonymsModalL10n', $this->get_translations_for_js() );
|
27 |
'link' => WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ),
|
28 |
'other' => sprintf(
|
29 |
/* translators: %s expands to 'Yoast SEO Premium'. */
|
30 |
+
__( 'Other benefits of %s for you:', 'wordpress-seo' ),
|
31 |
+
'Yoast SEO Premium'
|
32 |
),
|
33 |
'buylink' => WPSEO_Shortlinker::get( 'https://yoa.st/keyword-synonyms-popup' ),
|
34 |
'buy' => sprintf(
|
35 |
/* translators: %s expands to 'Yoast SEO Premium'. */
|
36 |
+
__( 'Get %s now!', 'wordpress-seo' ),
|
37 |
+
'Yoast SEO Premium'
|
38 |
),
|
39 |
'small' => __( '1 year free updates and upgrades included!', 'wordpress-seo' ),
|
40 |
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ),
|
48 |
*/
|
49 |
public function get_translations_for_js() {
|
50 |
$translations = $this->get_translations();
|
51 |
+
|
52 |
return array(
|
53 |
'locale' => WPSEO_Utils::get_user_locale(),
|
54 |
'intl' => $translations,
|
57 |
|
58 |
/**
|
59 |
* Prints the localized Keyword Synonyms modal translations for JS.
|
60 |
+
*
|
61 |
+
* @return void
|
62 |
*/
|
63 |
public function enqueue_translations() {
|
64 |
wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'admin-global-script', 'yoastKeywordSynonymsModalL10n', $this->get_translations_for_js() );
|
admin/class-multiple-keywords-modal.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @package WPSEO\Admin
|
4 |
+
*/
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class to print out the translatable strings for the Multiple Keywords modal.
|
8 |
+
*/
|
9 |
+
class WPSEO_Multiple_Keywords_Modal {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Returns the translations for the Multiple Keywords modal.
|
13 |
+
*
|
14 |
+
* These strings are not escaped because they're meant to be used with React
|
15 |
+
* which already takes care of that. If used in PHP, they should be escaped.
|
16 |
+
*
|
17 |
+
* @return array Translated text strings for the Multiple Keywords modal.
|
18 |
+
*/
|
19 |
+
public function get_translations() {
|
20 |
+
return array(
|
21 |
+
'title' => __( 'Would you like to add another keyword?', 'wordpress-seo' ),
|
22 |
+
'intro' => sprintf(
|
23 |
+
/* translators: %1$s expands to a 'Yoast SEO Premium' text linked to the yoast.com website. */
|
24 |
+
__( 'Great news: you can, with %1$s!', 'wordpress-seo' ),
|
25 |
+
'{{link}}Yoast SEO Premium{{/link}}'
|
26 |
+
),
|
27 |
+
'link' => WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ),
|
28 |
+
'other' => sprintf(
|
29 |
+
/* translators: %s expands to 'Yoast SEO Premium'. */
|
30 |
+
__( 'Other benefits of %s for you:', 'wordpress-seo' ),
|
31 |
+
'Yoast SEO Premium'
|
32 |
+
),
|
33 |
+
'buylink' => WPSEO_Shortlinker::get( 'https://yoa.st/add-keywords-popup' ),
|
34 |
+
'buy' => sprintf(
|
35 |
+
/* translators: %s expands to 'Yoast SEO Premium'. */
|
36 |
+
__( 'Get %s now!', 'wordpress-seo' ),
|
37 |
+
'Yoast SEO Premium'
|
38 |
+
),
|
39 |
+
'small' => __( '1 year free updates and upgrades included!', 'wordpress-seo' ),
|
40 |
+
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ),
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Passes translations to JS for the Multiple Keywords modal component.
|
46 |
+
*
|
47 |
+
* @return array Translated text strings for the Multiple Keywords modal component.
|
48 |
+
*/
|
49 |
+
public function get_translations_for_js() {
|
50 |
+
$translations = $this->get_translations();
|
51 |
+
|
52 |
+
return array(
|
53 |
+
'locale' => WPSEO_Utils::get_user_locale(),
|
54 |
+
'intl' => $translations,
|
55 |
+
);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Prints the localized Multiple Keywords modal translations for JS.
|
60 |
+
*
|
61 |
+
* @return void
|
62 |
+
*/
|
63 |
+
public function enqueue_translations() {
|
64 |
+
wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'admin-global-script', 'yoastMultipleKeywordsModalL10n', $this->get_translations_for_js() );
|
65 |
+
}
|
66 |
+
}
|
admin/class-structured-data-blocks.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Admin
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class to load assets required for structured data blocks.
|
10 |
+
*/
|
11 |
+
class WPSEO_Structured_Data_Blocks {
|
12 |
+
/**
|
13 |
+
* @var WPSEO_Admin_Asset_Manager
|
14 |
+
*/
|
15 |
+
protected $asset_manager;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* WPSEO_Structured_Data_Blocks constructor.
|
19 |
+
*/
|
20 |
+
public function __construct() {
|
21 |
+
$this->asset_manager = new WPSEO_Admin_Asset_Manager();
|
22 |
+
|
23 |
+
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
|
24 |
+
add_filter( 'block_categories', array( $this, 'add_block_category' ) );
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Enqueue Gutenberg block assets for backend editor.
|
29 |
+
*/
|
30 |
+
public function enqueue_block_editor_assets() {
|
31 |
+
$this->asset_manager->enqueue_script( 'structured-data-blocks' );
|
32 |
+
$this->asset_manager->enqueue_style( 'structured-data-blocks' );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Adds the structured data blocks category to the Gutenberg categories.
|
37 |
+
*
|
38 |
+
* @param array $categories The current categories.
|
39 |
+
*
|
40 |
+
* @return array The updated categories.
|
41 |
+
*/
|
42 |
+
public function add_block_category( $categories ) {
|
43 |
+
$categories[] = array(
|
44 |
+
'slug' => 'yoast-structured-data-blocks',
|
45 |
+
'title' => __( 'Structured Data Blocks', 'wordpress-seo' ),
|
46 |
+
);
|
47 |
+
|
48 |
+
return $categories;
|
49 |
+
}
|
50 |
+
}
|
admin/class-yoast-form.php
CHANGED
@@ -76,8 +76,19 @@ class Yoast_Form {
|
|
76 |
<?php
|
77 |
if ( $form === true ) {
|
78 |
$enctype = ( $contains_files ) ? ' enctype="multipart/form-data"' : '';
|
79 |
-
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
}
|
82 |
$this->set_option( $option );
|
83 |
}
|
76 |
<?php
|
77 |
if ( $form === true ) {
|
78 |
$enctype = ( $contains_files ) ? ' enctype="multipart/form-data"' : '';
|
79 |
+
|
80 |
+
$network_admin = new Yoast_Network_Admin();
|
81 |
+
if ( $network_admin->meets_requirements() ) {
|
82 |
+
$action_url = network_admin_url( 'settings.php' );
|
83 |
+
$hidden_fields_cb = array( $network_admin, 'settings_fields' );
|
84 |
+
}
|
85 |
+
else {
|
86 |
+
$action_url = admin_url( 'options.php' );
|
87 |
+
$hidden_fields_cb = 'settings_fields';
|
88 |
+
}
|
89 |
+
|
90 |
+
echo '<form action="' . esc_url( $action_url ) . '" method="post" id="wpseo-conf"' . $enctype . ' accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
|
91 |
+
call_user_func( $hidden_fields_cb, $option_long_name );
|
92 |
}
|
93 |
$this->set_option( $option );
|
94 |
}
|
admin/class-yoast-network-admin.php
ADDED
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Internals
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Multisite utility class for network admin functionality.
|
10 |
+
*/
|
11 |
+
class Yoast_Network_Admin implements WPSEO_WordPress_Integration, WPSEO_WordPress_AJAX_Integration {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Action identifier for updating plugin network options.
|
15 |
+
*/
|
16 |
+
const UPDATE_OPTIONS_ACTION = 'yoast_handle_network_options';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Action identifier for restoring a site.
|
20 |
+
*/
|
21 |
+
const RESTORE_SITE_ACTION = 'yoast_restore_site';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Gets the available sites as choices, e.g. for a dropdown.
|
25 |
+
*
|
26 |
+
* @param bool $include_empty Optional. Whether to include an initial placeholder choice.
|
27 |
+
*
|
28 |
+
* @return array Choices as $site_id => $site_label pairs.
|
29 |
+
*/
|
30 |
+
public function get_site_choices( $include_empty = false ) {
|
31 |
+
$choices = array();
|
32 |
+
|
33 |
+
if ( $include_empty ) {
|
34 |
+
$choices['-'] = __( 'None', 'wordpress-seo' );
|
35 |
+
}
|
36 |
+
|
37 |
+
$sites = get_sites( array( 'deleted' => 0 ) );
|
38 |
+
foreach ( $sites as $site ) {
|
39 |
+
$choices[ $site->blog_id ] = $site->blog_id . ': ' . $site->domain . $site->path;
|
40 |
+
|
41 |
+
$site_states = $this->get_site_states( $site );
|
42 |
+
if ( ! empty( $site_states ) ) {
|
43 |
+
$choices[ $site->blog_id ] .= ' [' . implode( ', ', $site_states ) . ']';
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
return $choices;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Gets the states of a site.
|
52 |
+
*
|
53 |
+
* @param WP_Site $site Site object.
|
54 |
+
*
|
55 |
+
* @return array Array of $state_slug => $state_label pairs.
|
56 |
+
*/
|
57 |
+
public function get_site_states( $site ) {
|
58 |
+
$available_states = array(
|
59 |
+
'public' => __( 'public', 'wordpress-seo' ),
|
60 |
+
'archived' => __( 'archived', 'wordpress-seo' ),
|
61 |
+
'mature' => __( 'mature', 'wordpress-seo' ),
|
62 |
+
'spam' => __( 'spam', 'wordpress-seo' ),
|
63 |
+
'deleted' => __( 'deleted', 'wordpress-seo' ),
|
64 |
+
);
|
65 |
+
|
66 |
+
$site_states = array();
|
67 |
+
foreach ( $available_states as $state_slug => $state_label ) {
|
68 |
+
if ( $site->$state_slug === '1' ) {
|
69 |
+
$site_states[ $state_slug ] = $state_label;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
return $site_states;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Handles a request to update plugin network options.
|
78 |
+
*
|
79 |
+
* This method works similar to how option updates are handled in `wp-admin/options.php` and
|
80 |
+
* `wp-admin/network/settings.php`.
|
81 |
+
*
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
public function handle_update_options_request() {
|
85 |
+
$option_group = filter_input( INPUT_POST, 'network_option_group', FILTER_SANITIZE_STRING );
|
86 |
+
|
87 |
+
$this->verify_request( "{$option_group}-network-options" );
|
88 |
+
|
89 |
+
$whitelist_options = Yoast_Network_Settings_API::get()->get_whitelist_options( $option_group );
|
90 |
+
|
91 |
+
if ( empty( $whitelist_options ) ) {
|
92 |
+
add_settings_error( $option_group, 'settings_updated', __( 'You are not allowed to modify unregistered network settings.', 'wordpress-seo' ), 'error' );
|
93 |
+
|
94 |
+
$this->terminate_request();
|
95 |
+
return;
|
96 |
+
}
|
97 |
+
|
98 |
+
foreach ( $whitelist_options as $option_name ) {
|
99 |
+
$value = null;
|
100 |
+
if ( isset( $_POST[ $option_name ] ) ) { // WPCS: CSRF ok.
|
101 |
+
$value = wp_unslash( $_POST[ $option_name ] ); // WPCS: CSRF ok.
|
102 |
+
}
|
103 |
+
|
104 |
+
WPSEO_Options::update_site_option( $option_name, $value );
|
105 |
+
}
|
106 |
+
|
107 |
+
$settings_errors = get_settings_errors();
|
108 |
+
if ( empty( $settings_errors ) ) {
|
109 |
+
add_settings_error( $option_group, 'settings_updated', __( 'Settings Updated.', 'wordpress-seo' ), 'updated' );
|
110 |
+
}
|
111 |
+
|
112 |
+
$this->terminate_request();
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Handles a request to restore a site's default settings.
|
117 |
+
*
|
118 |
+
* @return void
|
119 |
+
*/
|
120 |
+
public function handle_restore_site_request() {
|
121 |
+
$this->verify_request( 'wpseo-network-restore', 'restore_site_nonce' );
|
122 |
+
|
123 |
+
$option_group = 'wpseo_ms';
|
124 |
+
|
125 |
+
$site_id = ! empty( $_POST[ $option_group ]['site_id'] ) ? (int) $_POST[ $option_group ]['site_id'] : 0; // WPCS: CSRF ok.
|
126 |
+
if ( ! $site_id ) {
|
127 |
+
add_settings_error( $option_group, 'settings_updated', __( 'No site has been selected to restore.', 'wordpress-seo' ), 'error' );
|
128 |
+
|
129 |
+
$this->terminate_request();
|
130 |
+
return;
|
131 |
+
}
|
132 |
+
|
133 |
+
$site = get_site( $site_id );
|
134 |
+
if ( ! $site ) {
|
135 |
+
/* translators: %s expands to the ID of a site within a multisite network. */
|
136 |
+
add_settings_error( $option_group, 'settings_updated', sprintf( __( 'Site with ID %d not found.', 'wordpress-seo' ), $site_id ), 'error' );
|
137 |
+
}
|
138 |
+
else {
|
139 |
+
WPSEO_Options::reset_ms_blog( $site_id );
|
140 |
+
|
141 |
+
/* translators: %s expands to the name of a site within a multisite network. */
|
142 |
+
add_settings_error( $option_group, 'settings_updated', sprintf( __( '%s restored to default SEO settings.', 'wordpress-seo' ), esc_html( $site->blogname ) ), 'updated' );
|
143 |
+
}
|
144 |
+
|
145 |
+
$this->terminate_request();
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Outputs nonce, action and option group fields for a network settings page in the plugin.
|
150 |
+
*
|
151 |
+
* @param string $option_group Option group name for the current page.
|
152 |
+
*
|
153 |
+
* @return void
|
154 |
+
*/
|
155 |
+
public function settings_fields( $option_group ) {
|
156 |
+
?>
|
157 |
+
<input type="hidden" name="network_option_group" value="<?php echo esc_attr( $option_group ); ?>" />
|
158 |
+
<input type="hidden" name="action" value="<?php echo esc_attr( self::UPDATE_OPTIONS_ACTION ); ?>" />
|
159 |
+
<?php
|
160 |
+
wp_nonce_field( "$option_group-network-options" );
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Enqueues network admin assets.
|
165 |
+
*
|
166 |
+
* @return void
|
167 |
+
*/
|
168 |
+
public function enqueue_assets() {
|
169 |
+
$asset_manager = new WPSEO_Admin_Asset_Manager();
|
170 |
+
$asset_manager->enqueue_script( 'network-admin-script' );
|
171 |
+
|
172 |
+
wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'network-admin-script', 'wpseoNetworkAdminGlobalL10n', array(
|
173 |
+
|
174 |
+
/* translators: %s: success message */
|
175 |
+
'success_prefix' => __( 'Success: %s', 'wordpress-seo' ),
|
176 |
+
|
177 |
+
/* translators: %s: error message */
|
178 |
+
'error_prefix' => __( 'Error: %s', 'wordpress-seo' ),
|
179 |
+
) );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Hooks in the necessary actions and filters.
|
184 |
+
*
|
185 |
+
* @return void
|
186 |
+
*/
|
187 |
+
public function register_hooks() {
|
188 |
+
|
189 |
+
if ( ! $this->meets_requirements() ) {
|
190 |
+
return;
|
191 |
+
}
|
192 |
+
|
193 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
|
194 |
+
|
195 |
+
add_action( 'admin_action_' . self::UPDATE_OPTIONS_ACTION, array( $this, 'handle_update_options_request' ) );
|
196 |
+
add_action( 'admin_action_' . self::RESTORE_SITE_ACTION, array( $this, 'handle_restore_site_request' ) );
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Hooks in the necessary AJAX actions.
|
201 |
+
*
|
202 |
+
* @return void
|
203 |
+
*/
|
204 |
+
public function register_ajax_hooks() {
|
205 |
+
add_action( 'wp_ajax_' . self::UPDATE_OPTIONS_ACTION, array( $this, 'handle_update_options_request' ) );
|
206 |
+
add_action( 'wp_ajax_' . self::RESTORE_SITE_ACTION, array( $this, 'handle_restore_site_request' ) );
|
207 |
+
}
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Checks whether the requirements to use this class are met.
|
211 |
+
*
|
212 |
+
* @return bool True if requirements are met, false otherwise.
|
213 |
+
*/
|
214 |
+
public function meets_requirements() {
|
215 |
+
return is_multisite() && is_network_admin();
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Verifies that the current request is valid.
|
220 |
+
*
|
221 |
+
* @param string $action Nonce action.
|
222 |
+
* @param string $query_arg Optional. Nonce query argument. Default '_wpnonce'.
|
223 |
+
*
|
224 |
+
* @return void
|
225 |
+
*/
|
226 |
+
public function verify_request( $action, $query_arg = '_wpnonce' ) {
|
227 |
+
$has_access = current_user_can( 'wpseo_manage_network_options' );
|
228 |
+
|
229 |
+
if ( wp_doing_ajax() ) {
|
230 |
+
check_ajax_referer( $action, $query_arg );
|
231 |
+
|
232 |
+
if ( ! $has_access ) {
|
233 |
+
wp_die( -1, 403 );
|
234 |
+
}
|
235 |
+
return;
|
236 |
+
}
|
237 |
+
|
238 |
+
check_admin_referer( $action, $query_arg );
|
239 |
+
|
240 |
+
if ( ! $has_access ) {
|
241 |
+
wp_die( __( 'You are not allowed to perform this action.', 'wordpress-seo' ) );
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Terminates the current request by either redirecting back or sending an AJAX response.
|
247 |
+
*
|
248 |
+
* @return void
|
249 |
+
*/
|
250 |
+
public function terminate_request() {
|
251 |
+
if ( wp_doing_ajax() ) {
|
252 |
+
$settings_errors = get_settings_errors();
|
253 |
+
|
254 |
+
if ( ! empty( $settings_errors ) && $settings_errors[0]['type'] === 'updated' ) {
|
255 |
+
wp_send_json_success( $settings_errors, 200 );
|
256 |
+
}
|
257 |
+
|
258 |
+
wp_send_json_error( $settings_errors, 400 );
|
259 |
+
}
|
260 |
+
|
261 |
+
$this->persist_settings_errors();
|
262 |
+
$this->redirect_back( array( 'settings-updated' => 'true' ) );
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Persists settings errors.
|
267 |
+
*
|
268 |
+
* Settings errors are stored in a transient for 30 seconds so that this transient
|
269 |
+
* can be retrieved on the next page load.
|
270 |
+
*
|
271 |
+
* @return void
|
272 |
+
*/
|
273 |
+
protected function persist_settings_errors() {
|
274 |
+
/*
|
275 |
+
* A regular transient is used here, since it is automatically cleared right after the redirect.
|
276 |
+
* A network transient would be cleaner, but would require a lot of copied code from core for
|
277 |
+
* just a minor adjustment when displaying settings errors.
|
278 |
+
*/
|
279 |
+
set_transient( 'settings_errors', get_settings_errors(), 30 );
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Redirects back to the referer URL, with optional query arguments.
|
284 |
+
*
|
285 |
+
* @param array $query_args Optional. Query arguments to add to the redirect URL. Default none.
|
286 |
+
*
|
287 |
+
* @return void
|
288 |
+
*/
|
289 |
+
protected function redirect_back( $query_args = array() ) {
|
290 |
+
$sendback = wp_get_referer();
|
291 |
+
|
292 |
+
if ( ! empty( $query_args ) ) {
|
293 |
+
$sendback = add_query_arg( $query_args, $sendback );
|
294 |
+
}
|
295 |
+
|
296 |
+
wp_safe_redirect( $sendback );
|
297 |
+
exit;
|
298 |
+
}
|
299 |
+
}
|
admin/class-yoast-network-settings-api.php
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* WPSEO plugin file.
|
4 |
+
*
|
5 |
+
* @package WPSEO\Admin\Network
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Implements a network settings API for the plugin's multisite settings.
|
10 |
+
*/
|
11 |
+
class Yoast_Network_Settings_API {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array Registered network settings.
|
15 |
+
*/
|
16 |
+
private $registered_settings = array();
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var array Options whitelist, keyed by option group.
|
20 |
+
*/
|
21 |
+
private $whitelist_options = array();
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var Yoast_Network_Settings_API The singleton instance of this class.
|
25 |
+
*/
|
26 |
+
private static $instance = null;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Registers a network setting and its data.
|
30 |
+
*
|
31 |
+
* @param string $option_group The group the network option is part of.
|
32 |
+
* @param string $option_name The name of the network option to sanitize and save.
|
33 |
+
* @param array $args {
|
34 |
+
* Optional. Data used to describe the network setting when registered.
|
35 |
+
*
|
36 |
+
* @type callable $sanitize_callback A callback function that sanitizes the network option's value.
|
37 |
+
* @type mixed $default Default value when calling `get_network_option()`.
|
38 |
+
* }
|
39 |
+
*
|
40 |
+
* @return void
|
41 |
+
*/
|
42 |
+
public function register_setting( $option_group, $option_name, $args = array() ) {
|
43 |
+
|
44 |
+
$args = wp_parse_args( $args, array(
|
45 |
+
'group' => $option_group,
|
46 |
+
'sanitize_callback' => null,
|
47 |
+
) );
|
48 |
+
|
49 |
+
if ( ! isset( $this->whitelist_options[ $option_group ] ) ) {
|
50 |
+
$this->whitelist_options[ $option_group ] = array();
|
51 |
+
}
|
52 |
+
|
53 |
+
$this->whitelist_options[ $option_group ][] = $option_name;
|
54 |
+
|
55 |
+
if ( ! empty( $args['sanitize_callback'] ) ) {
|
56 |
+
add_filter( "sanitize_option_{$option_name}", array( $this, 'filter_sanitize_option' ), 10, 2 );
|
57 |
+
}
|
58 |
+
|
59 |
+
if ( array_key_exists( 'default', $args ) ) {
|
60 |
+
add_filter( "default_site_option_{$option_name}", array( $this, 'filter_default_option' ), 10, 2 );
|
61 |
+
}
|
62 |
+
|
63 |
+
$this->registered_settings[ $option_name ] = $args;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Gets the registered settings and their data.
|
68 |
+
*
|
69 |
+
* @return array Array of $option_name => $data pairs.
|
70 |
+
*/
|
71 |
+
public function get_registered_settings() {
|
72 |
+
return $this->registered_settings;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Gets the whitelisted options for a given option group.
|
77 |
+
*
|
78 |
+
* @param string $option_group Option group.
|
79 |
+
*
|
80 |
+
* @return array List of option names, or empty array if unknown option group.
|
81 |
+
*/
|
82 |
+
public function get_whitelist_options( $option_group ) {
|
83 |
+
if ( ! isset( $this->whitelist_options[ $option_group ] ) ) {
|
84 |
+
return array();
|
85 |
+
}
|
86 |
+
|
87 |
+
return $this->whitelist_options[ $option_group ];
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Filters sanitization for a network option value.
|
92 |
+
*
|
93 |
+
* This method is added as a filter to `sanitize_option_{$option}` for network options that are
|
94 |
+
* registered with a sanitize callback.
|
95 |
+
*
|
96 |
+
* @param string $value The sanitized option value.
|
97 |
+
* @param string $option The option name.
|
98 |
+
*
|
99 |
+
* @return string The filtered sanitized option value.
|
100 |
+
*/
|
101 |
+
public function filter_sanitize_option( $value, $option ) {
|
102 |
+
|
103 |
+
if ( empty( $this->registered_settings[ $option ] ) ) {
|
104 |
+
return $value;
|
105 |
+
}
|
106 |
+
|
107 |
+
return call_user_func( $this->registered_settings[ $option ]['sanitize_callback'], $value );
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Filters the default value for a network option.
|
112 |
+
*
|
113 |
+
* This function is added as a filter to `default_site_option_{$option}` for network options that
|
114 |
+
* are registered with a default.
|
115 |
+
*
|
116 |
+
* @param mixed $default Existing default value to return.
|
117 |
+
* @param string $option The option name.
|
118 |
+
*
|
119 |
+
* @return mixed The filtered default value.
|
120 |
+
*/
|
121 |
+
public function filter_default_option( $default, $option ) {
|
122 |
+
|
123 |
+
// If a default value was manually passed to the function, allow it to override.
|
124 |
+
if ( $default !== false ) {
|
125 |
+
return $default;
|
126 |
+
}
|
127 |
+
|
128 |
+
if ( empty( $this->registered_settings[ $option ] ) ) {
|
129 |
+
return $default;
|
130 |
+
}
|
131 |
+
|
132 |
+
return $this->registered_settings[ $option ]['default'];
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Checks whether the requirements to use this class are met.
|
137 |
+
*
|
138 |
+
* @return bool True if requirements are met, false otherwise.
|
139 |
+
*/
|
140 |
+
public function meets_requirements() {
|
141 |
+
return is_multisite();
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Gets the singleton instance of this class.
|
146 |
+
*
|
147 |
+
* @return Yoast_Network_Settings_API The singleton instance.
|
148 |
+
*/
|
149 |
+
public static function get() {
|
150 |
+
|
151 |
+
if ( self::$instance === null ) {
|
152 |
+
self::$instance = new self();
|
153 |
+
}
|
154 |
+
|
155 |
+
return self::$instance;
|
156 |
+
}
|
157 |
+
}
|
admin/formatter/class-metabox-formatter.php
CHANGED
@@ -45,6 +45,9 @@ class WPSEO_Metabox_Formatter {
|
|
45 |
$analysis_seo = new WPSEO_Metabox_Analysis_SEO();
|
46 |
$analysis_readability = new WPSEO_Metabox_Analysis_Readability();
|
47 |
|
|
|
|
|
|
|
48 |
return array(
|
49 |
'language' => WPSEO_Language_Utils::get_site_language_name(),
|
50 |
'settings_link' => $this->get_settings_link(),
|
@@ -53,7 +56,6 @@ class WPSEO_Metabox_Formatter {
|
|
53 |
'base_url' => '',
|
54 |
'contentTab' => __( 'Readability', 'wordpress-seo' ),
|
55 |
'keywordTab' => __( 'Keyword:', 'wordpress-seo' ),
|
56 |
-
'enterFocusKeyword' => __( 'Enter your focus keyword', 'wordpress-seo' ),
|
57 |
'removeKeyword' => __( 'Remove keyword', 'wordpress-seo' ),
|
58 |
'contentLocale' => get_locale(),
|
59 |
'userLocale' => WPSEO_Utils::get_user_locale(),
|
@@ -63,9 +65,10 @@ class WPSEO_Metabox_Formatter {
|
|
63 |
'metadesc_template' => '',
|
64 |
'contentAnalysisActive' => $analysis_readability->is_enabled() ? 1 : 0,
|
65 |
'keywordAnalysisActive' => $analysis_seo->is_enabled() ? 1 : 0,
|
|
|
66 |
'intl' => $this->get_content_analysis_component_translations(),
|
67 |
'isRtl' => is_rtl(),
|
68 |
-
'
|
69 |
|
70 |
/**
|
71 |
* Filter to determine if the markers should be enabled or not.
|
@@ -172,6 +175,37 @@ class WPSEO_Metabox_Formatter {
|
|
172 |
);
|
173 |
}
|
174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
/**
|
176 |
* Returns Jed compatible YoastSEO.js translations.
|
177 |
*
|
45 |
$analysis_seo = new WPSEO_Metabox_Analysis_SEO();
|
46 |
$analysis_readability = new WPSEO_Metabox_Analysis_Readability();
|
47 |
|
48 |
+
$premium_benefits = new WPSEO_Premium_Benefits_List();
|
49 |
+
$premium_benefits->enqueue_translations();
|
50 |
+
|
51 |
return array(
|
52 |
'language' => WPSEO_Language_Utils::get_site_language_name(),
|
53 |
'settings_link' => $this->get_settings_link(),
|
56 |
'base_url' => '',
|
57 |
'contentTab' => __( 'Readability', 'wordpress-seo' ),
|
58 |
'keywordTab' => __( 'Keyword:', 'wordpress-seo' ),
|
|
|
59 |
'removeKeyword' => __( 'Remove keyword', 'wordpress-seo' ),
|
60 |
'contentLocale' => get_locale(),
|
61 |
'userLocale' => WPSEO_Utils::get_user_locale(),
|
65 |
'metadesc_template' => '',
|
66 |
'contentAnalysisActive' => $analysis_readability->is_enabled() ? 1 : 0,
|
67 |
'keywordAnalysisActive' => $analysis_seo->is_enabled() ? 1 : 0,
|
68 |
+
'cornerstoneActive' => WPSEO_Options::get( 'enable_cornerstone_content', false ) ? 1 : 0,
|
69 |
'intl' => $this->get_content_analysis_component_translations(),
|
70 |
'isRtl' => is_rtl(),
|
71 |
+
'addKeywordUpsell' => $this->get_add_keyword_upsell_translations(),
|
72 |
|
73 |
/**
|
74 |
* Filter to determine if the markers should be enabled or not.
|
175 |
);
|
176 |
}
|
177 |
|
178 |
+
/**
|
179 |
+
* Returns the translations for the Add Keyword modal.
|
180 |
+
*
|
181 |
+
* These strings are not escaped because they're meant to be used with React
|
182 |
+
* which already takes care of that. If used in PHP, they should be escaped.
|
183 |
+
*
|
184 |
+
* @return array Translated text strings for the Add Keyword modal.
|
185 |
+
*/
|
186 |
+
public function get_add_keyword_upsell_translations() {
|
187 |
+
return array(
|
188 |
+
'title' => __( 'Would you like to add more than one keyword?', 'wordpress-seo' ),
|
189 |
+
'intro' => sprintf(
|
190 |
+
/* translators: %1$s expands to a 'Yoast SEO Premium' text linked to the yoast.com website. */
|
191 |
+
__( 'Great news: you can, with %1$s!', 'wordpress-seo' ),
|
192 |
+
'{{link}}Yoast SEO Premium{{/link}}'
|
193 |
+
),
|
194 |
+
'link' => WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ),
|
195 |
+
'other' => sprintf(
|
196 |
+
/* translators: %s expands to 'Yoast SEO Premium'. */
|
197 |
+
__( 'Other benefits of %s for you:', 'wordpress-seo' ), 'Yoast SEO Premium'
|
198 |
+
),
|
199 |
+
'buylink' => WPSEO_Shortlinker::get( 'https://yoa.st/add-keywords-popup' ),
|
200 |
+
'buy' => sprintf(
|
201 |
+
/* translators: %s expands to 'Yoast SEO Premium'. */
|
202 |
+
__( 'Get %s now!', 'wordpress-seo' ), 'Yoast SEO Premium'
|
203 |
+
),
|
204 |
+
'small' => __( '1 year free updates and upgrades included!', 'wordpress-seo' ),
|
205 |
+
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ),
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
/**
|
210 |
* Returns Jed compatible YoastSEO.js translations.
|
211 |
*
|
admin/menu/class-admin-menu.php
CHANGED
@@ -8,18 +8,7 @@
|
|
8 |
/**
|
9 |
* Registers the admin menu on the left of the admin area.
|
10 |
*/
|
11 |
-
class WPSEO_Admin_Menu
|
12 |
-
/** @var WPSEO_Menu Menu */
|
13 |
-
protected $menu;
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Constructs the Admin Menu.
|
17 |
-
*
|
18 |
-
* @param WPSEO_Menu $menu Menu to use.
|
19 |
-
*/
|
20 |
-
public function __construct( WPSEO_Menu $menu ) {
|
21 |
-
$this->menu = $menu;
|
22 |
-
}
|
23 |
|
24 |
/**
|
25 |
* Registers all hooks to WordPress.
|
@@ -35,7 +24,7 @@ class WPSEO_Admin_Menu implements WPSEO_WordPress_Integration {
|
|
35 |
* Registers the menu item submenus.
|
36 |
*/
|
37 |
public function register_settings_page() {
|
38 |
-
$can_manage_options =
|
39 |
|
40 |
if ( $can_manage_options ) {
|
41 |
/*
|
@@ -48,13 +37,14 @@ class WPSEO_Admin_Menu implements WPSEO_WordPress_Integration {
|
|
48 |
'Yoast SEO: ' . __( 'Dashboard', 'wordpress-seo' ),
|
49 |
__( 'SEO', 'wordpress-seo' ) . ' ' . $this->get_notification_counter(),
|
50 |
$this->get_manage_capability(),
|
51 |