The SEO Framework - Version 3.2.2

Version Description

This minor update brings major bug fixes. Most notoriously, the home page settings now predict the metadata perfectly in the admin screens. Bloggers will love this update, too, because Facebook and Twitter metadata for the home blog page is now always correct.

For developers, please note that the upcoming major release (3.3.0) will introduce new taxonomical settings. Because the image-rendering integration isn't suited for this, it'll be overhauled. For more information, see this issue.

Also, for developers, note that some API changes better suited for a major release were also brought into this minor release; these were required to fix some bugs.

Download this release

Release Info

Developer Cybr
Plugin Icon 128x128 The SEO Framework
Version 3.2.2
Comparing to
See all releases

Code changes from version 3.1.4 to 3.2.2

Files changed (70) hide show
  1. autodescription.php +4 -4
  2. bootstrap/activation.php +2 -2
  3. bootstrap/deactivation.php +2 -1
  4. bootstrap/define.php +1 -1
  5. bootstrap/envtest.php +5 -3
  6. bootstrap/load.php +7 -7
  7. bootstrap/upgrade.php +6 -4
  8. inc/classes/admin-init.class.php +178 -87
  9. inc/classes/admin-pages.class.php +3 -3
  10. inc/classes/builders/scripts.class.php +174 -62
  11. inc/classes/cache.class.php +28 -27
  12. inc/classes/compat.class.php +1 -1
  13. inc/classes/core.class.php +38 -49
  14. inc/classes/debug.class.php +55 -41
  15. inc/classes/deprecated.class.php +1 -2
  16. inc/classes/detect.class.php +37 -25
  17. inc/classes/doing-it-right.class.php +3 -2
  18. inc/classes/feed.class.php +1 -1
  19. inc/classes/generate-description.class.php +103 -204
  20. inc/classes/generate-image.class.php +16 -26
  21. inc/classes/generate-ldjson.class.php +13 -11
  22. inc/classes/generate-title.class.php +185 -70
  23. inc/classes/generate-url.class.php +29 -24
  24. inc/classes/generate.class.php +3 -4
  25. inc/classes/init.class.php +3 -3
  26. inc/classes/inpost.class.php +7 -4
  27. inc/classes/load.class.php +4 -4
  28. inc/classes/metaboxes.class.php +8 -29
  29. inc/classes/post-data.class.php +17 -17
  30. inc/classes/profile.class.php +6 -7
  31. inc/classes/query.class.php +76 -92
  32. inc/classes/render.class.php +3 -3
  33. inc/classes/sanitize.class.php +32 -76
  34. inc/classes/silencer.class.php +1 -1
  35. inc/classes/site-options.class.php +3 -4
  36. inc/classes/sitemaps.class.php +7 -2
  37. inc/classes/term-data.class.php +8 -8
  38. inc/classes/user-data.class.php +13 -4
  39. inc/functions/api.php +1 -1
  40. inc/functions/deprecated.php +2 -2
  41. inc/functions/tsfem-suggestion.php +10 -108
  42. inc/interfaces/debug.interface.php +4 -4
  43. inc/views/inpost/seo-settings-singular-gutenberg-data.php +12 -0
  44. inc/views/inpost/seo-settings-singular.php +14 -6
  45. inc/views/metaboxes/description-metabox.php +3 -146
  46. inc/views/metaboxes/feed-metabox.php +1 -1
  47. inc/views/metaboxes/general-metabox.php +9 -9
  48. inc/views/metaboxes/homepage-metabox.php +6 -6
  49. inc/views/metaboxes/robots-metabox.php +3 -3
  50. inc/views/metaboxes/schema-metabox.php +4 -4
  51. inc/views/metaboxes/social-metabox.php +7 -7
  52. inc/views/metaboxes/title-metabox.php +4 -4
  53. inc/views/metaboxes/webmaster-metabox.php +1 -1
  54. language/autodescription.pot +120 -193
  55. lib/css/pt.css +7 -0
  56. lib/css/pt.min.css +1 -1
  57. lib/js/gutenberg.js +1 -1
  58. lib/js/installer/tsfinstaller.js +0 -285
  59. lib/js/installer/tsfinstaller.min.js +0 -1
  60. lib/js/media.js +1 -1
  61. lib/js/pt-gb.js +339 -0
  62. lib/js/pt-gb.min.js +1 -0
  63. lib/js/pt.js +1 -1
  64. lib/js/tsf-gbc.js +253 -0
  65. lib/js/tsf-gbc.min.js +1 -0
  66. lib/js/tsf.js +107 -141
  67. lib/js/tsf.min.js +1 -1
  68. lib/js/tt.js +6 -3
  69. lib/js/tt.min.js +1 -1
  70. readme.txt +97 -120
autodescription.php CHANGED
@@ -2,8 +2,8 @@
2
  /**
3
  * Plugin Name: The SEO Framework
4
  * Plugin URI: https://theseoframework.com/
5
- * Description: An automated, advanced, accessible, unbranded and extremely fast SEO solution for any WordPress website.
6
- * Version: 3.1.4
7
  * Author: Sybre Waaijer
8
  * Author URI: https://theseoframework.com/
9
  * License: GPLv3
@@ -15,7 +15,7 @@ defined( 'ABSPATH' ) or die;
15
 
16
  /**
17
  * The SEO Framework plugin
18
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
19
  *
20
  * This program is free software: you can redistribute it and/or modify
21
  * it under the terms of the GNU General Public License version 3 as published
@@ -53,7 +53,7 @@ defined( 'ABSPATH' ) or die;
53
  *
54
  * @since 2.3.5
55
  */
56
- define( 'THE_SEO_FRAMEWORK_VERSION', '3.1.4' );
57
 
58
  /**
59
  * The plugin Database version.
2
  /**
3
  * Plugin Name: The SEO Framework
4
  * Plugin URI: https://theseoframework.com/
5
+ * Description: An automated, advanced, accessible, unbranded and extremely fast SEO solution for your WordPress website.
6
+ * Version: 3.2.2
7
  * Author: Sybre Waaijer
8
  * Author URI: https://theseoframework.com/
9
  * License: GPLv3
15
 
16
  /**
17
  * The SEO Framework plugin
18
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
19
  *
20
  * This program is free software: you can redistribute it and/or modify
21
  * it under the terms of the GNU General Public License version 3 as published
53
  *
54
  * @since 2.3.5
55
  */
56
+ define( 'THE_SEO_FRAMEWORK_VERSION', '3.2.2' );
57
 
58
  /**
59
  * The plugin Database version.
bootstrap/activation.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -84,8 +84,8 @@ function _activation_set_options_autoload() {
84
  \remove_all_actions( "update_option_{$setting}" );
85
  \remove_all_filters( "sanitize_option_{$setting}" );
86
 
87
- //? Write a small difference, so the change will be forwarded to the database.
88
  $temp_options = $options;
 
89
  if ( is_array( $temp_options ) )
90
  $temp_options['update_buster'] = (int) time();
91
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
84
  \remove_all_actions( "update_option_{$setting}" );
85
  \remove_all_filters( "sanitize_option_{$setting}" );
86
 
 
87
  $temp_options = $options;
88
+ //? Write a small difference, so the change will be forwarded to the database.
89
  if ( is_array( $temp_options ) )
90
  $temp_options['update_buster'] = (int) time();
91
 
bootstrap/deactivation.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -65,6 +65,7 @@ function _deactivation_unset_options_autoload() {
65
  \remove_all_filters( "sanitize_option_{$setting}" );
66
 
67
  $temp_options = $options;
 
68
  if ( is_array( $temp_options ) )
69
  $temp_options['update_buster'] = (int) time();
70
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
65
  \remove_all_filters( "sanitize_option_{$setting}" );
66
 
67
  $temp_options = $options;
68
+ //? Write a small difference, so the change will be forwarded to the database.
69
  if ( is_array( $temp_options ) )
70
  $temp_options['update_buster'] = (int) time();
71
 
bootstrap/define.php CHANGED
@@ -7,7 +7,7 @@ defined( 'THE_SEO_FRAMEWORK_DB_VERSION' ) or die;
7
 
8
  /**
9
  * The SEO Framework plugin
10
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
7
 
8
  /**
9
  * The SEO Framework plugin
10
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
bootstrap/envtest.php CHANGED
@@ -7,7 +7,7 @@ defined( 'THE_SEO_FRAMEWORK_DB_VERSION' ) or die;
7
 
8
  /**
9
  * The SEO Framework plugin
10
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
@@ -72,9 +72,11 @@ function the_seo_framework_pre_boot_test() {
72
  'wp' => '37965',
73
  );
74
 
75
- ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < $requirements['php'] and $test = 1
 
76
  or $GLOBALS['wp_db_version'] < $requirements['wp'] and $test = 2
77
  or $test = true;
 
78
 
79
  //* All good.
80
  if ( true === $test ) {
@@ -83,7 +85,7 @@ function the_seo_framework_pre_boot_test() {
83
  }
84
 
85
  if ( $ms ) {
86
- $_plugins = get_site_option( 'active_sitewide_plugins' );
87
  $network_mode = isset( $_plugins[ plugin_basename( THE_SEO_FRAMEWORK_PLUGIN_BASE_FILE ) ] );
88
  } else {
89
  $network_mode = false;
7
 
8
  /**
9
  * The SEO Framework plugin
10
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
72
  'wp' => '37965',
73
  );
74
 
75
+ // phpcs:disable Generic.Formatting.MultipleStatementAlignment.NotSameWarning
76
+ ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < $requirements['php'] and $test = 1 // precision alignment ok.
77
  or $GLOBALS['wp_db_version'] < $requirements['wp'] and $test = 2
78
  or $test = true;
79
+ // phpcs:enable Generic.Formatting.MultipleStatementAlignment.NotSameWarning
80
 
81
  //* All good.
82
  if ( true === $test ) {
85
  }
86
 
87
  if ( $ms ) {
88
+ $_plugins = get_site_option( 'active_sitewide_plugins' );
89
  $network_mode = isset( $_plugins[ plugin_basename( THE_SEO_FRAMEWORK_PLUGIN_BASE_FILE ) ] );
90
  } else {
91
  $network_mode = false;
bootstrap/load.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -70,7 +70,7 @@ function _init_tsf() {
70
  if ( \The_SEO_Framework\_can_load() ) {
71
  if ( \is_admin() ) {
72
  //! TODO: admin-only loader.
73
- $tsf = new \The_SEO_Framework\Load();
74
  $tsf->loaded = true;
75
 
76
  /**
@@ -79,7 +79,7 @@ function _init_tsf() {
79
  */
80
  \do_action( 'the_seo_framework_admin_loaded' );
81
  } else {
82
- $tsf = new \The_SEO_Framework\Load();
83
  $tsf->loaded = true;
84
  }
85
 
@@ -89,7 +89,7 @@ function _init_tsf() {
89
  */
90
  \do_action( 'the_seo_framework_loaded' );
91
  } else {
92
- $tsf = new \The_SEO_Framework\Silencer();
93
  $tsf->loaded = false;
94
  }
95
 
@@ -125,11 +125,11 @@ function _autoload_classes( $class ) {
125
  $strip = 'The_SEO_Framework\\';
126
 
127
  if ( strpos( $class, '_Interface' ) ) {
128
- $path = THE_SEO_FRAMEWORK_DIR_PATH_INTERFACE;
129
  $extension = '.interface.php';
130
- $class = str_replace( '_Interface', '', $class );
131
  } else {
132
- $path = THE_SEO_FRAMEWORK_DIR_PATH_CLASS;
133
  $extension = '.class.php';
134
 
135
  //: substr_count( $class, '\\', 2 ) >= 2 // strrpos... str_split...
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
70
  if ( \The_SEO_Framework\_can_load() ) {
71
  if ( \is_admin() ) {
72
  //! TODO: admin-only loader.
73
+ $tsf = new \The_SEO_Framework\Load();
74
  $tsf->loaded = true;
75
 
76
  /**
79
  */
80
  \do_action( 'the_seo_framework_admin_loaded' );
81
  } else {
82
+ $tsf = new \The_SEO_Framework\Load();
83
  $tsf->loaded = true;
84
  }
85
 
89
  */
90
  \do_action( 'the_seo_framework_loaded' );
91
  } else {
92
+ $tsf = new \The_SEO_Framework\Silencer();
93
  $tsf->loaded = false;
94
  }
95
 
125
  $strip = 'The_SEO_Framework\\';
126
 
127
  if ( strpos( $class, '_Interface' ) ) {
128
+ $path = THE_SEO_FRAMEWORK_DIR_PATH_INTERFACE;
129
  $extension = '.interface.php';
130
+ $class = str_replace( '_Interface', '', $class );
131
  } else {
132
+ $path = THE_SEO_FRAMEWORK_DIR_PATH_CLASS;
133
  $extension = '.class.php';
134
 
135
  //: substr_count( $class, '\\', 2 ) >= 2 // strrpos... str_split...
bootstrap/upgrade.php CHANGED
@@ -3,9 +3,11 @@
3
  * @package The_SEO_Framework/Bootstrap
4
  */
5
 
 
 
6
  /**
7
  * The SEO Framework plugin
8
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
9
  *
10
  * This program is free software: you can redistribute it and/or modify
11
  * it under the terms of the GNU General Public License version 3 as published
@@ -20,8 +22,6 @@
20
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21
  */
22
 
23
- defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
24
-
25
  /**
26
  * This file holds functions for upgrading the plugin.
27
  * This file will only be called ONCE if the required version option is lower
@@ -87,7 +87,7 @@ function the_seo_framework_do_upgrade() {
87
  if ( ! the_seo_framework()->loaded ) return;
88
 
89
  if ( the_seo_framework()->is_seo_settings_page( false ) ) {
90
- wp_redirect( self_admin_url() );
91
  exit;
92
  }
93
 
@@ -194,6 +194,7 @@ add_action( 'the_seo_framework_upgraded', 'the_seo_framework_prepare_extension_m
194
  * Enqueues and outputs an Extension Manager suggestion.
195
  *
196
  * @since 3.1.0
 
197
  * @staticvar bool $run
198
  *
199
  * @return void Early when already enqueued
@@ -204,6 +205,7 @@ function the_seo_framework_prepare_extension_manager_suggestion() {
204
 
205
  if ( is_admin() ) {
206
  add_action( 'admin_init', function() {
 
207
  require THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'tsfem-suggestion.php';
208
  the_seo_framework_load_extension_manager_suggestion();
209
  }, 20 );
3
  * @package The_SEO_Framework/Bootstrap
4
  */
5
 
6
+ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
7
+
8
  /**
9
  * The SEO Framework plugin
10
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
22
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
  */
24
 
 
 
25
  /**
26
  * This file holds functions for upgrading the plugin.
27
  * This file will only be called ONCE if the required version option is lower
87
  if ( ! the_seo_framework()->loaded ) return;
88
 
89
  if ( the_seo_framework()->is_seo_settings_page( false ) ) {
90
+ wp_redirect( self_admin_url() ); // phpcs:ignore -- self_admin_url() is safe.
91
  exit;
92
  }
93
 
194
  * Enqueues and outputs an Extension Manager suggestion.
195
  *
196
  * @since 3.1.0
197
+ * @since 3.2.2. No longer suggests when the user is new.
198
  * @staticvar bool $run
199
  *
200
  * @return void Early when already enqueued
205
 
206
  if ( is_admin() ) {
207
  add_action( 'admin_init', function() {
208
+ if ( ! the_seo_framework_previous_db_version() ) return;
209
  require THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'tsfem-suggestion.php';
210
  the_seo_framework_load_extension_manager_suggestion();
211
  }, 20 );
inc/classes/admin-init.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -99,16 +99,38 @@ class Admin_Init extends Init {
99
 
100
  if ( _has_run( __METHOD__ ) ) return;
101
 
102
- $rtl = \is_rtl();
103
-
104
- //! PHP 5.4 compat: put in var. Also, we call it twice here...
105
  $scripts = $this->Scripts();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  /**
107
  * @since 3.1.0
108
  * @param array $scripts The default CSS and JS loader settings.
109
  * @param string $scripts The \The_SEO_Framework\Builders\Scripts builder class name.
110
  */
111
- $scripts::register( (array) \apply_filters_ref_array( 'the_seo_framework_scripts', [
112
  [
113
  [
114
  'id' => 'tsf',
@@ -162,7 +184,7 @@ class Admin_Init extends Init {
162
  'border-bottom-color:{{$bg_accent}}',
163
  ],
164
  '.tsf-tooltip-text' => [
165
- $rtl ? 'direction:rtl;' : '',
166
  ],
167
  ],
168
  ],
@@ -176,24 +198,42 @@ class Admin_Init extends Init {
176
  'ver' => THE_SEO_FRAMEWORK_VERSION,
177
  ],
178
  ],
179
- $scripts,
180
- ] ) );
 
181
 
182
- if ( $this->is_post_edit() ) {
183
- $this->enqueue_media_scripts();
184
- $this->enqueue_primaryterm_scripts();
185
- } elseif ( $this->is_seo_settings_page() ) {
186
- $this->enqueue_media_scripts();
187
- \wp_enqueue_style( 'wp-color-picker' );
188
- \wp_enqueue_script( 'wp-color-picker' );
189
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  }
191
 
192
  /**
193
  * Enqueues Media Upload and Cropping scripts.
194
  *
195
  * @since 3.1.0
196
- * @staticvar bool|null $registered Prevents duplicate calls.
197
  */
198
  public function enqueue_media_scripts() {
199
 
@@ -254,27 +294,36 @@ class Admin_Init extends Init {
254
 
255
  if ( _has_run( __METHOD__ ) ) return;
256
 
257
- $id = $this->get_the_real_admin_ID();
258
- $rtl = \is_rtl();
259
 
260
  $post_type = \get_post_type( $id );
261
  $_taxonomies = $post_type ? $this->get_hierarchical_taxonomies_as( 'objects', $post_type ) : [];
 
262
 
263
- $taxonomies = [];
264
 
265
  foreach ( $_taxonomies as $_t ) {
266
- $_i18n_name = strtolower( $_t->labels->singular_name );
 
267
  $taxonomies[ $_t->name ] = [
268
  'name' => $_t->name,
269
- 'i18n' => [
270
- /* translators: %s = term name */
271
- 'makePrimary' => sprintf( \esc_html__( 'Make primary %s', 'autodescription' ), $_i18n_name ),
272
- /* translators: %s = term name */
273
- 'primary' => sprintf( \esc_html__( 'Primary %s', 'autodescription' ), $_i18n_name ),
274
- 'name' => $_i18n_name,
275
- ],
276
  'primary' => $this->get_primary_term_id( $id, $_t->name ) ?: 0,
277
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
 
280
  $inline_css = [];
@@ -290,15 +339,29 @@ class Admin_Init extends Init {
290
  ];
291
  }
292
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  //! PHP 5.4 compat: put in var.
294
  $scripts = $this->Scripts();
295
  $scripts::register( [
296
  [
297
- 'id' => 'tsf-pt',
298
  'type' => 'js',
299
- 'deps' => [ 'jquery', 'tsf', 'tsf-tt' ],
300
  'autoload' => true,
301
- 'name' => 'pt',
302
  'base' => THE_SEO_FRAMEWORK_DIR_URL . 'lib/js/',
303
  'ver' => THE_SEO_FRAMEWORK_VERSION,
304
  'l10n' => [
@@ -339,66 +402,69 @@ class Admin_Init extends Init {
339
  * 4 : Added dynamic output control.
340
  * @since 2.9.0 Added boolean $returnValue['states']['isSettingsPage']
341
  * @since 3.0.4 `descPixelGuideline` has been increased from "920 and 820" to "1820 and 1720" respectively.
 
342
  *
343
  * @return array $strings The l10n strings.
344
  */
345
  protected function get_javascript_l10n() {
346
 
347
  $id = $this->get_the_real_ID();
348
- $default_title = '';
 
349
  $title_additions = '';
350
 
351
  $use_title_additions = $this->use_title_branding();
352
- $home_tagline = $this->get_option( 'homepage_title_tagline' );
353
- $title_location = $this->get_option( 'title_location' );
 
354
 
355
- $title_separator = esc_html( $this->get_separator( 'title' ) );
356
- $description_separator = esc_html( $this->get_separator( 'description' ) );
357
-
358
- $ishome = false;
359
  $is_settings_page = $this->is_seo_settings_page();
360
- $is_post_edit = $this->is_post_edit();
361
- $is_term_edit = $this->is_term_edit();
362
- $has_input = $is_settings_page || $is_post_edit || $is_term_edit;
 
363
 
364
- $page_on_front = $this->has_page_on_front();
365
 
366
  if ( $is_settings_page ) {
367
  // We're on our SEO settings pages.
368
  if ( $page_on_front ) {
369
  // Home is a page.
370
- $id = \get_option( 'page_on_front' );
371
  $inpost_title = $this->get_custom_field( '_genesis_title', $id );
372
  } else {
373
  // Home is a blog.
374
  $inpost_title = '';
375
  }
376
- $default_title = $inpost_title ?: $this->get_blogname();
377
  $title_additions = $this->get_home_page_tagline();
378
 
379
  $use_title_additions = (bool) $this->get_option( 'homepage_tagline' );
380
  } else {
381
  // We're somewhere within default WordPress pages.
382
- if ( $this->is_static_frontpage( $id ) ) {
383
- $default_title = $this->get_option( 'homepage_title' ) ?: $this->get_blogname();
 
 
 
 
 
 
 
384
  $title_location = $this->get_option( 'home_title_location' );
385
- $ishome = true;
 
386
 
387
  $use_title_additions = (bool) $this->get_option( 'homepage_tagline' );
388
- $title_additions = $this->get_home_page_tagline();
389
  } elseif ( $is_post_edit ) {
390
- $default_title = $this->get_raw_generated_title( [ 'id' => $id ] );
391
  $title_additions = $this->get_blogname();
392
- } elseif ( $is_term_edit ) {
393
- //* Category or Tag.
394
- if ( $this->get_current_taxonomy() && $id ) {
395
- $default_title = $this->get_generated_single_term_title( $this->fetch_the_term( $id ) );
396
- $title_additions = $this->get_blogname();
397
- }
398
  } else {
399
  //* We're in a special place.
400
  // Can't fetch title.
401
- $default_title = '';
402
  $title_additions = $this->get_blogname();
403
  }
404
  }
@@ -408,15 +474,15 @@ class Admin_Init extends Init {
408
  * Use $this->get_settings_capability() ?... might conflict with other nonces.
409
  * @augments tsfMedia 'upload_files'
410
  */
411
- // 'manage_options' => \current_user_can( 'manage_options' ) ? \wp_create_nonce( 'tsf-ajax-manage_options' ) : false,
412
- 'upload_files' => \current_user_can( 'upload_files' ) ? \wp_create_nonce( 'tsf-ajax-upload_files' ) : false,
413
- 'edit_posts' => \current_user_can( 'edit_posts' ) ? \wp_create_nonce( 'tsf-ajax-edit_posts' ) : false,
414
  ] );
415
 
416
- $term_name = '';
417
  $use_term_prefix = false;
418
  if ( $is_term_edit ) {
419
- $term_name = $this->get_tax_type_label( $this->get_current_taxonomy(), true );
420
  $use_term_prefix = $this->use_generated_archive_prefix();
421
  }
422
 
@@ -431,7 +497,7 @@ class Admin_Init extends Init {
431
  'twTitlePHLock' => (bool) $this->get_custom_field( '_twitter_title', $id ),
432
  'twDescriptionPHLock' => (bool) $this->get_custom_field( '_twitter_description', $id ),
433
  ];
434
- } elseif ( $ishome ) {
435
  $social_settings_locks = [
436
  'refTitleLock' => (bool) $this->get_option( 'homepage_title' ),
437
  'refDescriptionLock' => (bool) $this->get_option( 'homepage_description' ),
@@ -444,17 +510,38 @@ class Admin_Init extends Init {
444
  }
445
 
446
  $social_settings_placeholders = [];
 
447
  if ( $is_post_edit || $is_settings_page ) {
448
- $social_settings_placeholders = [
449
- 'ogDesc' => $this->get_generated_open_graph_description( [ 'id' => $id ] ),
450
- 'twDesc' => $this->get_generated_twitter_description( [ 'id' => $id ] ),
451
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  foreach ( $social_settings_placeholders as &$v ) {
453
- $v = html_entity_decode( $v, ENT_COMPAT, 'UTF-8' );
454
  }
455
  }
456
 
457
- $input_guidelines = [];
458
  $input_guidelines_i18n = [];
459
  if ( $has_input ) {
460
  $input_guidelines = $this->get_input_guidelines();
@@ -465,7 +552,7 @@ class Admin_Init extends Init {
465
  'nonces' => $this->get_js_nonces(),
466
  'states' => [
467
  'isRTL' => (bool) \is_rtl(),
468
- 'isHome' => $ishome,
469
  'hasInput' => $has_input,
470
  'counterType' => \absint( $this->get_user_option( 0, 'counter_type', 3 ) ),
471
  'useTagline' => $use_title_additions,
@@ -485,32 +572,32 @@ class Admin_Init extends Init {
485
  'i18n' => [
486
  'saveAlert' => \__( 'The changes you made will be lost if you navigate away from this page.', 'autodescription' ),
487
  'confirmReset' => \__( 'Are you sure you want to reset all SEO settings to their defaults?', 'autodescription' ),
 
488
  'privateTitle' => $has_input && $id ? trim( str_replace( '%s', '', \__( 'Private: %s', 'default' ) ) ) : '',
 
489
  'protectedTitle' => $has_input && $id ? trim( str_replace( '%s', '', \__( 'Protected: %s', 'default' ) ) ) : '',
490
  /* translators: Pixel counter. 1: width, 2: guideline */
491
  'pixelsUsed' => $has_input ? \__( '%1$d out of %2$d pixels are used.', 'autodescription' ) : '',
492
  'inputGuidelines' => $input_guidelines_i18n,
493
  ],
494
  'params' => [
495
- 'objectTitle' => $default_title,
496
- 'defaultTitle' => $default_title,
497
- 'titleAdditions' => $title_additions,
498
- 'blogDescription' => $this->s_title_raw( $this->get_blogdescription() ),
499
- 'termName' => $term_name,
500
- 'untitledTitle' => $this->get_static_untitled_title(),
501
- 'titleSeparator' => $title_separator,
502
- 'descriptionSeparator' => $description_separator,
503
- 'titleLocation' => $title_location,
504
- 'inputGuidelines' => $input_guidelines,
505
- 'socialPlaceholders' => $social_settings_placeholders,
506
  ],
507
  ];
508
 
509
- $flags = ENT_COMPAT;
510
  foreach ( [ 'i18n', 'params' ] as $key ) {
511
  foreach ( $l10n[ $key ] as &$v ) {
512
  if ( is_scalar( $v ) )
513
- $v = html_entity_decode( $v, $flags, 'UTF-8' );
514
  }
515
  }
516
 
@@ -741,7 +828,7 @@ class Admin_Init extends Init {
741
  * @since 2.9.3 : 1. Query arguments work again (regression 2.9.2).
742
  * 2. Now only accepts http and https protocols.
743
  *
744
- * @param string $page Menu slug.
745
  * @param array $query_args Optional. Associative array of query string arguments
746
  * (key => value). Default is an empty array.
747
  * @return null Return early if first argument is false.
@@ -876,8 +963,12 @@ class Admin_Init extends Init {
876
  public function _wp_ajax_crop_image() {
877
 
878
  $this->_check_tsf_ajax_referer( 'upload_files' );
879
- if ( ! \current_user_can( 'upload_files' ) || ! isset( $_POST['id'], $_POST['context'], $_POST['cropDetails'] ) )
 
 
 
880
  \wp_send_json_error();
 
881
 
882
  $attachment_id = \absint( $_POST['id'] ); // input var ok.
883
 
@@ -909,7 +1000,7 @@ class Admin_Init extends Init {
909
  $parent_url = \wp_get_attachment_url( $attachment_id );
910
  $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
911
 
912
- $size = @getimagesize( $cropped );
913
  $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
914
 
915
  $object = [
@@ -921,7 +1012,7 @@ class Admin_Init extends Init {
921
  ];
922
 
923
  $attachment_id = \wp_insert_attachment( $object, $cropped );
924
- $metadata = \wp_generate_attachment_metadata( $attachment_id, $cropped );
925
 
926
  /**
927
  * Filters the cropped image attachment metadata.
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
99
 
100
  if ( _has_run( __METHOD__ ) ) return;
101
 
102
+ //! PHP 5.4 compat: put in var.
 
 
103
  $scripts = $this->Scripts();
104
+ $scripts::register( $this->get_default_scripts() );
105
+
106
+ if ( $this->is_post_edit() ) {
107
+ $this->enqueue_media_scripts();
108
+ $this->enqueue_primaryterm_scripts();
109
+
110
+ if ( $this->is_gutenberg_page() ) {
111
+ $this->enqueue_gutenberg_compat_scripts();
112
+ }
113
+ } elseif ( $this->is_seo_settings_page() ) {
114
+ $this->enqueue_media_scripts();
115
+ \wp_enqueue_style( 'wp-color-picker' );
116
+ \wp_enqueue_script( 'wp-color-picker' );
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Returns a filterable sequential array of default scripts.
122
+ *
123
+ * @since 3.2.2
124
+ *
125
+ * @return array
126
+ */
127
+ public function get_default_scripts() {
128
  /**
129
  * @since 3.1.0
130
  * @param array $scripts The default CSS and JS loader settings.
131
  * @param string $scripts The \The_SEO_Framework\Builders\Scripts builder class name.
132
  */
133
+ return (array) \apply_filters_ref_array( 'the_seo_framework_scripts', [
134
  [
135
  [
136
  'id' => 'tsf',
184
  'border-bottom-color:{{$bg_accent}}',
185
  ],
186
  '.tsf-tooltip-text' => [
187
+ \is_rtl() ? 'direction:rtl' : '',
188
  ],
189
  ],
190
  ],
198
  'ver' => THE_SEO_FRAMEWORK_VERSION,
199
  ],
200
  ],
201
+ $this->Scripts(),
202
+ ] );
203
+ }
204
 
205
+ /**
206
+ * Enqueues Media Upload and Cropping scripts.
207
+ *
208
+ * @since 3.2.0
209
+ * @staticvar bool|null $registered Prevents duplicate calls.
210
+ */
211
+ public function enqueue_gutenberg_compat_scripts() {
212
+
213
+ if ( _has_run( __METHOD__ ) ) return;
214
+
215
+ $scripts = $this->Scripts();
216
+ $scripts::register( [
217
+ [
218
+ 'id' => 'tsf-gbc',
219
+ 'type' => 'js',
220
+ 'deps' => [ 'jquery', 'tsf', 'wp-editor', 'wp-data', 'lodash', 'react' ],
221
+ 'autoload' => true,
222
+ 'name' => 'tsf-gbc',
223
+ 'base' => THE_SEO_FRAMEWORK_DIR_URL . 'lib/js/',
224
+ 'ver' => THE_SEO_FRAMEWORK_VERSION,
225
+ 'l10n' => [
226
+ 'name' => 'tsfGBCL10n',
227
+ 'data' => [],
228
+ ],
229
+ ],
230
+ ] );
231
  }
232
 
233
  /**
234
  * Enqueues Media Upload and Cropping scripts.
235
  *
236
  * @since 3.1.0
 
237
  */
238
  public function enqueue_media_scripts() {
239
 
294
 
295
  if ( _has_run( __METHOD__ ) ) return;
296
 
297
+ $id = $this->get_the_real_admin_ID();
 
298
 
299
  $post_type = \get_post_type( $id );
300
  $_taxonomies = $post_type ? $this->get_hierarchical_taxonomies_as( 'objects', $post_type ) : [];
301
+ $taxonomies = [];
302
 
303
+ $gutenberg = $this->is_gutenberg_page();
304
 
305
  foreach ( $_taxonomies as $_t ) {
306
+ $singular_name = $this->get_tax_type_label( $_t->name );
307
+
308
  $taxonomies[ $_t->name ] = [
309
  'name' => $_t->name,
 
 
 
 
 
 
 
310
  'primary' => $this->get_primary_term_id( $id, $_t->name ) ?: 0,
311
+ ] + (
312
+ $gutenberg ? [
313
+ 'i18n' => [
314
+ /* translators: %s = term name */
315
+ 'selectPrimary' => sprintf( \esc_html__( 'Select Primary %s', 'autodescription' ), $singular_name ),
316
+ ],
317
+ ] : [
318
+ 'i18n' => [
319
+ /* translators: %s = term name */
320
+ 'makePrimary' => sprintf( \esc_html__( 'Make primary %s', 'autodescription' ), strtolower( $singular_name ) ),
321
+ /* translators: %s = term name */
322
+ 'primary' => sprintf( \esc_html__( 'Primary %s', 'autodescription' ), strtolower( $singular_name ) ),
323
+ 'name' => strtolower( $singular_name ),
324
+ ],
325
+ ]
326
+ );
327
  }
328
 
329
  $inline_css = [];
339
  ];
340
  }
341
 
342
+ if ( $gutenberg ) {
343
+ $vars = [
344
+ 'id' => 'tsf-pt-gb',
345
+ 'name' => 'pt-gb',
346
+ ];
347
+ $deps = [ 'jquery', 'tsf', 'wp-hooks', 'wp-element', 'wp-components', 'wp-url', 'wp-api-fetch', 'lodash', 'react' ];
348
+ } else {
349
+ $vars = [
350
+ 'id' => 'tsf-pt',
351
+ 'name' => 'pt',
352
+ ];
353
+ $deps = [ 'jquery', 'tsf', 'tsf-tt' ];
354
+ }
355
+
356
  //! PHP 5.4 compat: put in var.
357
  $scripts = $this->Scripts();
358
  $scripts::register( [
359
  [
360
+ 'id' => $vars['id'],
361
  'type' => 'js',
362
+ 'deps' => $deps,
363
  'autoload' => true,
364
+ 'name' => $vars['name'],
365
  'base' => THE_SEO_FRAMEWORK_DIR_URL . 'lib/js/',
366
  'ver' => THE_SEO_FRAMEWORK_VERSION,
367
  'l10n' => [
402
  * 4 : Added dynamic output control.
403
  * @since 2.9.0 Added boolean $returnValue['states']['isSettingsPage']
404
  * @since 3.0.4 `descPixelGuideline` has been increased from "920 and 820" to "1820 and 1720" respectively.
405
+ * @since 3.2.2 Added string $returnValue['nonces']['manage_options']
406
  *
407
  * @return array $strings The l10n strings.
408
  */
409
  protected function get_javascript_l10n() {
410
 
411
  $id = $this->get_the_real_ID();
412
+
413
+ $default_title = '';
414
  $title_additions = '';
415
 
416
  $use_title_additions = $this->use_title_branding();
417
+ $home_tagline = $this->get_option( 'homepage_title_tagline' );
418
+ $title_location = $this->get_option( 'title_location' );
419
+ $title_separator = \esc_html( $this->get_separator( 'title' ) );
420
 
421
+ $is_home = false;
 
 
 
422
  $is_settings_page = $this->is_seo_settings_page();
423
+ $page_on_front = $this->has_page_on_front();
424
+ $is_post_edit = $this->is_post_edit();
425
+ $is_term_edit = $this->is_term_edit();
426
+ $has_input = $is_settings_page || $is_post_edit || $is_term_edit;
427
 
428
+ $_decode_flags = ENT_QUOTES | ENT_COMPAT;
429
 
430
  if ( $is_settings_page ) {
431
  // We're on our SEO settings pages.
432
  if ( $page_on_front ) {
433
  // Home is a page.
434
+ $id = (int) \get_option( 'page_on_front' );
435
  $inpost_title = $this->get_custom_field( '_genesis_title', $id );
436
  } else {
437
  // Home is a blog.
438
  $inpost_title = '';
439
  }
440
+ $default_title = $inpost_title ?: $this->get_blogname();
441
  $title_additions = $this->get_home_page_tagline();
442
 
443
  $use_title_additions = (bool) $this->get_option( 'homepage_tagline' );
444
  } else {
445
  // We're somewhere within default WordPress pages.
446
+ if ( $is_term_edit ) {
447
+ //* Category or Tag.
448
+ if ( $this->get_current_taxonomy() && $id ) {
449
+ // DEBUG: Use get_generated_archive_title() instead...? use_generated_archive_prefix() is in the way.
450
+ $default_title = $this->get_generated_single_term_title( $this->fetch_the_term( $id ) );
451
+ $title_additions = $this->get_blogname();
452
+ }
453
+ } elseif ( $this->is_static_frontpage( $id ) ) { // implies $is_post_edit or $is_settings_page
454
+ $default_title = $this->get_option( 'homepage_title' ) ?: $this->get_blogname();
455
  $title_location = $this->get_option( 'home_title_location' );
456
+
457
+ $is_home = true;
458
 
459
  $use_title_additions = (bool) $this->get_option( 'homepage_tagline' );
460
+ $title_additions = $this->get_home_page_tagline();
461
  } elseif ( $is_post_edit ) {
462
+ $default_title = $this->get_raw_generated_title( [ 'id' => $id ] );
463
  $title_additions = $this->get_blogname();
 
 
 
 
 
 
464
  } else {
465
  //* We're in a special place.
466
  // Can't fetch title.
467
+ $default_title = '';
468
  $title_additions = $this->get_blogname();
469
  }
470
  }
474
  * Use $this->get_settings_capability() ?... might conflict with other nonces.
475
  * @augments tsfMedia 'upload_files'
476
  */
477
+ 'manage_options' => \current_user_can( 'manage_options' ) ? \wp_create_nonce( 'tsf-ajax-manage_options' ) : false,
478
+ 'upload_files' => \current_user_can( 'upload_files' ) ? \wp_create_nonce( 'tsf-ajax-upload_files' ) : false,
479
+ 'edit_posts' => \current_user_can( 'edit_posts' ) ? \wp_create_nonce( 'tsf-ajax-edit_posts' ) : false,
480
  ] );
481
 
482
+ $term_name = '';
483
  $use_term_prefix = false;
484
  if ( $is_term_edit ) {
485
+ $term_name = $this->get_tax_type_label( $this->get_current_taxonomy(), true );
486
  $use_term_prefix = $this->use_generated_archive_prefix();
487
  }
488
 
497
  'twTitlePHLock' => (bool) $this->get_custom_field( '_twitter_title', $id ),
498
  'twDescriptionPHLock' => (bool) $this->get_custom_field( '_twitter_description', $id ),
499
  ];
500
+ } elseif ( $is_home ) {
501
  $social_settings_locks = [
502
  'refTitleLock' => (bool) $this->get_option( 'homepage_title' ),
503
  'refDescriptionLock' => (bool) $this->get_option( 'homepage_description' ),
510
  }
511
 
512
  $social_settings_placeholders = [];
513
+
514
  if ( $is_post_edit || $is_settings_page ) {
515
+ if ( $is_settings_page ) {
516
+ if ( $page_on_front ) {
517
+ $social_settings_placeholders = [
518
+ 'ogDesc' => $this->get_custom_field( '_genesis_description', $id ) ?: $this->get_generated_open_graph_description( [ 'id' => $id ] ),
519
+ 'twDesc' => $this->get_custom_field( '_genesis_description', $id ) ?: $this->get_generated_twitter_description( [ 'id' => $id ] ),
520
+ ];
521
+ } else {
522
+ $social_settings_placeholders = [
523
+ 'ogDesc' => $this->get_generated_open_graph_description( [ 'id' => $id ] ),
524
+ 'twDesc' => $this->get_generated_twitter_description( [ 'id' => $id ] ),
525
+ ];
526
+ }
527
+ } elseif ( $is_home ) {
528
+ $social_settings_placeholders = [
529
+ 'ogDesc' => $this->get_option( 'homepage_description' ) ?: $this->get_generated_open_graph_description( [ 'id' => $id ] ),
530
+ 'twDesc' => $this->get_option( 'homepage_description' ) ?: $this->get_generated_twitter_description( [ 'id' => $id ] ),
531
+ ];
532
+ } else {
533
+ $social_settings_placeholders = [
534
+ 'ogDesc' => $this->get_generated_open_graph_description( [ 'id' => $id ] ),
535
+ 'twDesc' => $this->get_generated_twitter_description( [ 'id' => $id ] ),
536
+ ];
537
+ }
538
+
539
  foreach ( $social_settings_placeholders as &$v ) {
540
+ $v = html_entity_decode( $v, $_decode_flags, 'UTF-8' );
541
  }
542
  }
543
 
544
+ $input_guidelines = [];
545
  $input_guidelines_i18n = [];
546
  if ( $has_input ) {
547
  $input_guidelines = $this->get_input_guidelines();
552
  'nonces' => $this->get_js_nonces(),
553
  'states' => [
554
  'isRTL' => (bool) \is_rtl(),
555
+ 'isHome' => $is_home,
556
  'hasInput' => $has_input,
557
  'counterType' => \absint( $this->get_user_option( 0, 'counter_type', 3 ) ),
558
  'useTagline' => $use_title_additions,
572
  'i18n' => [
573
  'saveAlert' => \__( 'The changes you made will be lost if you navigate away from this page.', 'autodescription' ),
574
  'confirmReset' => \__( 'Are you sure you want to reset all SEO settings to their defaults?', 'autodescription' ),
575
+ // phpcs:ignore -- WordPress doesn't have a comment, either.
576
  'privateTitle' => $has_input && $id ? trim( str_replace( '%s', '', \__( 'Private: %s', 'default' ) ) ) : '',
577
+ // phpcs:ignore -- WordPress doesn't have a comment, either.
578
  'protectedTitle' => $has_input && $id ? trim( str_replace( '%s', '', \__( 'Protected: %s', 'default' ) ) ) : '',
579
  /* translators: Pixel counter. 1: width, 2: guideline */
580
  'pixelsUsed' => $has_input ? \__( '%1$d out of %2$d pixels are used.', 'autodescription' ) : '',
581
  'inputGuidelines' => $input_guidelines_i18n,
582
  ],
583
  'params' => [
584
+ 'objectTitle' => $this->s_title_raw( $default_title ),
585
+ 'defaultTitle' => $this->s_title_raw( $default_title ),
586
+ 'titleAdditions' => $this->s_title_raw( $title_additions ),
587
+ 'blogDescription' => $this->s_title_raw( $this->get_blogdescription() ),
588
+ 'termName' => $this->s_title_raw( $term_name ),
589
+ 'untitledTitle' => $this->s_title_raw( $this->get_static_untitled_title() ),
590
+ 'titleSeparator' => $title_separator,
591
+ 'titleLocation' => $title_location,
592
+ 'inputGuidelines' => $input_guidelines,
593
+ 'socialPlaceholders' => $social_settings_placeholders,
 
594
  ],
595
  ];
596
 
 
597
  foreach ( [ 'i18n', 'params' ] as $key ) {
598
  foreach ( $l10n[ $key ] as &$v ) {
599
  if ( is_scalar( $v ) )
600
+ $v = html_entity_decode( $v, $_decode_flags, 'UTF-8' );
601
  }
602
  }
603
 
828
  * @since 2.9.3 : 1. Query arguments work again (regression 2.9.2).
829
  * 2. Now only accepts http and https protocols.
830
  *
831
+ * @param string $page Menu slug. This slug must exist, or the redirect will loop back to the current page.
832
  * @param array $query_args Optional. Associative array of query string arguments
833
  * (key => value). Default is an empty array.
834
  * @return null Return early if first argument is false.
963
  public function _wp_ajax_crop_image() {
964
 
965
  $this->_check_tsf_ajax_referer( 'upload_files' );
966
+ if (
967
+ ! \current_user_can( 'upload_files' ) // precision alignment ok.
968
+ || ! isset( $_POST['id'], $_POST['context'], $_POST['cropDetails'] ) // input var ok.
969
+ ) {
970
  \wp_send_json_error();
971
+ }
972
 
973
  $attachment_id = \absint( $_POST['id'] ); // input var ok.
974
 
1000
  $parent_url = \wp_get_attachment_url( $attachment_id );
1001
  $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
1002
 
1003
+ $size = @getimagesize( $cropped ); // phpcs:ignore -- Feature might not be enabled.
1004
  $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
1005
 
1006
  $object = [
1012
  ];
1013
 
1014
  $attachment_id = \wp_insert_attachment( $object, $cropped );
1015
+ $metadata = \wp_generate_attachment_metadata( $attachment_id, $cropped );
1016
 
1017
  /**
1018
  * Filters the cropped image attachment metadata.
inc/classes/admin-pages.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -335,7 +335,7 @@ class Admin_Pages extends Inpost {
335
  if ( $this->get_static_cache( 'check_seo_plugin_conflicts' ) && \current_user_can( 'activate_plugins' ) ) {
336
  $this->detect_seo_plugins()
337
  and $this->do_dismissible_notice(
338
- __( 'Multiple SEO tools have been detected. You should only use one.', 'autodescription' ),
339
  'warning'
340
  );
341
  $this->update_static_cache( 'check_seo_plugin_conflicts', 0 );
@@ -356,7 +356,7 @@ class Admin_Pages extends Inpost {
356
  */
357
  protected function do_settings_page_notices() {
358
 
359
- $get = empty( $_GET ) ? null : $_GET;
360
 
361
  if ( null === $get )
362
  return;
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
335
  if ( $this->get_static_cache( 'check_seo_plugin_conflicts' ) && \current_user_can( 'activate_plugins' ) ) {
336
  $this->detect_seo_plugins()
337
  and $this->do_dismissible_notice(
338
+ \__( 'Multiple SEO tools have been detected. You should only use one.', 'autodescription' ),
339
  'warning'
340
  );
341
  $this->update_static_cache( 'check_seo_plugin_conflicts', 0 );
356
  */
357
  protected function do_settings_page_notices() {
358
 
359
+ $get = empty( $_GET ) ? null : $_GET; // CSRF, input var OK.
360
 
361
  if ( null === $get )
362
  return;
inc/classes/builders/scripts.class.php CHANGED
@@ -7,7 +7,7 @@ namespace The_SEO_Framework\Builders;
7
 
8
  /**
9
  * The SEO Framework plugin
10
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
@@ -82,9 +82,11 @@ final class Scripts {
82
 
83
  /**
84
  * @since 3.1.0
 
 
85
  * @param string|null $include_secret The inclusion secret generated on tab load.
86
  */
87
- public static $include_secret;
88
 
89
  /**
90
  * Prepares the class and loads constructor.
@@ -103,6 +105,7 @@ final class Scripts {
103
  *
104
  * @since 3.1.0
105
  * @access private
 
106
  */
107
  public function __construct() {
108
 
@@ -115,6 +118,20 @@ final class Scripts {
115
  \add_action( 'admin_footer', [ $this, '_output_templates' ], 999 );
116
  }
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  /**
119
  * Returns the script status of $id for $type.
120
  *
@@ -131,7 +148,7 @@ final class Scripts {
131
  }
132
 
133
  /**
134
- * Enqueues registered scripts, styles, and templates.
135
  *
136
  * @since 3.1.0
137
  */
@@ -141,11 +158,14 @@ final class Scripts {
141
  }
142
 
143
  /**
144
- * Registers script to be enqueued.
 
 
145
  *
146
  * @since 3.1.0
147
  * @uses static::$scripts
148
- * @see $this->enqueue_scripts()
 
149
  *
150
  * @NOTE If the script is associative, it'll be registered as-is.
151
  * If the script is sequential, it'll be iterated over, and then registered.
@@ -181,62 +201,162 @@ final class Scripts {
181
  }
182
 
183
  /**
184
- * Prepares scripts for output on post edit screens.
185
  *
186
- * @since 3.1.0
187
- * @access private
188
  *
189
- * @param string $hook The current admin hook.
 
190
  */
191
- public function _prepare_admin_scripts( $hook = '' ) {
192
- $this->enqueue_scripts();
 
 
 
 
 
 
 
 
193
  }
194
 
195
  /**
196
- * Enqueues scripts, l10n and templates.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  *
198
  * @since 3.1.0
199
- * @uses static::$scripts
200
- * @uses $this->generate_file_url()
201
- * @uses $this->register_template()
 
 
 
 
 
202
  */
203
- private function enqueue_scripts() {
 
 
204
 
 
 
 
 
 
 
 
 
205
  //= Register them first to accomodate for dependencies.
206
  foreach ( static::$scripts as $s ) {
207
  if ( static::get_status_of( $s['id'], $s['type'] ) & static::REGISTERED ) continue;
208
-
209
- switch ( $s['type'] ) {
210
- case 'css' :
211
- \wp_register_style( $s['id'], $this->generate_file_url( $s, 'css' ), $s['deps'], $s['ver'], 'all' );
212
- isset( $s['inline'] )
213
- and \wp_add_inline_style( $s['id'], $this->get_inline_css( $s['inline'] ) );
214
- break;
215
- case 'js' :
216
- \wp_register_script( $s['id'], $this->generate_file_url( $s, 'js' ), $s['deps'], $s['ver'], true );
217
- isset( $s['l10n'] )
218
- and \wp_localize_script( $s['id'], $s['l10n']['name'], $s['l10n']['data'] );
219
- isset( $s['tmpl'] )
220
- and $this->register_template( $s['id'], $s['tmpl'] );
221
- break;
222
- }
223
- static::$queue[ $s['type'] ][ $s['id'] ] = static::REGISTERED;
224
  }
 
225
 
 
 
 
 
 
 
 
 
226
  foreach ( static::$scripts as $s ) {
227
- if ( static::get_status_of( $s['id'], $s['type'] ) & static::LOADED ) continue;
228
-
229
  if ( $s['autoload'] ) {
230
- switch ( $s['type'] ) {
231
- case 'css' :
232
- \wp_enqueue_style( $s['id'] );
233
- break;
234
- case 'js' :
235
- \wp_enqueue_script( $s['id'] );
236
- break;
237
- }
238
  }
239
- static::$queue[ $s['type'] ][ $s['id'] ] |= static::LOADED;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  }
241
  }
242
 
@@ -310,7 +430,7 @@ final class Scripts {
310
  $tsf = \the_seo_framework();
311
 
312
  if (
313
- ! isset( $_colors[ $_scheme ]->colors )
314
  || ! is_array( $_colors[ $_scheme ]->colors )
315
  || count( $_colors[ $_scheme ]->colors ) < 4
316
  ) {
@@ -385,14 +505,21 @@ final class Scripts {
385
  * The loop will only run when templates are registered.
386
  *
387
  * @since 3.1.0
388
- * @see $this->enqueue_scripts()
 
 
 
389
  * @access private
 
390
  */
391
  public function _output_templates() {
392
- foreach ( static::$templates as $id => $templates )
393
- if ( \wp_script_is( $id, 'enqueued' ) ) // This list retains scripts after they're outputted.
394
  foreach ( $templates as $t )
395
  $this->output_view( $t[0], $t[1] );
 
 
 
396
  }
397
 
398
  /**
@@ -419,21 +546,6 @@ final class Scripts {
419
  include $file;
420
  static::$include_secret = null;
421
  }
422
-
423
- /**
424
- * Verifies view inclusion secret.
425
- *
426
- * @since 3.1.0
427
- * @see static::output_view()
428
- * @uses static::$include_secret
429
- * @internal
430
- *
431
- * @param string $secret The passed secret.
432
- * @return bool True on success, false on failure.
433
- */
434
- public static function verify( $secret ) {
435
- return $secret && static::$include_secret === $secret;
436
- }
437
  }
438
 
439
  $_load_scripts_class();
7
 
8
  /**
9
  * The SEO Framework plugin
10
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
  *
12
  * This program is free software: you can redistribute it and/or modify
13
  * it under the terms of the GNU General Public License version 3 as published
82
 
83
  /**
84
  * @since 3.1.0
85
+ * @since 3.2.2 Is now a private variable.
86
+ * @see static::verify()
87
  * @param string|null $include_secret The inclusion secret generated on tab load.
88
  */
89
+ private static $include_secret;
90
 
91
  /**
92
  * Prepares the class and loads constructor.
105
  *
106
  * @since 3.1.0
107
  * @access private
108
+ * @internal
109
  */
110
  public function __construct() {
111
 
118
  \add_action( 'admin_footer', [ $this, '_output_templates' ], 999 );
119
  }
120
 
121
+ /**
122
+ * Prepares scripts for output on post edit screens.
123
+ *
124
+ * @since 3.1.0
125
+ * @access private
126
+ * @internal
127
+ *
128
+ * @param string $hook The current admin hook.
129
+ */
130
+ public function _prepare_admin_scripts( $hook = '' ) {
131
+ $this->forward_known_scripts();
132
+ $this->autoload_known_scripts();
133
+ }
134
+
135
  /**
136
  * Returns the script status of $id for $type.
137
  *
148
  }
149
 
150
  /**
151
+ * Enqueues all known registered scripts, styles, and templates.
152
  *
153
  * @since 3.1.0
154
  */
158
  }
159
 
160
  /**
161
+ * Registers script to be enqueued. Can register multiple scripts at once.
162
+ *
163
+ * A better name would've been "collect"...
164
  *
165
  * @since 3.1.0
166
  * @uses static::$scripts
167
+ * @see $this->forward_known_scripts()
168
+ * @see $this->autoload_known_scripts()
169
  *
170
  * @NOTE If the script is associative, it'll be registered as-is.
171
  * If the script is sequential, it'll be iterated over, and then registered.
201
  }
202
 
203
  /**
204
+ * Registers and enqueues known scripts.
205
  *
206
+ * @since 3.2.2
 
207
  *
208
+ * @param string $id The script ID.
209
+ * @param string $type The script type.
210
  */
211
+ public static function forward_known_script( $id, $type ) {
212
+ if ( ! ( static::get_status_of( $id, $type ) & static::REGISTERED ) ) {
213
+ foreach ( static::$scripts as $s ) {
214
+ if ( $s['id'] === $id ) {
215
+ if ( $s['type'] === $type ) {
216
+ static::forward_script( $s );
217
+ }
218
+ }
219
+ }
220
+ }
221
  }
222
 
223
  /**
224
+ * Registers and enqueues known scripts.
225
+ *
226
+ * @since 3.2.2
227
+ * @uses static::forward_known_script();
228
+ *
229
+ * @param string $id The script ID.
230
+ * @param string $type The script type.
231
+ */
232
+ public static function enqueue_known_script( $id, $type ) {
233
+
234
+ static::forward_known_script( $id, $type );
235
+
236
+ if ( static::get_status_of( $id, $type ) & static::REGISTERED ) {
237
+ if ( ! ( static::get_status_of( $id, $type ) & static::LOADED ) ) {
238
+ static::load_script( $id, $type );
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Verifies template view inclusion secret.
245
  *
246
  * @since 3.1.0
247
+ * @see static::output_view()
248
+ * @uses static::$include_secret
249
+ *
250
+ * @example template file header:
251
+ * `defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and The_SEO_Framework\Builders\Scripts::verify( $_secret ) or die;`
252
+ *
253
+ * @param string $secret The passed secret.
254
+ * @return bool True on success, false on failure.
255
  */
256
+ public static function verify( $secret ) {
257
+ return $secret && static::$include_secret === $secret;
258
+ }
259
 
260
+ /**
261
+ * Forwards known scripts to WordPress' script handler. Also prepares l10n and templates.
262
+ *
263
+ * @since 3.2.2
264
+ * @uses static::$scripts
265
+ * @uses static::egister_script()
266
+ */
267
+ private function forward_known_scripts() {
268
  //= Register them first to accomodate for dependencies.
269
  foreach ( static::$scripts as $s ) {
270
  if ( static::get_status_of( $s['id'], $s['type'] ) & static::REGISTERED ) continue;
271
+ static::forward_script( $s );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  }
273
+ }
274
 
275
+ /**
276
+ * Enqueues known scripts, and invokes the l10n and templates.
277
+ *
278
+ * @since 3.2.2
279
+ * @uses static::$scripts
280
+ * @uses static::load_script()
281
+ */
282
+ private function autoload_known_scripts() {
283
  foreach ( static::$scripts as $s ) {
 
 
284
  if ( $s['autoload'] ) {
285
+ if ( static::get_status_of( $s['id'], $s['type'] ) & static::LOADED ) continue;
286
+ static::load_script( $s['id'], $s['type'] );
 
 
 
 
 
 
287
  }
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Enqueues scripts in WordPress' script handler. Also prepares l10n and templates.
293
+ *
294
+ * @since 3.2.2
295
+ * @see $this->forward_known_scripts();
296
+ * @see static::enqueue_known_script();
297
+ * @augments static::$queue
298
+ * @uses $this->generate_file_url()
299
+ * @uses $this->get_inline_css()
300
+ * @uses $this->register_template()
301
+ *
302
+ * @param array $s The script.
303
+ */
304
+ private static function forward_script( array $s ) {
305
+
306
+ $instance = static::$instance;
307
+ $registered = false;
308
+
309
+ switch ( $s['type'] ) {
310
+ case 'css':
311
+ \wp_register_style( $s['id'], $instance->generate_file_url( $s, 'css' ), $s['deps'], $s['ver'], 'all' );
312
+ isset( $s['inline'] )
313
+ and \wp_add_inline_style( $s['id'], $instance->get_inline_css( $s['inline'] ) );
314
+ $registered = true;
315
+ break;
316
+ case 'js':
317
+ \wp_register_script( $s['id'], $instance->generate_file_url( $s, 'js' ), $s['deps'], $s['ver'], true );
318
+ isset( $s['l10n'] )
319
+ and \wp_localize_script( $s['id'], $s['l10n']['name'], $s['l10n']['data'] );
320
+ isset( $s['tmpl'] )
321
+ and $instance->register_template( $s['id'], $s['tmpl'] );
322
+ $registered = true;
323
+ break;
324
+ }
325
+ if ( $registered ) {
326
+ isset( static::$queue[ $s['type'] ][ $s['id'] ] )
327
+ and static::$queue[ $s['type'] ][ $s['id'] ] |= static::REGISTERED
328
+ or static::$queue[ $s['type'] ][ $s['id'] ] = static::REGISTERED; // Precision alignment ok.
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Loads known registered script.
334
+ *
335
+ * @since 3.2.2
336
+ *
337
+ * @param string $id The script ID.
338
+ * @param string $type The script type.
339
+ */
340
+ private static function load_script( $id, $type ) {
341
+
342
+ if ( ! ( static::get_status_of( $id, $type ) & static::REGISTERED ) ) return;
343
+
344
+ $loaded = false;
345
+
346
+ switch ( $type ) {
347
+ case 'css':
348
+ \wp_enqueue_style( $id );
349
+ $loaded = true;
350
+ break;
351
+ case 'js':
352
+ \wp_enqueue_script( $id );
353
+ $loaded = true;
354
+ break;
355
+ }
356
+ if ( $loaded ) {
357
+ isset( static::$queue[ $type ][ $id ] )
358
+ and static::$queue[ $type ][ $id ] |= static::LOADED
359
+ or static::$queue[ $type ][ $id ] = static::LOADED; // Precision alignment ok.
360
  }
361
  }
362
 
430
  $tsf = \the_seo_framework();
431
 
432
  if (
433
+ ! isset( $_colors[ $_scheme ]->colors ) // Precision alignment OK.
434
  || ! is_array( $_colors[ $_scheme ]->colors )
435
  || count( $_colors[ $_scheme ]->colors ) < 4
436
  ) {
505
  * The loop will only run when templates are registered.
506
  *
507
  * @since 3.1.0
508
+ * @since 3.2.2 Now clears outputted templates, so to prevent duplications.
509
+ * @see $this->forward_known_scripts()
510
+ * @see $this->register_template()
511
+ * @see $this->autoload_scripts()
512
  * @access private
513
+ * @internal
514
  */
515
  public function _output_templates() {
516
+ foreach ( static::$templates as $id => $templates ) {
517
+ if ( \wp_script_is( $id, 'enqueued' ) ) { // This list retains scripts after they're outputted.
518
  foreach ( $templates as $t )
519
  $this->output_view( $t[0], $t[1] );
520
+ unset( static::$templates[ $id ] );
521
+ }
522
+ }
523
  }
524
 
525
  /**
546
  include $file;
547
  static::$include_secret = null;
548
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  }
550
 
551
  $_load_scripts_class();
inc/classes/cache.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -215,7 +215,7 @@ class Cache extends Sitemaps {
215
  $success = false;
216
 
217
  switch ( $type ) :
218
- case 'front' :
219
  $front_id = $this->get_the_front_page_ID();
220
 
221
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $front_id, '', 'frontpage' ) );
@@ -223,14 +223,14 @@ class Cache extends Sitemaps {
223
  $success = true;
224
  break;
225
 
226
- case 'post' :
227
  $post_type = \get_post_type( $id );
228
 
229
  if ( $post_type ) {
230
  switch ( $post_type ) {
231
- case 'page' :
232
- case 'post' :
233
- case 'attachment' :
234
  break;
235
 
236
  default:
@@ -246,35 +246,35 @@ class Cache extends Sitemaps {
246
  break;
247
 
248
  //* Careful, this can only run on archive pages. For now.
249
- case 'term' :
250
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $id, $args['term'], 'term' ) );
251
  $this->delete_ld_json_transient( $id, $args['term'], 'term' );
252
  $success = true;
253
  break;
254
 
255
- case 'author' :
256
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $id, 'author', 'author' ) );
257
  $this->delete_ld_json_transient( $id, 'author', 'author' );
258
  $success = true;
259
  break;
260
 
261
- case 'sitemap' :
262
  $success = $this->delete_sitemap_transient();
263
  break;
264
 
265
- case 'robots' :
266
  $success = $this->object_cache_delete( $this->get_robots_txt_cache_key() );
267
  break;
268
 
269
- case 'excluded_post_ids' :
270
  $success = $this->delete_excluded_post_ids_transient();
271
  break;
272
 
273
- case 'object' :
274
  $success = \wp_cache_flush();
275
  break;
276
 
277
- case 'detection' :
278
  break;
279
 
280
  /**
@@ -284,8 +284,9 @@ class Cache extends Sitemaps {
284
  * @NOTE Other caching plugins can override these groups. Therefore this
285
  * does NOT work.
286
  * @TODO make this work.
 
287
  */
288
- case 'objectflush' :
289
  //* @NOTE false can't pass.
290
  if ( false && $this->use_object_cache ) {
291
  if ( isset( $GLOBALS['wp_object_cache']->cache['the_seo_framework'] ) ) {
@@ -309,7 +310,7 @@ class Cache extends Sitemaps {
309
  * @param array $args Additional arguments. They can overwrite $type and $id.
310
  * @param bool $success Whether the action cleared.
311
  */
312
- do_action( "the_seo_framework_delete_cache_{$type}", $type, $id, $args, $success );
313
 
314
  return $success;
315
  }
@@ -492,7 +493,7 @@ class Cache extends Sitemaps {
492
  /**
493
  * Change key based on options.
494
  */
495
- $options = $this->enable_ld_json_breadcrumbs() ? '1' : '0';
496
  $options .= $this->enable_ld_json_searchbox() ? '1' : '0';
497
 
498
  return 'tsf_' . $revision . '_' . $options . '_ldjs_' . $cache_key;
@@ -636,15 +637,15 @@ class Cache extends Sitemaps {
636
  $post_type = \get_post_type( $page_id );
637
 
638
  switch ( $post_type ) :
639
- case 'page' :
640
  $the_id = 'page_' . $page_id;
641
  break;
642
 
643
- case 'post' :
644
  $the_id = 'post_' . $page_id;
645
  break;
646
 
647
- case 'attachment' :
648
  $the_id = 'attach_' . $page_id;
649
  break;
650
 
@@ -711,25 +712,25 @@ class Cache extends Sitemaps {
711
  public function generate_cache_key_by_type( $page_id, $taxonomy = '', $type = '' ) {
712
 
713
  switch ( $type ) :
714
- case 'author' :
715
  return $this->add_cache_key_suffix( 'author_' . $page_id );
716
  break;
717
- case 'frontpage' :
718
  return $this->add_cache_key_suffix( $this->generate_front_page_cache_key() );
719
  break;
720
- case 'page' :
721
  return $this->add_cache_key_suffix( 'page_' . $page_id );
722
  break;
723
- case 'post' :
724
  return $this->add_cache_key_suffix( 'post_' . $page_id );
725
  break;
726
- case 'attachment' :
727
  return $this->add_cache_key_suffix( 'attach_' . $page_id );
728
  break;
729
- case 'singular' :
730
  return $this->add_cache_key_suffix( 'singular_' . $page_id );
731
  break;
732
- case 'term' :
733
  return $this->add_cache_key_suffix( $this->generate_taxonomical_cache_key( $page_id, $taxonomy ) );
734
  break;
735
  default:
@@ -757,7 +758,7 @@ class Cache extends Sitemaps {
757
  static $locale = null;
758
 
759
  if ( is_null( $locale ) )
760
- $locale = strtolower( get_locale() );
761
 
762
  return $key . '_' . $GLOBALS['blog_id'] . '_' . $locale;
763
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
215
  $success = false;
216
 
217
  switch ( $type ) :
218
+ case 'front':
219
  $front_id = $this->get_the_front_page_ID();
220
 
221
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $front_id, '', 'frontpage' ) );
223
  $success = true;
224
  break;
225
 
226
+ case 'post':
227
  $post_type = \get_post_type( $id );
228
 
229
  if ( $post_type ) {
230
  switch ( $post_type ) {
231
+ case 'page':
232
+ case 'post':
233
+ case 'attachment':
234
  break;
235
 
236
  default:
246
  break;
247
 
248
  //* Careful, this can only run on archive pages. For now.
249
+ case 'term':
250
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $id, $args['term'], 'term' ) );
251
  $this->delete_ld_json_transient( $id, $args['term'], 'term' );
252
  $success = true;
253
  break;
254
 
255
+ case 'author':
256
  $this->object_cache_delete( $this->get_meta_output_cache_key_by_type( $id, 'author', 'author' ) );
257
  $this->delete_ld_json_transient( $id, 'author', 'author' );
258
  $success = true;
259
  break;
260
 
261
+ case 'sitemap':
262
  $success = $this->delete_sitemap_transient();
263
  break;
264
 
265
+ case 'robots':
266
  $success = $this->object_cache_delete( $this->get_robots_txt_cache_key() );
267
  break;
268
 
269
+ case 'excluded_post_ids':
270
  $success = $this->delete_excluded_post_ids_transient();
271
  break;
272
 
273
+ case 'object':
274
  $success = \wp_cache_flush();
275
  break;
276
 
277
+ case 'detection':
278
  break;
279
 
280
  /**
284
  * @NOTE Other caching plugins can override these groups. Therefore this
285
  * does NOT work.
286
  * @TODO make this work.
287
+ * @see 'object' switch-index.
288
  */
289
+ case 'objectflush':
290
  //* @NOTE false can't pass.
291
  if ( false && $this->use_object_cache ) {
292
  if ( isset( $GLOBALS['wp_object_cache']->cache['the_seo_framework'] ) ) {
310
  * @param array $args Additional arguments. They can overwrite $type and $id.
311
  * @param bool $success Whether the action cleared.
312
  */
313
+ \do_action( "the_seo_framework_delete_cache_{$type}", $type, $id, $args, $success );
314
 
315
  return $success;
316
  }
493
  /**
494
  * Change key based on options.
495
  */
496
+ $options = $this->enable_ld_json_breadcrumbs() ? '1' : '0';
497
  $options .= $this->enable_ld_json_searchbox() ? '1' : '0';
498
 
499
  return 'tsf_' . $revision . '_' . $options . '_ldjs_' . $cache_key;
637
  $post_type = \get_post_type( $page_id );
638
 
639
  switch ( $post_type ) :
640
+ case 'page':
641
  $the_id = 'page_' . $page_id;
642
  break;
643
 
644
+ case 'post':
645
  $the_id = 'post_' . $page_id;
646
  break;
647
 
648
+ case 'attachment':
649
  $the_id = 'attach_' . $page_id;
650
  break;
651
 
712
  public function generate_cache_key_by_type( $page_id, $taxonomy = '', $type = '' ) {
713
 
714
  switch ( $type ) :
715
+ case 'author':
716
  return $this->add_cache_key_suffix( 'author_' . $page_id );
717
  break;
718
+ case 'frontpage':
719
  return $this->add_cache_key_suffix( $this->generate_front_page_cache_key() );
720
  break;
721
+ case 'page':
722
  return $this->add_cache_key_suffix( 'page_' . $page_id );
723
  break;
724
+ case 'post':
725
  return $this->add_cache_key_suffix( 'post_' . $page_id );
726
  break;
727
+ case 'attachment':
728
  return $this->add_cache_key_suffix( 'attach_' . $page_id );
729
  break;
730
+ case 'singular':
731
  return $this->add_cache_key_suffix( 'singular_' . $page_id );
732
  break;
733
+ case 'term':
734
  return $this->add_cache_key_suffix( $this->generate_taxonomical_cache_key( $page_id, $taxonomy ) );
735
  break;
736
  default:
758
  static $locale = null;
759
 
760
  if ( is_null( $locale ) )
761
+ $locale = strtolower( \get_locale() );
762
 
763
  return $key . '_' . $GLOBALS['blog_id'] . '_' . $locale;
764
  }
inc/classes/compat.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
inc/classes/core.class.php CHANGED
@@ -9,7 +9,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
9
 
10
  /**
11
  * The SEO Framework plugin
12
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
13
  *
14
  * This program is free software: you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License version 3 as published
@@ -67,6 +67,7 @@ class Core {
67
  * If the property never existed, default PHP behavior is invoked.
68
  *
69
  * @since 2.8.0
 
70
  *
71
  * @param string $name The property name.
72
  * @param mixed $value The property value.
@@ -75,29 +76,28 @@ class Core {
75
  /**
76
  * For now, no deprecation is being handled; as no properties have been deprecated. Just removed.
77
  */
78
- $this->_inaccessible_p_or_m( 'the_seo_framework()->' . \esc_html( $name ), 'unknown' );
79
 
80
- //* Invoke default behavior.
81
- $this->$name = $value;
 
82
  }
83
 
84
  /**
85
  * Handles unapproachable invoked properties.
 
86
  * Makes sure deprecated properties are still accessible.
87
- * If property never existed, default PHP behavior is invoked.
88
  *
89
  * @since 2.7.0
90
  * @since 3.1.0 Removed known deprecations.
 
91
  *
92
  * @param string $name The property name.
93
- * @return mixed $var The property value.
94
  */
95
  final public function __get( $name ) {
96
-
97
- $this->_inaccessible_p_or_m( 'the_seo_framework()->' . \esc_html( $name ), 'unknown' );
98
-
99
- //* Invoke default behavior.
100
- return $this->$name;
101
  }
102
 
103
  /**
@@ -120,7 +120,7 @@ class Core {
120
  return call_user_func_array( [ $depr_class, $name ], $arguments );
121
  }
122
 
123
- \the_seo_framework()->_inaccessible_p_or_m( 'the_seo_framework()->' . \esc_html( $name ) . '()' );
124
  return;
125
  }
126
 
@@ -159,7 +159,7 @@ class Core {
159
  */
160
  public function get_view( $view, array $__args = [], $instance = 'main' ) {
161
 
162
- //? extract().
163
  foreach ( $__args as $__k => $__v ) $$__k = $__v;
164
  unset( $__k, $__v, $__args );
165
 
@@ -235,22 +235,11 @@ class Core {
235
  '<a href="https://theseoframework.com/" rel="noreferrer noopener nofollow" target="_blank">%s</a>',
236
  \esc_html__( 'About', 'autodescription' )
237
  );
238
-
239
- /**
240
- * These are weak checks.
241
- * But it has minimum to no UX/performance impact on failure.
242
- */
243
- if ( ! defined( 'TSF_EXTENSION_MANAGER_VERSION' ) ) {
244
- $tsfem = \get_plugins( '/the-seo-framework-extension-manager' );
245
- //... I want PHP 5.5 for empty expressions :(
246
- // TODO open a plugin installation screen?
247
- if ( empty( $tsfem ) )
248
- $tsf_links['tsfem'] = sprintf(
249
- '<a href="%s" rel="noreferrer noopener" target="_blank">%s</a>',
250
- \esc_url( \__( 'https://wordpress.org/plugins/the-seo-framework-extension-manager/', 'autodescription' ) ),
251
- \esc_html_x( 'Extensions', 'Plugin extensions', 'autodescription' )
252
- );
253
- }
254
 
255
  return array_merge( $links, $tsf_links );
256
  }
@@ -751,23 +740,23 @@ class Core {
751
  * The conversion list's keys are per reference only.
752
  */
753
  $conversions = [
754
- '**' => 'strong',
755
- '*' => 'em',
756
- '`' => 'code',
757
- '[]()' => 'a',
758
  '======' => 'h6',
759
- '=====' => 'h5',
760
- '====' => 'h4',
761
- '===' => 'h3',
762
- '==' => 'h2',
763
- '=' => 'h1',
764
  ];
765
 
766
  $md_types = empty( $convert ) ? $conversions : array_intersect( $conversions, $convert );
767
 
768
  foreach ( $md_types as $type ) :
769
  switch ( $type ) :
770
- case 'strong' :
771
  $count = preg_match_all( '/(?:\*{2})([^\*{\2}]+)(?:\*{2})/', $text, $matches, PREG_PATTERN_ORDER );
772
 
773
  for ( $i = 0; $i < $count; $i++ ) {
@@ -779,7 +768,7 @@ class Core {
779
  }
780
  break;
781
 
782
- case 'em' :
783
  $count = preg_match_all( '/(?:\*{1})([^\*{\1}]+)(?:\*{1})/', $text, $matches, PREG_PATTERN_ORDER );
784
 
785
  for ( $i = 0; $i < $count; $i++ ) {
@@ -791,7 +780,7 @@ class Core {
791
  }
792
  break;
793
 
794
- case 'code' :
795
  $count = preg_match_all( '/(?:`{1})([^`{\1}]+)(?:`{1})/', $text, $matches, PREG_PATTERN_ORDER );
796
 
797
  for ( $i = 0; $i < $count; $i++ ) {
@@ -803,12 +792,12 @@ class Core {
803
  }
804
  break;
805
 
806
- case 'h6' :
807
- case 'h5' :
808
- case 'h4' :
809
- case 'h3' :
810
- case 'h2' :
811
- case 'h1' :
812
  $amount = filter_var( $type, FILTER_SANITIZE_NUMBER_INT );
813
  //* Considers word non-boundary. @TODO consider removing this?
814
  $expression = sprintf( '/(?:\={%1$s})\B([^\={\%1$s}]+)\B(?:\={%1$s})/', $amount );
@@ -824,8 +813,8 @@ class Core {
824
  }
825
  break;
826
 
827
- case 'a' :
828
- $count = preg_match_all( '/(?:(?:\[{1})([^\]{1}]+)(?:\]{1})(?:\({1})([^\)\(]+)(?:\){1}))/', $text, $matches, PREG_PATTERN_ORDER );
829
 
830
  $_string = $args['a_internal'] ? '<a href="%s">%s</a>' : '<a href="%s" target="_blank" rel="nofollow noreferrer noopener">%s</a>';
831
 
9
 
10
  /**
11
  * The SEO Framework plugin
12
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
13
  *
14
  * This program is free software: you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License version 3 as published
67
  * If the property never existed, default PHP behavior is invoked.
68
  *
69
  * @since 2.8.0
70
+ * @since 3.2.2 This method no longer allows to overwrite protected or private variables.
71
  *
72
  * @param string $name The property name.
73
  * @param mixed $value The property value.
76
  /**
77
  * For now, no deprecation is being handled; as no properties have been deprecated. Just removed.
78
  */
79
+ $this->_inaccessible_p_or_m( 'the_seo_framework()->' . $name, 'unknown' );
80
 
81
+ //* Invoke default behavior: Write variable if it's not protected.
82
+ if ( ! isset( $this->$name ) )
83
+ $this->$name = $value;
84
  }
85
 
86
  /**
87
  * Handles unapproachable invoked properties.
88
+ *
89
  * Makes sure deprecated properties are still accessible.
 
90
  *
91
  * @since 2.7.0
92
  * @since 3.1.0 Removed known deprecations.
93
+ * @since 3.2.2 This method no longer invokes PHP errors, nor returns protected values.
94
  *
95
  * @param string $name The property name.
96
+ * @return void
97
  */
98
  final public function __get( $name ) {
99
+ $this->_inaccessible_p_or_m( 'the_seo_framework()->' . $name, 'unknown' );
100
+ return;
 
 
 
101
  }
102
 
103
  /**
120
  return call_user_func_array( [ $depr_class, $name ], $arguments );
121
  }
122
 
123
+ \the_seo_framework()->_inaccessible_p_or_m( 'the_seo_framework()->' . $name . '()' );
124
  return;
125
  }
126
 
159
  */
160
  public function get_view( $view, array $__args = [], $instance = 'main' ) {
161
 
162
+ //? A faster extract().
163
  foreach ( $__args as $__k => $__v ) $$__k = $__v;
164
  unset( $__k, $__v, $__args );
165
 
235
  '<a href="https://theseoframework.com/" rel="noreferrer noopener nofollow" target="_blank">%s</a>',
236
  \esc_html__( 'About', 'autodescription' )
237
  );
238
+ $tsf_links['tsfem'] = sprintf(
239
+ '<a href="%s" rel="noreferrer noopener" target="_blank">%s</a>',
240
+ 'https://theseoframework.com/extensions/',
241
+ \esc_html_x( 'Extensions', 'Plugin extensions', 'autodescription' )
242
+ );
 
 
 
 
 
 
 
 
 
 
 
243
 
244
  return array_merge( $links, $tsf_links );
245
  }
740
  * The conversion list's keys are per reference only.
741
  */
742
  $conversions = [
743
+ '**' => 'strong',
744
+ '*' => 'em',
745
+ '`' => 'code',
746
+ '[]()' => 'a',
747
  '======' => 'h6',
748
+ '=====' => 'h5',
749
+ '====' => 'h4',
750
+ '===' => 'h3',
751
+ '==' => 'h2',
752
+ '=' => 'h1',
753
  ];
754
 
755
  $md_types = empty( $convert ) ? $conversions : array_intersect( $conversions, $convert );
756
 
757
  foreach ( $md_types as $type ) :
758
  switch ( $type ) :
759
+ case 'strong':
760
  $count = preg_match_all( '/(?:\*{2})([^\*{\2}]+)(?:\*{2})/', $text, $matches, PREG_PATTERN_ORDER );
761
 
762
  for ( $i = 0; $i < $count; $i++ ) {
768
  }
769
  break;
770
 
771
+ case 'em':
772
  $count = preg_match_all( '/(?:\*{1})([^\*{\1}]+)(?:\*{1})/', $text, $matches, PREG_PATTERN_ORDER );
773
 
774
  for ( $i = 0; $i < $count; $i++ ) {
780
  }
781
  break;
782
 
783
+ case 'code':
784
  $count = preg_match_all( '/(?:`{1})([^`{\1}]+)(?:`{1})/', $text, $matches, PREG_PATTERN_ORDER );
785
 
786
  for ( $i = 0; $i < $count; $i++ ) {
792
  }
793
  break;
794
 
795
+ case 'h6':
796
+ case 'h5':
797
+ case 'h4':
798
+ case 'h3':
799
+ case 'h2':
800
+ case 'h1':
801
  $amount = filter_var( $type, FILTER_SANITIZE_NUMBER_INT );
802
  //* Considers word non-boundary. @TODO consider removing this?
803
  $expression = sprintf( '/(?:\={%1$s})\B([^\={\%1$s}]+)\B(?:\={%1$s})/', $amount );
813
  }
814
  break;
815
 
816
+ case 'a':
817
+ $count = preg_match_all( '/(?:(?:\[{1})([^\]]+)(?:\]{1})(?:\({1})([^\)\(]+)(?:\){1}))/', $text, $matches, PREG_PATTERN_ORDER );
818
 
819
  $_string = $args['a_internal'] ? '<a href="%s">%s</a>' : '<a href="%s" target="_blank" rel="nofollow noreferrer noopener">%s</a>';
820
 
inc/classes/debug.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -284,13 +284,54 @@ final class Debug implements Debug_Interface {
284
  }
285
  }
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  /**
288
  * The SEO Framework error handler.
289
  *
290
- * Only handles notices.
291
  * @see E_USER_NOTICE
292
  *
293
  * @since 2.6.0
 
294
  *
295
  * @param int Error handling code.
296
  * @param string The error message.
@@ -298,28 +339,15 @@ final class Debug implements Debug_Interface {
298
  protected function error_handler_deprecated( $code, $message ) {
299
 
300
  //* Only do so if E_USER_NOTICE is pased.
301
- if ( 1024 === $code && isset( $message ) ) {
302
-
303
- $backtrace = debug_backtrace();
304
- /**
305
- * 0 = This function. 1 = Debug function. 2 = Error trigger. 3 = Deprecated Class, 4 = Deprecated Method, 5 = Magic Method, 6 = Deprecated call.
306
- * 0 = This function. 1 = Debug function. 2 = Error trigger. 3 = Deprecated Class, 4 = Deprecated Filter, 5 = Deprecated call.
307
- */
308
- if ( 'Filter ' === substr( $message, 0, 7 ) ) {
309
- $error = $backtrace[5];
310
- } else {
311
- $error = $backtrace[6];
312
- }
313
-
314
- $this->error_handler( $error, $message );
315
  }
316
  }
317
 
318
  /**
319
  * The SEO Framework error handler.
320
  *
321
- * Only handles notices.
322
- * @see E_USER_NOTICE
323
  *
324
  * @since 2.6.0
325
  *
@@ -329,25 +357,18 @@ final class Debug implements Debug_Interface {
329
  protected function error_handler_doing_it_wrong( $code, $message ) {
330
 
331
  //* Only do so if E_USER_NOTICE is pased.
332
- if ( 1024 === $code && isset( $message ) ) {
333
-
334
- $backtrace = debug_backtrace();
335
- /**
336
- * 0 = This function. 1 = Debug function. 2 = magic methods, 3 = Error trigger.
337
- */
338
- $error = $backtrace[3];
339
-
340
- $this->error_handler( $error, $message );
341
  }
342
  }
343
 
344
  /**
345
  * The SEO Framework error handler.
346
  *
347
- * Only handles notices.
348
- * @see E_USER_ERROR
349
  *
350
  * @since 2.6.0
 
351
  *
352
  * @param int Error handling code.
353
  * @param string The error message.
@@ -355,16 +376,8 @@ final class Debug implements Debug_Interface {
355
  protected function error_handler_inaccessible_call( $code, $message ) {
356
 
357
  //* Only do so if E_USER_ERROR is pased.
358
- if ( 256 === $code && isset( $message ) ) {
359
-
360
- $backtrace = debug_backtrace();
361
-
362
- /**
363
- * 0 = This function. 1-3 = Debug functions. 4-5 = magic methods, 6 = user call.
364
- */
365
- $error = $backtrace[6];
366
-
367
- $this->error_handler( $error, $message, $code );
368
  }
369
  }
370
 
@@ -374,7 +387,7 @@ final class Debug implements Debug_Interface {
374
  * @since 2.6.0
375
  * @since 2.8.0 added $code parameter
376
  *
377
- * @param array $error The Error location and file.
378
  * @param string $message The error message. Expected to be escaped.
379
  * @param int $code The error handler code.
380
  */
@@ -690,7 +703,8 @@ final class Debug implements Debug_Interface {
690
  }
691
 
692
  $value = '<font color="harrisonford">' . $type . ' ' . $value . '</font>';
693
- $out = \esc_html( $name ) . ' => ' . $value;
 
694
  $output .= $out . PHP_EOL;
695
  }
696
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
284
  }
285
  }
286
 
287
+ /**
288
+ * Retrieves the erroneous caller data.
289
+ *
290
+ * Assesses the depth of the caller based on "consistent" tracing.
291
+ * This is inaccurate when an error is invoked internally; but, you can trust that
292
+ * the plugin doesn't trigger this behavior.
293
+ *
294
+ * @since 3.2.2
295
+ * @see PHP debug_backtrace()
296
+ *
297
+ * @return array The erroneous caller data
298
+ */
299
+ protected function get_error() {
300
+
301
+ $backtrace = debug_backtrace();
302
+ /**
303
+ * 0 = This function.
304
+ * 1 = Error handler.
305
+ * 2 = Error forwarder.
306
+ * 3 = Debug handler.
307
+ */
308
+ if ( isset( $backtrace[7]['object'] ) && is_a( $backtrace[7]['object'], \the_seo_framework_class(), false ) ) {
309
+ /**
310
+ * 4 = TSF Factory magic method.
311
+ * 5 = Error invoking thing.
312
+ * 6 = TSF Factory. (the_seo_framework(), or a variable that stored this)
313
+ * 7 = Erroneous caller.
314
+ */
315
+ $error = $backtrace[7];
316
+ } else {
317
+ /**
318
+ * 4 = Error invoking thing.
319
+ * 5 = Erroneous caller.
320
+ */
321
+ $error = $backtrace[5];
322
+ }
323
+
324
+ return $error;
325
+ }
326
+
327
  /**
328
  * The SEO Framework error handler.
329
  *
330
+ * Only handles user notices.
331
  * @see E_USER_NOTICE
332
  *
333
  * @since 2.6.0
334
+ * @since 3.2.2 Fixed unaccounted-for backtrace depth logic since this class decoupling in 3.1
335
  *
336
  * @param int Error handling code.
337
  * @param string The error message.
339
  protected function error_handler_deprecated( $code, $message ) {
340
 
341
  //* Only do so if E_USER_NOTICE is pased.
342
+ if ( E_USER_NOTICE === $code && isset( $message ) ) {
343
+ $this->error_handler( $this->get_error(), $message );
 
 
 
 
 
 
 
 
 
 
 
 
344
  }
345
  }
346
 
347
  /**
348
  * The SEO Framework error handler.
349
  *
350
+ * Only handles user notices.
 
351
  *
352
  * @since 2.6.0
353
  *
357
  protected function error_handler_doing_it_wrong( $code, $message ) {
358
 
359
  //* Only do so if E_USER_NOTICE is pased.
360
+ if ( E_USER_NOTICE === $code && isset( $message ) ) {
361
+ $this->error_handler( $this->get_error(), $message );
 
 
 
 
 
 
 
362
  }
363
  }
364
 
365
  /**
366
  * The SEO Framework error handler.
367
  *
368
+ * Only handles user errors.
 
369
  *
370
  * @since 2.6.0
371
+ * @since 3.2.2 Fixed unaccounted-for backtrace depth logic since this class decoupling in 3.1
372
  *
373
  * @param int Error handling code.
374
  * @param string The error message.
376
  protected function error_handler_inaccessible_call( $code, $message ) {
377
 
378
  //* Only do so if E_USER_ERROR is pased.
379
+ if ( E_USER_ERROR === $code && isset( $message ) ) {
380
+ $this->error_handler( $this->get_error(), $message, $code );
 
 
 
 
 
 
 
 
381
  }
382
  }
383
 
387
  * @since 2.6.0
388
  * @since 2.8.0 added $code parameter
389
  *
390
+ * @param array $error The Error location and file data extruded from debug_backtrace().
391
  * @param string $message The error message. Expected to be escaped.
392
  * @param int $code The error handler code.
393
  */
703
  }
704
 
705
  $value = '<font color="harrisonford">' . $type . ' ' . $value . '</font>';
706
+ $out = \esc_html( $name ) . ' => ' . $value;
707
+
708
  $output .= $out . PHP_EOL;
709
  }
710
 
inc/classes/deprecated.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -664,5 +664,4 @@ final class Deprecated {
664
  $tsf->_deprecated_function( 'the_seo_framework()->generate_description_from_id()', '3.1.0', 'the_seo_framework()->get_generated_description()' );
665
  return $tsf->get_generated_description( $args, $escape );
666
  }
667
-
668
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
664
  $tsf->_deprecated_function( 'the_seo_framework()->generate_description_from_id()', '3.1.0', 'the_seo_framework()->get_generated_description()' );
665
  return $tsf->get_generated_description( $args, $escape );
666
  }
 
667
  }
inc/classes/detect.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -43,6 +43,7 @@ class Detect extends Render {
43
  */
44
  public function doing_ajax() {
45
  static $cache = null;
 
46
  return isset( $cache ) ? $cache : $cache = defined( 'DOING_AJAX' ) && DOING_AJAX;
47
  }
48
 
@@ -121,15 +122,17 @@ class Detect extends Render {
121
  public function conflicting_plugins() {
122
 
123
  $conflicting_plugins = [
124
- 'seo_tools' => [
125
  'Yoast SEO' => 'wordpress-seo/wp-seo.php',
126
  'Yoast SEO Premium' => 'wordpress-seo-premium/wp-seo-premium.php',
127
  'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php',
128
  'SEO Ultimate' => 'seo-ultimate/seo-ultimate.php',
129
  'Gregs High Performance SEO' => 'gregs-high-performance-seo/ghpseo.php',
130
  'SEOPress' => 'wp-seopress/seopress.php',
 
 
131
  ],
132
- 'sitemaps' => [
133
  'Google XML Sitemaps' => 'google-sitemap-generator/sitemap.php',
134
  'Better WordPress Google XML Sitemaps' => 'bwp-google-xml-sitemaps/bwp-simple-gxs.php', // Remove?
135
  'Google XML Sitemaps for qTranslate' => 'google-xml-sitemaps-v3-for-qtranslate/sitemap.php', // Remove?
@@ -138,16 +141,16 @@ class Detect extends Render {
138
  'Simple Wp Sitemap' => 'simple-wp-sitemap/simple-wp-sitemap.php',
139
  'XML Sitemaps' => 'xml-sitemaps/xml-sitemaps.php',
140
  ],
141
- 'open_graph' => [
142
  'Facebook Open Graph Meta Tags for WordPress' => 'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
143
- 'Facebook Thumb Fixer' => 'facebook-thumb-fixer/_facebook-thumb-fixer.php',
144
- 'NextGEN Facebook OG' => 'nextgen-facebook/nextgen-facebook.php',
145
- 'Open Graph' => 'opengraph/opengraph.php',
146
- 'Open Graph Protocol Framework' => 'open-graph-protocol-framework/open-graph-protocol-framework.php',
147
- 'Shareaholic2' => 'shareaholic/sexy-bookmarks.php',
148
- 'Social Sharing Toolkit' => 'social-sharing-toolkit/social_sharing_toolkit.php',
149
- 'WordPress Social Sharing Optimization' => 'wpsso/wpsso.php',
150
- 'WP Facebook Open Graph protocol' => 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php',
151
  ],
152
  'twitter_card' => [],
153
  ];
@@ -270,7 +273,7 @@ class Detect extends Render {
270
  }
271
 
272
  ksort( $mapped );
273
- $key = serialize( $mapped );
274
 
275
  if ( isset( $cache[ $key ] ) )
276
  return $cache[ $key ];
@@ -934,17 +937,23 @@ class Detect extends Render {
934
  * Gets all post types that could possibly support SEO.
935
  *
936
  * @since 3.1.0
 
 
937
  *
938
  * @return array The post types with rewrite capabilities.
939
  */
940
  protected function get_rewritable_post_types() {
941
-
942
- $post_types = (array) \get_post_types( [
943
- 'public' => true,
944
- 'rewrite' => true,
945
- ] );
946
  //? array_values() because get_post_types() gives a sequential array.
947
- return array_unique( array_merge( $this->get_forced_supported_post_types(), array_values( $post_types ) ) );
 
 
 
 
 
 
 
 
948
  }
949
 
950
  /**
@@ -1035,13 +1044,18 @@ class Detect extends Render {
1035
  * Detects if we're on a Gutenberg page.
1036
  *
1037
  * @since 3.1.0
 
 
1038
  *
1039
  * @return bool
1040
  */
1041
- protected function is_gutenberg_page() {
1042
- if ( function_exists( '\\is_gutenberg_page' ) ) {
 
 
 
1043
  return \is_gutenberg_page();
1044
- }
1045
  return false;
1046
  }
1047
 
@@ -1074,9 +1088,7 @@ class Detect extends Render {
1074
  return $cache;
1075
 
1076
  $parsed_url = \wp_parse_url( \get_option( 'home' ) );
1077
- if ( ! empty( $parsed_url['path'] ) && ltrim( $parsed_url['path'], ' \\/' ) )
1078
- $cache = true;
1079
 
1080
- return $cache ?: $cache = false;
1081
  }
1082
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
43
  */
44
  public function doing_ajax() {
45
  static $cache = null;
46
+
47
  return isset( $cache ) ? $cache : $cache = defined( 'DOING_AJAX' ) && DOING_AJAX;
48
  }
49
 
122
  public function conflicting_plugins() {
123
 
124
  $conflicting_plugins = [
125
+ 'seo_tools' => [
126
  'Yoast SEO' => 'wordpress-seo/wp-seo.php',
127
  'Yoast SEO Premium' => 'wordpress-seo-premium/wp-seo-premium.php',
128
  'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php',
129
  'SEO Ultimate' => 'seo-ultimate/seo-ultimate.php',
130
  'Gregs High Performance SEO' => 'gregs-high-performance-seo/ghpseo.php',
131
  'SEOPress' => 'wp-seopress/seopress.php',
132
+ 'Rank Math' => 'seo-by-rank-math/rank-math.php',
133
+ 'Smart Crawl' => 'smartcrawl-seo/wpmu-dev-seo.php',
134
  ],
135
+ 'sitemaps' => [
136
  'Google XML Sitemaps' => 'google-sitemap-generator/sitemap.php',
137
  'Better WordPress Google XML Sitemaps' => 'bwp-google-xml-sitemaps/bwp-simple-gxs.php', // Remove?
138
  'Google XML Sitemaps for qTranslate' => 'google-xml-sitemaps-v3-for-qtranslate/sitemap.php', // Remove?
141
  'Simple Wp Sitemap' => 'simple-wp-sitemap/simple-wp-sitemap.php',
142
  'XML Sitemaps' => 'xml-sitemaps/xml-sitemaps.php',
143
  ],
144
+ 'open_graph' => [
145
  'Facebook Open Graph Meta Tags for WordPress' => 'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
146
+ 'Facebook Thumb Fixer' => 'facebook-thumb-fixer/_facebook-thumb-fixer.php',
147
+ 'NextGEN Facebook OG' => 'nextgen-facebook/nextgen-facebook.php',
148
+ 'Open Graph' => 'opengraph/opengraph.php',
149
+ 'Open Graph Protocol Framework' => 'open-graph-protocol-framework/open-graph-protocol-framework.php',
150
+ 'Shareaholic2' => 'shareaholic/sexy-bookmarks.php',
151
+ 'Social Sharing Toolkit' => 'social-sharing-toolkit/social_sharing_toolkit.php',
152
+ 'WordPress Social Sharing Optimization' => 'wpsso/wpsso.php',
153
+ 'WP Facebook Open Graph protocol' => 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php',
154
  ],
155
  'twitter_card' => [],
156
  ];
273
  }
274
 
275
  ksort( $mapped );
276
+ $key = serialize( $mapped ); // phpcs:ignore -- No objects are inserted, nor is this ever unserialized.
277
 
278
  if ( isset( $cache[ $key ] ) )
279
  return $cache[ $key ];
937
  * Gets all post types that could possibly support SEO.
938
  *
939
  * @since 3.1.0
940
+ * @since 3.2.1 Added cache.
941
+ * @staticvar $cache
942
  *
943
  * @return array The post types with rewrite capabilities.
944
  */
945
  protected function get_rewritable_post_types() {
946
+ static $cache = null;
 
 
 
 
947
  //? array_values() because get_post_types() gives a sequential array.
948
+ return isset( $cache ) ? $cache : $cache = array_unique(
949
+ array_merge(
950
+ $this->get_forced_supported_post_types(),
951
+ array_values( (array) \get_post_types( [
952
+ 'public' => true,
953
+ 'rewrite' => true,
954
+ ] ) )
955
+ )
956
+ );
957
  }
958
 
959
  /**
1044
  * Detects if we're on a Gutenberg page.
1045
  *
1046
  * @since 3.1.0
1047
+ * @since 3.2.0 : 1. Now detects the WP 5.0 block editor.
1048
+ * 2. Method is now public.
1049
  *
1050
  * @return bool
1051
  */
1052
+ public function is_gutenberg_page() {
1053
+ if ( function_exists( '\\use_block_editor_for_post' ) )
1054
+ return ! empty( $GLOBALS['post'] ) && \use_block_editor_for_post( $GLOBALS['post'] );
1055
+
1056
+ if ( function_exists( '\\is_gutenberg_page' ) )
1057
  return \is_gutenberg_page();
1058
+
1059
  return false;
1060
  }
1061
 
1088
  return $cache;
1089
 
1090
  $parsed_url = \wp_parse_url( \get_option( 'home' ) );
 
 
1091
 
1092
+ return $cache = ! empty( $parsed_url['path'] ) && ltrim( $parsed_url['path'], ' \\/' );
1093
  }
1094
  }
inc/classes/doing-it-right.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -1779,7 +1779,7 @@ class Doing_It_Right extends Generate_Ldjson {
1779
  return $i18n;
1780
 
1781
  $guideline_i18n = $this->get_input_guidelines_i18n()['long'];
1782
-
1783
  return $i18n = [
1784
  'title' => \esc_attr__( 'Title:', 'autodescription' ),
1785
  'description' => \esc_attr__( 'Description:', 'autodescription' ),
@@ -1808,5 +1808,6 @@ class Doing_It_Right extends Generate_Ldjson {
1808
  'length_far_too_long' => $guideline_i18n['farTooLong'],
1809
  'length_good' => $guideline_i18n['good'],
1810
  ];
 
1811
  }
1812
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
1779
  return $i18n;
1780
 
1781
  $guideline_i18n = $this->get_input_guidelines_i18n()['long'];
1782
+ // phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned -- precision alignment OK.
1783
  return $i18n = [
1784
  'title' => \esc_attr__( 'Title:', 'autodescription' ),
1785
  'description' => \esc_attr__( 'Description:', 'autodescription' ),
1808
  'length_far_too_long' => $guideline_i18n['farTooLong'],
1809
  'length_good' => $guideline_i18n['good'],
1810
  ];
1811
+ // phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
1812
  }
1813
  }
inc/classes/feed.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
inc/classes/generate-description.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -48,7 +48,7 @@ class Generate_Description extends Generate {
48
  public function get_description( $args = null, $escape = true ) {
49
 
50
  $desc = $this->get_description_from_custom_field( $args, false )
51
- ?: $this->get_generated_description( $args, false );
52
 
53
  return $escape ? $this->escape_description( $desc ) : $desc;
54
  }
@@ -70,7 +70,7 @@ class Generate_Description extends Generate {
70
  public function get_open_graph_description( $args = null, $escape = true ) {
71
 
72
  $desc = $this->get_open_graph_description_from_custom_field( $args, false )
73
- ?: $this->get_generated_open_graph_description( $args, false );
74
 
75
  return $escape ? $this->escape_description( $desc ) : $desc;
76
  }
@@ -104,6 +104,7 @@ class Generate_Description extends Generate {
104
  * Falls back to meta description.
105
  *
106
  * @since 3.1.0
 
107
  * @see $this->get_open_graph_description()
108
  * @see $this->get_open_graph_description_from_custom_field()
109
  *
@@ -114,13 +115,19 @@ class Generate_Description extends Generate {
114
  $desc = '';
115
 
116
  if ( $this->is_real_front_page() ) {
117
- $desc = $this->get_option( 'homepage_og_description' ) ?: '';
118
- }
119
- if ( ! $desc ) {
120
- if ( $this->is_singular() ) {
121
- $desc = $this->get_custom_field( '_open_graph_description' )
122
- ?: $this->get_description_from_custom_field();
 
123
  }
 
 
 
 
 
124
  }
125
 
126
  return $desc;
@@ -131,6 +138,8 @@ class Generate_Description extends Generate {
131
  * Falls back to meta description.
132
  *
133
  * @since 3.1.0
 
 
134
  * @see $this->get_open_graph_description()
135
  * @see $this->get_open_graph_description_from_custom_field()
136
  *
@@ -142,14 +151,18 @@ class Generate_Description extends Generate {
142
  $desc = '';
143
 
144
  if ( $args['taxonomy'] ) {
145
- $desc = '';
146
  } else {
147
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
148
- $desc = $this->get_option( 'homepage_og_description' ) ?: '';
149
- }
150
- if ( ! $desc ) {
 
 
 
 
151
  $desc = $this->get_custom_field( '_open_graph_description', $args['id'] )
152
- ?: $this->get_description_from_custom_field( $args );
153
  }
154
  }
155
 
@@ -174,7 +187,7 @@ class Generate_Description extends Generate {
174
  public function get_twitter_description( $args = null, $escape = true ) {
175
 
176
  $desc = $this->get_twitter_description_from_custom_field( $args, false )
177
- ?: $this->get_generated_twitter_description( $args, false );
178
 
179
  return $escape ? $this->escape_description( $desc ) : $desc;
180
  }
@@ -208,6 +221,8 @@ class Generate_Description extends Generate {
208
  * Falls back to Open Graph description.
209
  *
210
  * @since 3.1.0
 
 
211
  * @see $this->get_twitter_description()
212
  * @see $this->get_twitter_description_from_custom_field()
213
  *
@@ -218,17 +233,23 @@ class Generate_Description extends Generate {
218
  $desc = '';
219
 
220
  if ( $this->is_real_front_page() ) {
221
- $desc = $this->get_option( 'homepage_twitter_description' )
222
- ?: $this->get_custom_field( '_twitter_description' )
223
- ?: $this->get_option( 'homepage_og_description' )
224
- ?: $this->get_custom_field( '_open_graph_description' )
225
- ?: $this->get_description_from_custom_field();
226
- } else {
227
- if ( $this->is_singular() ) {
228
- $desc = $this->get_custom_field( '_twitter_description' )
229
- ?: $this->get_custom_field( '_open_graph_description' )
230
- ?: $this->get_description_from_custom_field();
231
  }
 
 
 
 
 
 
232
  }
233
 
234
  return $desc;
@@ -239,6 +260,8 @@ class Generate_Description extends Generate {
239
  * Falls back to Open Graph description.
240
  *
241
  * @since 3.1.0
 
 
242
  * @see $this->get_twitter_description()
243
  * @see $this->get_twitter_description_from_custom_field()
244
  *
@@ -250,18 +273,22 @@ class Generate_Description extends Generate {
250
  $desc = '';
251
 
252
  if ( $args['taxonomy'] ) {
253
- $desc = '';
254
  } else {
255
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
256
  $desc = $this->get_option( 'homepage_twitter_description' )
257
  ?: $this->get_custom_field( '_twitter_description', $args['id'] )
258
  ?: $this->get_option( 'homepage_og_description' )
259
  ?: $this->get_custom_field( '_open_graph_description', $args['id'] )
260
- ?: $this->get_description_from_custom_field( $args );
 
 
 
 
261
  } else {
262
  $desc = $this->get_custom_field( '_twitter_description', $args['id'] )
263
  ?: $this->get_custom_field( '_open_graph_description', $args['id'] )
264
- ?: $this->get_description_from_custom_field( $args );
265
  }
266
  }
267
 
@@ -311,6 +338,7 @@ class Generate_Description extends Generate {
311
  * Gets a custom description, based on expected or current query, without escaping.
312
  *
313
  * @since 3.1.0
 
314
  * @internal
315
  * @see $this->get_description_from_custom_field()
316
  *
@@ -321,15 +349,18 @@ class Generate_Description extends Generate {
321
  $desc = '';
322
 
323
  if ( $this->is_real_front_page() ) {
324
- $desc = $this->get_option( 'homepage_description' ) ?: '';
325
- }
326
- if ( ! $desc ) {
327
- if ( $this->is_singular() ) {
328
- $desc = $this->get_custom_field( '_genesis_description' ) ?: '';
329
- } elseif ( $this->is_term_meta_capable() ) {
330
- $data = $this->get_term_meta( $this->get_the_real_ID() );
331
- $desc = ! empty( $data['description'] ) ? $data['description'] : '';
332
  }
 
 
 
 
 
333
  }
334
 
335
  return $desc;
@@ -339,6 +370,7 @@ class Generate_Description extends Generate {
339
  * Gets a custom description, based on input arguments query, without escaping.
340
  *
341
  * @since 3.1.0
 
342
  * @internal
343
  * @see $this->get_description_from_custom_field()
344
  *
@@ -350,14 +382,18 @@ class Generate_Description extends Generate {
350
  $desc = '';
351
 
352
  if ( $args['taxonomy'] ) {
353
- // $term = \get_term( $args['id'], $args['taxonomy'] ); // redundant
354
- $data = $this->get_term_meta( $args['id'] );
355
  $desc = ! empty( $data['description'] ) ? $data['description'] : '';
356
  } else {
357
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
 
 
 
 
358
  $desc = $this->get_option( 'homepage_description' ) ?: '';
 
 
359
  }
360
- $desc = $desc ?: $this->get_custom_field( '_genesis_description', $args['id'] ) ?: '';
361
  }
362
 
363
  return $desc;
@@ -373,6 +409,7 @@ class Generate_Description extends Generate {
373
  * 4. Added type argument.
374
  * @since 3.1.2 1. Now omits additions when the description will be deemed too short.
375
  * 2. Now no longer converts additions into excerpt when no excerpt is found.
 
376
  * @uses $this->generate_description()
377
  * @staticvar array $cache
378
  *
@@ -387,35 +424,17 @@ class Generate_Description extends Generate {
387
  if ( ! $this->is_auto_description_enabled( $args ) ) return '';
388
 
389
  if ( null === $args ) {
390
- $excerpt = $this->get_description_excerpt_from_query();
391
  $_filter_id = $this->get_the_real_ID();
392
- $additions_superseded = $this->are_description_additions_superseded();
393
  } else {
394
  $this->fix_generation_args( $args );
395
  $_filter_id = $args['id'];
396
- $excerpt = $this->get_description_excerpt_from_args( $args );
397
- $additions_superseded = $this->are_description_additions_superseded( $args );
398
  }
399
 
400
  if ( ! in_array( $type, [ 'opengraph', 'twitter', 'search' ], true ) )
401
  $type = 'search';
402
 
403
- $additions_length = 0;
404
- $sep_length = 0;
405
-
406
- $guidelines = $this->get_input_guidelines()['description'][ $type ];
407
-
408
- if ( ! $additions_superseded && 'search' === $type ) {
409
- $additions = $this->get_description_additions( $args );
410
-
411
- $sep_length = 3;
412
- $additions_length = $additions ? mb_strlen( html_entity_decode( $additions ) ) : 0;
413
- if ( $excerpt && $additions_length > 68 ) {
414
- $additions_length = 0;
415
- $sep_length = 0;
416
- }
417
- }
418
-
419
  /**
420
  * @since 2.9.0
421
  * @since 3.1.0 No longer passes 3rd and 4th parameter.
@@ -425,30 +444,11 @@ class Generate_Description extends Generate {
425
  $excerpt = (string) \apply_filters( 'the_seo_framework_fetched_description_excerpt', $excerpt, $_filter_id );
426
 
427
  $excerpt = $this->trim_excerpt(
428
- $excerpt,
429
  0,
430
- $guidelines['chars']['goodUpper'] - $additions_length - $sep_length
431
  );
432
 
433
- $use_additions = $additions_length
434
- && ( $excerpt || ( $additions_length >= $guidelines['chars']['lower'] ) );
435
-
436
- if ( $use_additions ) {
437
- if ( $excerpt ) {
438
- $desc = sprintf(
439
- /* translators: 1: Description additions, 2: Description separator, 3: Excerpt */
440
- \__( '%1$s %2$s %3$s', 'autodescription' ),
441
- $additions,
442
- $this->get_description_separator(),
443
- $excerpt
444
- );
445
- } else {
446
- $desc = $additions;
447
- }
448
- } else {
449
- $desc = $excerpt;
450
- }
451
-
452
  /**
453
  * Filters the generated description, if any.
454
  * @since 2.9.0
@@ -456,7 +456,7 @@ class Generate_Description extends Generate {
456
  * @param string $description The description.
457
  * @param array|null $args The description arguments.
458
  */
459
- $desc = (string) \apply_filters( 'the_seo_framework_generated_description', $desc, $args );
460
 
461
  return $escape ? $this->escape_description( $desc ) : $desc;
462
  }
@@ -491,27 +491,6 @@ class Generate_Description extends Generate {
491
  return $this->get_generated_description( $args, $escape, 'opengraph' );
492
  }
493
 
494
- /**
495
- * Determines whether description additions are used instead of an excerpt,
496
- * thus superseding the need.
497
- *
498
- * @since 3.1.0
499
- *
500
- * @param array|null $args An array of 'id' and 'taxonomy' values.
501
- * @return bool
502
- */
503
- protected function are_description_additions_superseded( $args = null ) {
504
-
505
- if ( $args ) {
506
- if ( empty( $args['taxonomy'] ) )
507
- return $this->is_blog_page( $args['id'] ) || $this->is_front_page_by_id( $args['id'] );
508
- } else {
509
- return $this->is_blog_page() || $this->is_real_front_page();
510
- }
511
-
512
- return false;
513
- }
514
-
515
  /**
516
  * Returns a description excerpt for the current query.
517
  *
@@ -545,6 +524,7 @@ class Generate_Description extends Generate {
545
  * Returns a description excerpt for the current query.
546
  *
547
  * @since 3.1.0
 
548
  *
549
  * @param array|null $args An array of 'id' and 'taxonomy' values.
550
  * @return string
@@ -558,7 +538,7 @@ class Generate_Description extends Generate {
558
  } else {
559
  if ( $this->is_blog_page( $args['id'] ) ) {
560
  $excerpt = $this->get_blog_page_description_excerpt();
561
- } elseif ( $this->is_front_page_by_id( $args['id'] ) ) {
562
  $excerpt = $this->get_front_page_description_excerpt();
563
  } else {
564
  $excerpt = $this->get_singular_description_excerpt( $args['id'] );
@@ -576,7 +556,7 @@ class Generate_Description extends Generate {
576
  * @return string
577
  */
578
  protected function get_blog_page_description_excerpt() {
579
- return $this->get_description_additions( [ 'id' => (int) \get_option( 'page_for_posts' ) ], true );
580
  }
581
 
582
  /**
@@ -594,7 +574,7 @@ class Generate_Description extends Generate {
594
  if ( $this->is_static_frontpage( $id ) ) {
595
  $excerpt = $this->get_singular_description_excerpt( $id );
596
  }
597
- $excerpt = $excerpt ?: $this->get_description_additions( [ 'id' => $id ], true );
598
 
599
  return $excerpt;
600
  }
@@ -621,7 +601,6 @@ class Generate_Description extends Generate {
621
 
622
  /**
623
  * @since 3.1.0
624
- *
625
  * @param string $excerpt The short circuit excerpt.
626
  * @param \WP_Term $term The Term object.
627
  */
@@ -672,6 +651,9 @@ class Generate_Description extends Generate {
672
  * Returns additions for "Title on Blogname".
673
  *
674
  * @since 3.1.0
 
 
 
675
  * @see $this->get_generated_description()
676
  *
677
  * @param array|null $args An array of 'id' and 'taxonomy' values.
@@ -681,57 +663,22 @@ class Generate_Description extends Generate {
681
  */
682
  protected function get_description_additions( $args, $forced = false ) {
683
 
684
- $term = null;
685
- if ( is_null( $args ) ) {
686
- $term = $this->is_archive() ? \get_queried_object() : null;
687
- } elseif ( ! empty( $args['taxonomy'] ) ) {
688
- $term = \get_term( $args['id'], $args['taxonomy'] );
689
- }
690
-
691
- $additions = [
692
- 'title' => '',
693
- 'on' => '',
694
- 'blogname' => '',
695
- ];
696
-
697
- if ( $forced || $this->add_description_additions( $args['id'], $term ) ) {
698
- if ( ! empty( $args['taxonomy'] ) ) {
699
- $title = $this->generate_title_from_args( $args );
700
- } else {
701
- if ( $this->is_blog_page( $args['id'] ) ) {
702
- $title = $this->get_raw_generated_title( $args );
703
- /* translators: %s = Blog page title. Front-end output. */
704
- $title = sprintf( \__( 'Latest posts: %s', 'autodescription' ), $title );
705
- } elseif ( $this->is_front_page_by_id( $args['id'] ) ) {
706
- $title = $this->get_home_page_tagline();
707
- } else {
708
- if ( is_null( $args ) ) {
709
- $title = $this->generate_title_from_query();
710
- } else {
711
- $title = $this->generate_title_from_args( $args );
712
- }
713
- }
714
- }
715
 
716
- if ( $forced || $this->get_option( 'description_blogname' ) ) {
717
- $additions = [
718
- 'title' => $title,
719
- 'on' => \_x( 'on', 'Placement. e.g. Post Title "on" Blog Name', 'autodescription' ),
720
- 'blogname' => $this->get_blogname(),
721
- ];
722
- } else {
723
- $additions = array_merge( $additions, [
724
- 'title' => $title,
725
- ] );
726
- }
727
  }
728
 
729
- if ( empty( $additions['title'] ) )
730
  return '';
731
 
732
- $title = $additions['title'];
733
- $on = $additions['on'];
734
- $blogname = $additions['blogname'];
735
 
736
  /* translators: 1: Title, 2: on, 3: Blogname */
737
  return trim( sprintf( \__( '%1$s %2$s %3$s', 'autodescription' ), $title, $on, $blogname ) );
@@ -780,6 +727,7 @@ class Generate_Description extends Generate {
780
  if ( ';' === substr( $excerpt, -1 ) ) {
781
  //* Replace connector punctuation with a dot.
782
  $excerpt = rtrim( $excerpt, ' \\/,.?!;' );
 
783
  if ( $excerpt )
784
  $excerpt .= '.';
785
  } elseif ( $excerpt ) {
@@ -828,53 +776,4 @@ class Generate_Description extends Generate {
828
  ]
829
  );
830
  }
831
-
832
- /**
833
- * Determines whether to add description additions. (╯°□°)╯︵ ┻━┻
834
- *
835
- * @since 2.6.0
836
- * @since 2.7.0 : 1. Removed cache.
837
- * 2. Removed excerpt availability check.
838
-
839
- * @param int $id The current page or post ID.
840
- * @param \WP_Term|string $term The current Term.
841
- * @return bool Whether to add description additions.
842
- */
843
- public function add_description_additions( $id = '', $term = '' ) {
844
-
845
- /**
846
- * @since 2.6.0
847
- * @param array $filter : {
848
- * @param bool $filter Set to true to add prefix.
849
- * @param int $id The Term object ID or The Page ID.
850
- * @param \WP_term $term The Term object.
851
- * }
852
- */
853
- $filter = \apply_filters( 'the_seo_framework_add_description_additions', true, $id, $term );
854
- $option = $this->get_option( 'description_additions' );
855
-
856
- return $option && $filter;
857
- }
858
-
859
- /**
860
- * Returns Description Separator.
861
- *
862
- * @since 2.3.9
863
- * @staticvar string $sep
864
- *
865
- * @return string The Separator, unescaped.
866
- */
867
- public function get_description_separator() {
868
- static $sep;
869
- /**
870
- * @since 2.3.9
871
- * @param string $sep The description separator.
872
- */
873
- return isset( $sep )
874
- ? $sep
875
- : $sep = (string) \apply_filters(
876
- 'the_seo_framework_description_separator',
877
- $this->get_separator( 'description' )
878
- );
879
- }
880
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
48
  public function get_description( $args = null, $escape = true ) {
49
 
50
  $desc = $this->get_description_from_custom_field( $args, false )
51
+ ?: $this->get_generated_description( $args, false ); // precision alignment ok.
52
 
53
  return $escape ? $this->escape_description( $desc ) : $desc;
54
  }
70
  public function get_open_graph_description( $args = null, $escape = true ) {
71
 
72
  $desc = $this->get_open_graph_description_from_custom_field( $args, false )
73
+ ?: $this->get_generated_open_graph_description( $args, false ); // precision alignment ok.
74
 
75
  return $escape ? $this->escape_description( $desc ) : $desc;
76
  }
104
  * Falls back to meta description.
105
  *
106
  * @since 3.1.0
107
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
108
  * @see $this->get_open_graph_description()
109
  * @see $this->get_open_graph_description_from_custom_field()
110
  *
115
  $desc = '';
116
 
117
  if ( $this->is_real_front_page() ) {
118
+ if ( $this->is_static_frontpage() ) {
119
+ $desc = $this->get_option( 'homepage_og_description' )
120
+ ?: $this->get_custom_field( '_open_graph_description' )
121
+ ?: $this->get_description_from_custom_field(); // precision alignment ok
122
+ } else {
123
+ $desc = $this->get_option( 'homepage_og_description' )
124
+ ?: $this->get_description_from_custom_field(); // precision alignment ok.
125
  }
126
+ } elseif ( $this->is_singular() ) {
127
+ $desc = $this->get_custom_field( '_open_graph_description' )
128
+ ?: $this->get_description_from_custom_field(); // precision alignment ok.
129
+ } elseif ( $this->is_term_meta_capable() ) {
130
+ $desc = $this->get_description_from_custom_field();
131
  }
132
 
133
  return $desc;
138
  * Falls back to meta description.
139
  *
140
  * @since 3.1.0
141
+ * @since 3.2.2: 1. Now tests for the home page as page prior getting custom field data.
142
+ * 2. Now obtains custom field data for terms.
143
  * @see $this->get_open_graph_description()
144
  * @see $this->get_open_graph_description_from_custom_field()
145
  *
151
  $desc = '';
152
 
153
  if ( $args['taxonomy'] ) {
154
+ $desc = $this->get_description_from_custom_field( $args );
155
  } else {
156
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
157
+ $desc = $this->get_option( 'homepage_og_description' )
158
+ ?: $this->get_custom_field( '_open_graph_description', $args['id'] )
159
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
160
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
161
+ $desc = $this->get_option( 'homepage_og_description' )
162
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
163
+ } else {
164
  $desc = $this->get_custom_field( '_open_graph_description', $args['id'] )
165
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
166
  }
167
  }
168
 
187
  public function get_twitter_description( $args = null, $escape = true ) {
188
 
189
  $desc = $this->get_twitter_description_from_custom_field( $args, false )
190
+ ?: $this->get_generated_twitter_description( $args, false ); // precision alignment ok.
191
 
192
  return $escape ? $this->escape_description( $desc ) : $desc;
193
  }
221
  * Falls back to Open Graph description.
222
  *
223
  * @since 3.1.0
224
+ * @since 3.2.2: 1. Now tests for the home page as page prior getting custom field data.
225
+ * 2. Now obtains custom field data for terms.
226
  * @see $this->get_twitter_description()
227
  * @see $this->get_twitter_description_from_custom_field()
228
  *
233
  $desc = '';
234
 
235
  if ( $this->is_real_front_page() ) {
236
+ if ( $this->is_static_frontpage() ) {
237
+ $desc = $this->get_option( 'homepage_twitter_description' )
238
+ ?: $this->get_custom_field( '_twitter_description' )
239
+ ?: $this->get_option( 'homepage_og_description' )
240
+ ?: $this->get_custom_field( '_open_graph_description' )
241
+ ?: $this->get_description_from_custom_field(); // precision alignment ok.
242
+ } else {
243
+ $desc = $this->get_option( 'homepage_twitter_description' )
244
+ ?: $this->get_option( 'homepage_og_description' )
245
+ ?: $this->get_description_from_custom_field(); // precision alignment ok.
246
  }
247
+ } elseif ( $this->is_singular() ) {
248
+ $desc = $this->get_custom_field( '_twitter_description' )
249
+ ?: $this->get_custom_field( '_open_graph_description' )
250
+ ?: $this->get_description_from_custom_field(); // precision alignment ok.
251
+ } elseif ( $this->is_term_meta_capable() ) {
252
+ $desc = $this->get_description_from_custom_field();
253
  }
254
 
255
  return $desc;
260
  * Falls back to Open Graph description.
261
  *
262
  * @since 3.1.0
263
+ * @since 3.2.2: 1. Now tests for the home page as page prior getting custom field data.
264
+ * 2. Now obtains custom field data for terms.
265
  * @see $this->get_twitter_description()
266
  * @see $this->get_twitter_description_from_custom_field()
267
  *
273
  $desc = '';
274
 
275
  if ( $args['taxonomy'] ) {
276
+ $desc = $this->get_description_from_custom_field( $args );
277
  } else {
278
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
279
  $desc = $this->get_option( 'homepage_twitter_description' )
280
  ?: $this->get_custom_field( '_twitter_description', $args['id'] )
281
  ?: $this->get_option( 'homepage_og_description' )
282
  ?: $this->get_custom_field( '_open_graph_description', $args['id'] )
283
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
284
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
285
+ $desc = $this->get_option( 'homepage_twitter_description' )
286
+ ?: $this->get_option( 'homepage_og_description' )
287
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
288
  } else {
289
  $desc = $this->get_custom_field( '_twitter_description', $args['id'] )
290
  ?: $this->get_custom_field( '_open_graph_description', $args['id'] )
291
+ ?: $this->get_description_from_custom_field( $args ); // precision alignment ok.
292
  }
293
  }
294
 
338
  * Gets a custom description, based on expected or current query, without escaping.
339
  *
340
  * @since 3.1.0
341
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
342
  * @internal
343
  * @see $this->get_description_from_custom_field()
344
  *
349
  $desc = '';
350
 
351
  if ( $this->is_real_front_page() ) {
352
+ if ( $this->is_static_frontpage() ) {
353
+ $desc = $this->get_option( 'homepage_description' )
354
+ ?: $this->get_custom_field( '_genesis_description' )
355
+ ?: ''; // precision alignment ok.
356
+ } else {
357
+ $desc = $this->get_option( 'homepage_description' ) ?: '';
 
 
358
  }
359
+ } elseif ( $this->is_singular() ) {
360
+ $desc = $this->get_custom_field( '_genesis_description' ) ?: '';
361
+ } elseif ( $this->is_term_meta_capable() ) {
362
+ $data = $this->get_term_meta( $this->get_the_real_ID() );
363
+ $desc = ! empty( $data['description'] ) ? $data['description'] : '';
364
  }
365
 
366
  return $desc;
370
  * Gets a custom description, based on input arguments query, without escaping.
371
  *
372
  * @since 3.1.0
373
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
374
  * @internal
375
  * @see $this->get_description_from_custom_field()
376
  *
382
  $desc = '';
383
 
384
  if ( $args['taxonomy'] ) {
385
+ $data = $this->get_term_meta( $args['id'] );
 
386
  $desc = ! empty( $data['description'] ) ? $data['description'] : '';
387
  } else {
388
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
389
+ $desc = $this->get_option( 'homepage_description' )
390
+ ?: $this->get_custom_field( '_genesis_description', $args['id'] )
391
+ ?: ''; // Precision alignment ok.
392
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
393
  $desc = $this->get_option( 'homepage_description' ) ?: '';
394
+ } else {
395
+ $desc = $this->get_custom_field( '_genesis_description', $args['id'] ) ?: '';
396
  }
 
397
  }
398
 
399
  return $desc;
409
  * 4. Added type argument.
410
  * @since 3.1.2 1. Now omits additions when the description will be deemed too short.
411
  * 2. Now no longer converts additions into excerpt when no excerpt is found.
412
+ * @since 3.2.2 Now converts HTML characters prior trimming.
413
  * @uses $this->generate_description()
414
  * @staticvar array $cache
415
  *
424
  if ( ! $this->is_auto_description_enabled( $args ) ) return '';
425
 
426
  if ( null === $args ) {
427
+ $excerpt = $this->get_description_excerpt_from_query();
428
  $_filter_id = $this->get_the_real_ID();
 
429
  } else {
430
  $this->fix_generation_args( $args );
431
  $_filter_id = $args['id'];
432
+ $excerpt = $this->get_description_excerpt_from_args( $args );
 
433
  }
434
 
435
  if ( ! in_array( $type, [ 'opengraph', 'twitter', 'search' ], true ) )
436
  $type = 'search';
437
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  /**
439
  * @since 2.9.0
440
  * @since 3.1.0 No longer passes 3rd and 4th parameter.
444
  $excerpt = (string) \apply_filters( 'the_seo_framework_fetched_description_excerpt', $excerpt, $_filter_id );
445
 
446
  $excerpt = $this->trim_excerpt(
447
+ html_entity_decode( $excerpt, ENT_QUOTES | ENT_COMPAT, 'UTF-8' ),
448
  0,
449
+ $this->get_input_guidelines()['description'][ $type ]['chars']['goodUpper']
450
  );
451
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  /**
453
  * Filters the generated description, if any.
454
  * @since 2.9.0
456
  * @param string $description The description.
457
  * @param array|null $args The description arguments.
458
  */
459
+ $desc = (string) \apply_filters( 'the_seo_framework_generated_description', $excerpt, $args );
460
 
461
  return $escape ? $this->escape_description( $desc ) : $desc;
462
  }
491
  return $this->get_generated_description( $args, $escape, 'opengraph' );
492
  }
493
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  /**
495
  * Returns a description excerpt for the current query.
496
  *
524
  * Returns a description excerpt for the current query.
525
  *
526
  * @since 3.1.0
527
+ * @since 3.2.2 Fixed front-page as blog logic.
528
  *
529
  * @param array|null $args An array of 'id' and 'taxonomy' values.
530
  * @return string
538
  } else {
539
  if ( $this->is_blog_page( $args['id'] ) ) {
540
  $excerpt = $this->get_blog_page_description_excerpt();
541
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
542
  $excerpt = $this->get_front_page_description_excerpt();
543
  } else {
544
  $excerpt = $this->get_singular_description_excerpt( $args['id'] );
556
  * @return string
557
  */
558
  protected function get_blog_page_description_excerpt() {
559
+ return $this->get_description_additions( [ 'id' => (int) \get_option( 'page_for_posts' ) ] );
560
  }
561
 
562
  /**
574
  if ( $this->is_static_frontpage( $id ) ) {
575
  $excerpt = $this->get_singular_description_excerpt( $id );
576
  }
577
+ $excerpt = $excerpt ?: $this->get_description_additions( [ 'id' => $id ] );
578
 
579
  return $excerpt;
580
  }
601
 
602
  /**
603
  * @since 3.1.0
 
604
  * @param string $excerpt The short circuit excerpt.
605
  * @param \WP_Term $term The Term object.
606
  */
651
  * Returns additions for "Title on Blogname".
652
  *
653
  * @since 3.1.0
654
+ * @since 3.2.0 : 1. Now no longer listens to options.
655
+ * 2. Now only works for the front and blog pages.
656
+ * @since 3.2.2 Now works for home pages from external requests.
657
  * @see $this->get_generated_description()
658
  *
659
  * @param array|null $args An array of 'id' and 'taxonomy' values.
663
  */
664
  protected function get_description_additions( $args, $forced = false ) {
665
 
666
+ $this->fix_generation_args( $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
 
668
+ if ( $this->is_blog_page( $args['id'] ) ) {
669
+ $title = $this->get_raw_generated_title( $args );
670
+ /* translators: %s = Blog page title. Front-end output. */
671
+ $title = sprintf( \__( 'Latest posts: %s', 'autodescription' ), $title );
672
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
673
+ $title = $this->get_home_page_tagline();
 
 
 
 
 
674
  }
675
 
676
+ if ( empty( $title ) )
677
  return '';
678
 
679
+ $title = $title;
680
+ $on = \_x( 'on', 'Placement. e.g. Post Title "on" Blog Name', 'autodescription' );
681
+ $blogname = $this->get_blogname();
682
 
683
  /* translators: 1: Title, 2: on, 3: Blogname */
684
  return trim( sprintf( \__( '%1$s %2$s %3$s', 'autodescription' ), $title, $on, $blogname ) );
727
  if ( ';' === substr( $excerpt, -1 ) ) {
728
  //* Replace connector punctuation with a dot.
729
  $excerpt = rtrim( $excerpt, ' \\/,.?!;' );
730
+
731
  if ( $excerpt )
732
  $excerpt .= '.';
733
  } elseif ( $excerpt ) {
776
  ]
777
  );
778
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  }
inc/classes/generate-image.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -96,6 +96,7 @@ class Generate_Image extends Generate_Url {
96
  * in a grey area... @TODO make images optional for Schema?
97
  *
98
  * @since 2.9.3
 
99
  * @uses $this->get_social_image()
100
  * @staticvar array $images
101
  * @TODO exchange 2nd argument with $taxonomy.
@@ -120,24 +121,12 @@ class Generate_Image extends Generate_Url {
120
  return $images[ $id ][ $singular ];
121
 
122
  if ( $singular ) {
123
- if ( $id === $this->get_the_front_page_ID() ) {
124
- if ( $this->has_page_on_front() ) {
125
- $image_args = [
126
- 'post_id' => $id,
127
- 'skip_fallback' => true,
128
- 'escape' => false,
129
- ];
130
- } else {
131
- $image_args = [
132
- 'post_id' => $id,
133
- 'skip_fallback' => true,
134
- 'disallowed' => [
135
- 'postmeta',
136
- 'featured',
137
- ],
138
- 'escape' => false,
139
- ];
140
- }
141
  } else {
142
  $image_args = [
143
  'post_id' => $id,
@@ -171,6 +160,7 @@ class Generate_Image extends Generate_Url {
171
  *
172
  * @since 2.9.0
173
  * @since 3.0.6 Added attachment page compatibility.
 
174
  *
175
  * @todo listen to attached images within post.
176
  * @todo listen to archive images. -> set taxonomy argument.
@@ -198,7 +188,8 @@ class Generate_Image extends Generate_Url {
198
  goto end;
199
  }
200
 
201
- if ( $args['post_id'] ) {
 
202
  //* 2. Fetch image from SEO meta upload.
203
  if ( $all_allowed || false === in_array( 'postmeta', $args['disallowed'], true ) ) {
204
  if ( $image = $this->get_social_image_url_from_post_meta( $args['post_id'], true ) )
@@ -232,7 +223,6 @@ class Generate_Image extends Generate_Url {
232
  if ( $args['skip_fallback'] )
233
  goto end;
234
 
235
-
236
  //* 3.5 Fetch image from fallback filter 0
237
  fallback_0 : {
238
  /**
@@ -362,7 +352,7 @@ class Generate_Image extends Generate_Url {
362
  return $defaults;
363
 
364
  //* Array merge doesn't support sanitation. We're simply type casting here.
365
- // phpcs:disable -- it's ok.
366
  $args['post_id'] = isset( $args['post_id'] ) ? (int) $args['post_id'] : $defaults['post_id'];
367
  $args['image'] = isset( $args['image'] ) ? (string) $args['image'] : $defaults['image'];
368
  $args['size'] = isset( $args['size'] ) ? $args['size'] : $defaults['size']; // Mixed.
@@ -370,7 +360,7 @@ class Generate_Image extends Generate_Url {
370
  $args['skip_fallback'] = isset( $args['skip_fallback'] ) ? (bool) $args['skip_fallback'] : $defaults['skip_fallback'];
371
  $args['disallowed'] = isset( $args['disallowed'] ) ? (array) $args['disallowed'] : $defaults['disallowed'];
372
  $args['escape'] = isset( $args['escape'] ) ? (bool) $args['escape'] : $defaults['escape'];
373
- // phpcs:enable
374
 
375
  return $args;
376
  }
@@ -409,7 +399,7 @@ class Generate_Image extends Generate_Url {
409
  */
410
  public function get_social_image_url_from_home_meta( $id = 0, $set_og_dimensions = false ) {
411
 
412
- //* Don't output if not front page.
413
  if ( false === $this->is_front_page_by_id( $id ) )
414
  return '';
415
 
@@ -506,7 +496,7 @@ class Generate_Image extends Generate_Url {
506
  if ( ! $image_id )
507
  return '';
508
 
509
- $args = $this->reparse_image_args( $args );
510
  $args['get_the_real_ID'] = true;
511
 
512
  $src = $this->parse_og_image( $image_id, $args, $set_og_dimensions );
@@ -532,7 +522,7 @@ class Generate_Image extends Generate_Url {
532
  if ( ! \wp_attachment_is_image( $id ) )
533
  return '';
534
 
535
- $args = $this->reparse_image_args( $args );
536
  $args['get_the_real_ID'] = true;
537
 
538
  $src = $this->parse_og_image( $id, $args, $set_og_dimensions );
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
96
  * in a grey area... @TODO make images optional for Schema?
97
  *
98
  * @since 2.9.3
99
+ * @since 3.2.2 No longer relies on the query.
100
  * @uses $this->get_social_image()
101
  * @staticvar array $images
102
  * @TODO exchange 2nd argument with $taxonomy.
121
  return $images[ $id ][ $singular ];
122
 
123
  if ( $singular ) {
124
+ if ( $this->is_real_front_page_by_id( $id ) ) {
125
+ $image_args = [
126
+ 'post_id' => $id,
127
+ 'skip_fallback' => true,
128
+ 'escape' => false,
129
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
130
  } else {
131
  $image_args = [
132
  'post_id' => $id,
160
  *
161
  * @since 2.9.0
162
  * @since 3.0.6 Added attachment page compatibility.
163
+ * @since 3.2.2 Now skips the singular meta images on archives.
164
  *
165
  * @todo listen to attached images within post.
166
  * @todo listen to archive images. -> set taxonomy argument.
188
  goto end;
189
  }
190
 
191
+ // FIXME: `! $this->is_archive()` = Patch for taxonomies taking incorrect images...
192
+ if ( $args['post_id'] && ! $this->is_archive() ) {
193
  //* 2. Fetch image from SEO meta upload.
194
  if ( $all_allowed || false === in_array( 'postmeta', $args['disallowed'], true ) ) {
195
  if ( $image = $this->get_social_image_url_from_post_meta( $args['post_id'], true ) )
223
  if ( $args['skip_fallback'] )
224
  goto end;
225
 
 
226
  //* 3.5 Fetch image from fallback filter 0
227
  fallback_0 : {
228
  /**
352
  return $defaults;
353
 
354
  //* Array merge doesn't support sanitation. We're simply type casting here.
355
+ // phpcs:disable WordPress.WhiteSpace.OperatorSpacing.SpacingBefore -- precision alignment OK.
356
  $args['post_id'] = isset( $args['post_id'] ) ? (int) $args['post_id'] : $defaults['post_id'];
357
  $args['image'] = isset( $args['image'] ) ? (string) $args['image'] : $defaults['image'];
358
  $args['size'] = isset( $args['size'] ) ? $args['size'] : $defaults['size']; // Mixed.
360
  $args['skip_fallback'] = isset( $args['skip_fallback'] ) ? (bool) $args['skip_fallback'] : $defaults['skip_fallback'];
361
  $args['disallowed'] = isset( $args['disallowed'] ) ? (array) $args['disallowed'] : $defaults['disallowed'];
362
  $args['escape'] = isset( $args['escape'] ) ? (bool) $args['escape'] : $defaults['escape'];
363
+ // phpcs:enable WordPress.WhiteSpace.OperatorSpacing.SpacingBefore
364
 
365
  return $args;
366
  }
399
  */
400
  public function get_social_image_url_from_home_meta( $id = 0, $set_og_dimensions = false ) {
401
 
402
+ //* Don't output if not on the front page ...FIXME... by query.
403
  if ( false === $this->is_front_page_by_id( $id ) )
404
  return '';
405
 
496
  if ( ! $image_id )
497
  return '';
498
 
499
+ $args = $this->reparse_image_args( $args );
500
  $args['get_the_real_ID'] = true;
501
 
502
  $src = $this->parse_og_image( $image_id, $args, $set_og_dimensions );
522
  if ( ! \wp_attachment_is_image( $id ) )
523
  return '';
524
 
525
+ $args = $this->reparse_image_args( $args );
526
  $args['get_the_real_ID'] = true;
527
 
528
  $src = $this->parse_og_image( $id, $args, $set_og_dimensions );
inc/classes/generate-ldjson.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -409,14 +409,14 @@ class Generate_Ldjson extends Generate_Image {
409
  * @since 3.0.0 1: Now only returns one crumb.
410
  * 2: Now listens to primary term ID.
411
  *
412
- * @return string LD+JSON breadcrumbs script for Posts.
413
  */
414
  public function get_ld_json_breadcrumbs_post() {
415
 
416
  $output = '';
417
 
418
- $post_id = $this->get_the_real_ID();
419
- $post_type = \get_post_type( $post_id );
420
  $taxonomies = $this->get_hierarchical_taxonomies_as( 'names', \get_post_type( $post_id ) );
421
 
422
  /**
@@ -572,15 +572,15 @@ class Generate_Ldjson extends Generate_Image {
572
  *
573
  * @since 2.9.3
574
  *
575
- * @param array $kittens The breadcrumb trees, with the key as parent.
576
  * @param array $previous_tree A previous set tree to compare to, if set.
577
  * @return array Trees in order.
578
  */
579
- protected function build_ld_json_breadcrumb_trees( $kittens, array $previous_tree = [] ) {
580
 
581
  $trees = $previous_tree;
582
 
583
- foreach ( $kittens as $parent => $kitten ) {
584
  if ( empty( $kitten ) ) {
585
  //* Final cat.
586
  $trees[] = $parent;
@@ -647,6 +647,9 @@ class Generate_Ldjson extends Generate_Image {
647
  * Generates homepage LD+JSON breadcrumb.
648
  *
649
  * @since 2.9.3
 
 
 
650
  * @staticvar array $crumb
651
  *
652
  * @return array The HomePage crumb entry.
@@ -654,7 +657,6 @@ class Generate_Ldjson extends Generate_Image {
654
  public function get_ld_json_breadcrumb_home_crumb() {
655
 
656
  static $crumb = null;
657
-
658
  if ( isset( $crumb ) )
659
  return $crumb;
660
 
@@ -775,15 +777,15 @@ class Generate_Ldjson extends Generate_Image {
775
  public function get_schema_url_id( $type, $from, $args = [] ) {
776
 
777
  switch ( $from ) {
778
- case 'currentpage' :
779
  $url = $this->get_current_permalink();
780
  break;
781
 
782
- case 'homepage' :
783
  $url = $this->get_homepage_permalink();
784
  break;
785
 
786
- case 'create' :
787
  $url = $this->create_canonical_url( $args );
788
  break;
789
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
409
  * @since 3.0.0 1: Now only returns one crumb.
410
  * 2: Now listens to primary term ID.
411
  *
412
+ * @return string LD+JSON breadcrumbs script for Posts on success. Empty string on failure.
413
  */
414
  public function get_ld_json_breadcrumbs_post() {
415
 
416
  $output = '';
417
 
418
+ $post_id = $this->get_the_real_ID();
419
+ $post_type = \get_post_type( $post_id );
420
  $taxonomies = $this->get_hierarchical_taxonomies_as( 'names', \get_post_type( $post_id ) );
421
 
422
  /**
572
  *
573
  * @since 2.9.3
574
  *
575
+ * @param array $cats The breadcrumb trees, with the key as parent.
576
  * @param array $previous_tree A previous set tree to compare to, if set.
577
  * @return array Trees in order.
578
  */
579
+ protected function build_ld_json_breadcrumb_trees( $cats, array $previous_tree = [] ) {
580
 
581
  $trees = $previous_tree;
582
 
583
+ foreach ( $cats as $parent => $kitten ) {
584
  if ( empty( $kitten ) ) {
585
  //* Final cat.
586
  $trees[] = $parent;
647
  * Generates homepage LD+JSON breadcrumb.
648
  *
649
  * @since 2.9.3
650
+ * @since 3.2.2: 1. The title now works for the home page as blog.
651
+ * 2. The image has been disabled for the home page as blog.
652
+ * - I couldn't fix it without evading the API, which is bad.
653
  * @staticvar array $crumb
654
  *
655
  * @return array The HomePage crumb entry.
657
  public function get_ld_json_breadcrumb_home_crumb() {
658
 
659
  static $crumb = null;
 
660
  if ( isset( $crumb ) )
661
  return $crumb;
662
 
777
  public function get_schema_url_id( $type, $from, $args = [] ) {
778
 
779
  switch ( $from ) {
780
+ case 'currentpage':
781
  $url = $this->get_current_permalink();
782
  break;
783
 
784
+ case 'homepage':
785
  $url = $this->get_homepage_permalink();
786
  break;
787
 
788
+ case 'create':
789
  $url = $this->create_canonical_url( $args );
790
  break;
791
 
inc/classes/generate-title.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -36,6 +36,7 @@ class Generate_Title extends Generate_Description {
36
  * Returns the meta title from custom fields. Falls back to autogenerated title.
37
  *
38
  * @since 3.1.0
 
39
  * @uses $this->get_custom_field_title()
40
  * @uses $this->get_generated_title()
41
  *
@@ -46,8 +47,8 @@ class Generate_Title extends Generate_Description {
46
  */
47
  public function get_title( $args = null, $escape = true ) {
48
 
49
- $title = $this->get_custom_field_title( $args )
50
- ?: $this->get_generated_title( $args, false );
51
 
52
  return $escape ? $this->escape_title( $title ) : $title;
53
  }
@@ -153,7 +154,7 @@ class Generate_Title extends Generate_Description {
153
  public function get_twitter_title( $args = null, $escape = true ) {
154
 
155
  $title = $this->get_twitter_title_from_custom_field( $args, false )
156
- ?: $this->get_generated_twitter_title( $args, false );
157
 
158
  return $escape ? $this->escape_title( $title ) : $title;
159
  }
@@ -186,6 +187,7 @@ class Generate_Title extends Generate_Description {
186
  * Falls back to Open Graph title.
187
  *
188
  * @since 3.1.0
 
189
  * @see $this->get_twitter_title()
190
  * @see $this->get_twitter_title_from_custom_field()
191
  *
@@ -196,14 +198,21 @@ class Generate_Title extends Generate_Description {
196
  $title = '';
197
 
198
  if ( $this->is_real_front_page() ) {
199
- $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_option( 'homepage_og_title' ) ?: '';
200
- }
201
- if ( ! $title ) {
202
- if ( $this->is_singular() ) {
203
- $title = $this->get_custom_field( '_twitter_title' )
204
  ?: $this->get_custom_field( '_open_graph_title' )
205
- ?: '';
 
 
 
 
206
  }
 
 
 
 
207
  }
208
 
209
  return $title;
@@ -214,6 +223,7 @@ class Generate_Title extends Generate_Description {
214
  * Falls back to Open Graph title.
215
  *
216
  * @since 3.1.0
 
217
  * @see $this->get_twitter_title()
218
  * @see $this->get_twitter_title_from_custom_field()
219
  *
@@ -227,13 +237,20 @@ class Generate_Title extends Generate_Description {
227
  if ( $args['taxonomy'] ) {
228
  $title = '';
229
  } else {
230
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
231
- $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_option( 'homepage_og_title' ) ?: '';
232
- }
233
- if ( ! $title ) {
 
 
 
 
 
 
 
234
  $title = $this->get_custom_field( '_twitter_title', $args['id'] )
235
  ?: $this->get_custom_field( '_open_graph_title', $args['id'] )
236
- ?: '';
237
  }
238
  }
239
 
@@ -274,7 +291,7 @@ class Generate_Title extends Generate_Description {
274
  public function get_open_graph_title( $args = null, $escape = true ) {
275
 
276
  $title = $this->get_open_graph_title_from_custom_field( $args, false )
277
- ?: $this->get_generated_open_graph_title( $args, false );
278
 
279
  return $escape ? $this->escape_title( $title ) : $title;
280
  }
@@ -307,6 +324,7 @@ class Generate_Title extends Generate_Description {
307
  * Falls back to meta title.
308
  *
309
  * @since 3.1.0
 
310
  * @see $this->get_open_graph_title()
311
  * @see $this->get_open_graph_title_from_custom_field()
312
  *
@@ -317,12 +335,15 @@ class Generate_Title extends Generate_Description {
317
  $title = '';
318
 
319
  if ( $this->is_real_front_page() ) {
320
- $title = $this->get_option( 'homepage_og_title' ) ?: '';
321
- }
322
- if ( ! $title ) {
323
- if ( $this->is_singular() ) {
324
- $title = $this->get_custom_field( '_open_graph_title' ) ?: '';
 
325
  }
 
 
326
  }
327
 
328
  return $title;
@@ -333,6 +354,7 @@ class Generate_Title extends Generate_Description {
333
  * Falls back to meta title.
334
  *
335
  * @since 3.1.0
 
336
  * @see $this->get_open_graph_title()
337
  * @see $this->get_open_graph_title_from_custom_field()
338
  *
@@ -346,10 +368,13 @@ class Generate_Title extends Generate_Description {
346
  if ( $args['taxonomy'] ) {
347
  $title = '';
348
  } else {
349
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
 
 
 
 
350
  $title = $this->get_option( 'homepage_og_title' ) ?: '';
351
- }
352
- if ( ! $title ) {
353
  $title = $this->get_custom_field( '_open_graph_title', $args['id'] ) ?: '';
354
  }
355
  }
@@ -405,6 +430,7 @@ class Generate_Title extends Generate_Description {
405
  * Gets a custom title, based on current query, without additions or prefixes.
406
  *
407
  * @since 3.1.0
 
408
  * @internal
409
  * @see $this->get_raw_custom_field_title()
410
  *
@@ -415,15 +441,18 @@ class Generate_Title extends Generate_Description {
415
  $title = '';
416
 
417
  if ( $this->is_real_front_page() ) {
418
- $title = $this->get_option( 'homepage_title' ) ?: '';
419
- }
420
- if ( ! $title ) {
421
- if ( $this->is_singular() ) {
422
- $title = $this->get_custom_field( '_genesis_title' ) ?: '';
423
- } elseif ( $this->is_term_meta_capable() ) {
424
- $data = $this->get_term_meta( $this->get_the_real_ID() );
425
- $title = ! empty( $data['doctitle'] ) ? $data['doctitle'] : '';
426
  }
 
 
 
 
 
427
  }
428
 
429
  return $title;
@@ -434,6 +463,7 @@ class Generate_Title extends Generate_Description {
434
  *
435
  * @since 3.1.0
436
  * @since 3.1.4 Now uses the 'id' to get custom singular title.
 
437
  * @internal
438
  * @see $this->get_raw_custom_field_title()
439
  *
@@ -444,14 +474,18 @@ class Generate_Title extends Generate_Description {
444
  $title = '';
445
 
446
  if ( $args['taxonomy'] ) {
447
- // $term = \get_term( $args['id'], $args['taxonomy'] ); // redundant
448
- $data = $this->get_term_meta( $args['id'] );
449
- $title = ! empty( $data['doctitle'] ) ? $data['doctitle'] : '';
450
  } else {
451
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
 
 
 
 
452
  $title = $this->get_option( 'homepage_title' ) ?: '';
 
 
453
  }
454
- $title = $title ?: $this->get_custom_field( '_genesis_title', $args['id'] ) ?: '';
455
  }
456
 
457
  return $title;
@@ -509,7 +543,7 @@ class Generate_Title extends Generate_Description {
509
  // Reset filters.
510
  $filtered = [];
511
  } else {
512
- $filters = [ 'single_post_title', 'single_cat_title', 'single_tag_title' ];
513
  /**
514
  * Texturization happens when outputting and saving the title; however,
515
  * we want the raw title, so we won't find unexplainable issues later.
@@ -592,7 +626,7 @@ class Generate_Title extends Generate_Description {
592
  if ( $args['taxonomy'] ) {
593
  $title = $this->get_generated_archive_title( \get_term( $args['id'], $args['taxonomy'] ) );
594
  } else {
595
- if ( $this->is_front_page_by_id( $args['id'] ) ) {
596
  $title = $this->get_static_front_page_title();
597
  } else {
598
  $title = $this->get_generated_single_post_title( $args['id'] );
@@ -648,6 +682,7 @@ class Generate_Title extends Generate_Description {
648
  return $title;
649
 
650
  $use_prefix = $this->use_generated_archive_prefix();
 
651
  $_tax = isset( $term->taxonomy ) ? $term->taxonomy : '';
652
 
653
  if ( ! $_query ) {
@@ -918,22 +953,47 @@ class Generate_Title extends Generate_Description {
918
  * @since 3.1.0
919
  * @since 3.1.2 Added strict taxonomical check.
920
  * @since 3.1.3 Fixed conditional logic.
 
 
921
  *
922
  * @param string $title The title. Passed by reference.
923
- * @param array|null $args The query arguments. Leave null to autodetermine query.
 
924
  */
925
  public function merge_title_branding( &$title, $args = null ) {
926
 
927
  if ( null === $args ) {
928
- $id = $this->get_the_real_ID();
929
- $tax = $this->get_current_taxonomy();
930
  } else {
931
  $this->fix_generation_args( $args );
932
- $id = $args['id'];
933
- $tax = $args['taxonomy'];
934
  }
935
 
936
- if ( ! $tax && $this->is_front_page_by_id( $id ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
937
  $addition = $this->get_home_page_tagline();
938
  //? Brilliant. TODO FIXME: Do an "upgrade" of this option at a 3.1.2+ release, switching title with additions in the settings description.
939
  $seplocation = 'left' === $this->get_home_title_seplocation() ? 'right' : 'left';
@@ -942,17 +1002,31 @@ class Generate_Title extends Generate_Description {
942
  $seplocation = $this->get_title_seplocation();
943
  }
944
 
945
- $title = trim( $title );
946
- $addition = trim( $addition );
947
- $sep = $this->get_title_separator();
948
 
949
- if ( $addition && $title ) {
950
- if ( 'left' === $seplocation ) {
951
- $title = "$addition $sep $title";
952
- } else {
953
- $title = "$title $sep $addition";
954
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
955
  }
 
 
956
  }
957
 
958
  /**
@@ -986,7 +1060,7 @@ class Generate_Title extends Generate_Description {
986
  *
987
  * @since 3.1.0
988
  * @since 3.1.2 Added strict taxonomical checks for title protection.
989
- * @since 3.1.3 Fixed conditional logic.
990
  * @see $this->merge_title_prefixes()
991
  *
992
  * @param string $title The title. Passed by reference.
@@ -1021,8 +1095,9 @@ class Generate_Title extends Generate_Description {
1021
  * Default 'Private: %s'.
1022
  * @param WP_Post $post Current post object.
1023
  */
 
1024
  $protected_title_format = (string) \apply_filters( 'protected_title_format', \__( 'Protected: %s', 'default' ), $post );
1025
- $title = sprintf( $protected_title_format, $title );
1026
  } elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) {
1027
  /**
1028
  * Filters the text prepended to the post title of private posts.
@@ -1035,8 +1110,9 @@ class Generate_Title extends Generate_Description {
1035
  * Default 'Private: %s'.
1036
  * @param WP_Post $post Current post object.
1037
  */
 
1038
  $private_title_format = (string) \apply_filters( 'private_title_format', \__( 'Private: %s', 'default' ), $post );
1039
- $title = sprintf( $private_title_format, $title );
1040
  }
1041
  }
1042
 
@@ -1093,7 +1169,10 @@ class Generate_Title extends Generate_Description {
1093
  * @since 3.1.0
1094
  * @since 3.1.2: 1. Added filter.
1095
  * 2. Added strict taxonomical check.
 
1096
  * @see $this->merge_title_branding()
 
 
1097
  *
1098
  * @param array|null $args The query arguments. Accepts 'id' and 'taxonomy'.
1099
  * Leave null to autodetermine query.
@@ -1101,30 +1180,66 @@ class Generate_Title extends Generate_Description {
1101
  */
1102
  public function use_title_branding( $args = null ) {
1103
 
1104
- $id = isset( $args['id'] ) ? $args['id'] : $this->get_the_real_ID();
1105
- $taxonomy = null === $args ? $this->get_current_taxonomy()
1106
- : ( isset( $args['taxonomy'] ) ? $args['taxonomy'] : '' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1107
 
1108
- $use = true;
 
 
 
 
 
 
1109
 
1110
- if ( $taxonomy ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1111
  $use = ! $this->get_option( 'title_rem_additions' );
1112
  } else {
1113
- if ( $this->is_front_page_by_id( $id ) ) {
1114
  $use = $this->use_home_page_title_tagline();
1115
- } elseif ( ! $this->use_singular_title_branding( $id ) ) {
1116
  $use = false;
1117
  } else {
1118
  $use = ! $this->get_option( 'title_rem_additions' );
1119
  }
1120
  }
1121
 
1122
- /**
1123
- * @since 3.1.2
1124
- * @param bool $use
1125
- * @param array|null $args
1126
- */
1127
- return \apply_filters_ref_array( 'the_seo_framework_use_title_branding', [ $use, $args ] );
1128
  }
1129
 
1130
  /**
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
36
  * Returns the meta title from custom fields. Falls back to autogenerated title.
37
  *
38
  * @since 3.1.0
39
+ * @since 3.2.2 No longer double-escapes the custom field title.
40
  * @uses $this->get_custom_field_title()
41
  * @uses $this->get_generated_title()
42
  *
47
  */
48
  public function get_title( $args = null, $escape = true ) {
49
 
50
+ $title = $this->get_custom_field_title( $args, false )
51
+ ?: $this->get_generated_title( $args, false ); // precision alignment ok.
52
 
53
  return $escape ? $this->escape_title( $title ) : $title;
54
  }
154
  public function get_twitter_title( $args = null, $escape = true ) {
155
 
156
  $title = $this->get_twitter_title_from_custom_field( $args, false )
157
+ ?: $this->get_generated_twitter_title( $args, false ); // precision alignment ok.
158
 
159
  return $escape ? $this->escape_title( $title ) : $title;
160
  }
187
  * Falls back to Open Graph title.
188
  *
189
  * @since 3.1.0
190
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
191
  * @see $this->get_twitter_title()
192
  * @see $this->get_twitter_title_from_custom_field()
193
  *
198
  $title = '';
199
 
200
  if ( $this->is_real_front_page() ) {
201
+ if ( $this->is_static_frontpage() ) {
202
+ $title = $this->get_option( 'homepage_twitter_title' )
203
+ ?: $this->get_custom_field( '_twitter_title' )
204
+ ?: $this->get_option( 'homepage_og_title' )
 
205
  ?: $this->get_custom_field( '_open_graph_title' )
206
+ ?: ''; // precision alignment ok.
207
+ } else {
208
+ $title = $this->get_option( 'homepage_twitter_title' )
209
+ ?: $this->get_option( 'homepage_og_title' )
210
+ ?: ''; // precision alignment ok.
211
  }
212
+ } elseif ( $this->is_singular() ) {
213
+ $title = $this->get_custom_field( '_twitter_title' )
214
+ ?: $this->get_custom_field( '_open_graph_title' )
215
+ ?: ''; // precision alignment ok.
216
  }
217
 
218
  return $title;
223
  * Falls back to Open Graph title.
224
  *
225
  * @since 3.1.0
226
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
227
  * @see $this->get_twitter_title()
228
  * @see $this->get_twitter_title_from_custom_field()
229
  *
237
  if ( $args['taxonomy'] ) {
238
  $title = '';
239
  } else {
240
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
241
+ $title = $this->get_option( 'homepage_twitter_title' )
242
+ ?: $this->get_custom_field( '_twitter_title', $args['id'] )
243
+ ?: $this->get_option( 'homepage_og_title' )
244
+ ?: $this->get_custom_field( '_open_graph_title', $args['id'] )
245
+ ?: ''; // precision alignment ok.
246
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
247
+ $title = $this->get_option( 'homepage_twitter_title' )
248
+ ?: $this->get_option( 'homepage_og_title' )
249
+ ?: ''; // precision alignment ok.
250
+ } else {
251
  $title = $this->get_custom_field( '_twitter_title', $args['id'] )
252
  ?: $this->get_custom_field( '_open_graph_title', $args['id'] )
253
+ ?: ''; // precision alignment ok.
254
  }
255
  }
256
 
291
  public function get_open_graph_title( $args = null, $escape = true ) {
292
 
293
  $title = $this->get_open_graph_title_from_custom_field( $args, false )
294
+ ?: $this->get_generated_open_graph_title( $args, false ); // precision alignment ok.
295
 
296
  return $escape ? $this->escape_title( $title ) : $title;
297
  }
324
  * Falls back to meta title.
325
  *
326
  * @since 3.1.0
327
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
328
  * @see $this->get_open_graph_title()
329
  * @see $this->get_open_graph_title_from_custom_field()
330
  *
335
  $title = '';
336
 
337
  if ( $this->is_real_front_page() ) {
338
+ if ( $this->is_static_frontpage() ) {
339
+ $title = $this->get_option( 'homepage_og_title' )
340
+ ?: $this->get_custom_field( '_open_graph_title' )
341
+ ?: ''; // precision alignment ok.
342
+ } else {
343
+ $title = $this->get_option( 'homepage_og_title' ) ?: '';
344
  }
345
+ } elseif ( $this->is_singular() ) {
346
+ $title = $this->get_custom_field( '_open_graph_title' ) ?: '';
347
  }
348
 
349
  return $title;
354
  * Falls back to meta title.
355
  *
356
  * @since 3.1.0
357
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
358
  * @see $this->get_open_graph_title()
359
  * @see $this->get_open_graph_title_from_custom_field()
360
  *
368
  if ( $args['taxonomy'] ) {
369
  $title = '';
370
  } else {
371
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
372
+ $title = $this->get_option( 'homepage_og_title' )
373
+ ?: $this->get_custom_field( '_open_graph_title', $args['id'] )
374
+ ?: ''; // Precision alignment ok.
375
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
376
  $title = $this->get_option( 'homepage_og_title' ) ?: '';
377
+ } else {
 
378
  $title = $this->get_custom_field( '_open_graph_title', $args['id'] ) ?: '';
379
  }
380
  }
430
  * Gets a custom title, based on current query, without additions or prefixes.
431
  *
432
  * @since 3.1.0
433
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
434
  * @internal
435
  * @see $this->get_raw_custom_field_title()
436
  *
441
  $title = '';
442
 
443
  if ( $this->is_real_front_page() ) {
444
+ if ( $this->is_static_frontpage() ) {
445
+ $title = $this->get_option( 'homepage_title' )
446
+ ?: $this->get_custom_field( '_genesis_title' )
447
+ ?: ''; // precision alignment ok.
448
+ } else {
449
+ $title = $this->get_option( 'homepage_title' ) ?: '';
 
 
450
  }
451
+ } elseif ( $this->is_singular() ) {
452
+ $title = $this->get_custom_field( '_genesis_title' ) ?: '';
453
+ } elseif ( $this->is_term_meta_capable() ) {
454
+ $_data = $this->get_term_meta( $this->get_the_real_ID() );
455
+ $title = ! empty( $_data['doctitle'] ) ? $_data['doctitle'] : '';
456
  }
457
 
458
  return $title;
463
  *
464
  * @since 3.1.0
465
  * @since 3.1.4 Now uses the 'id' to get custom singular title.
466
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
467
  * @internal
468
  * @see $this->get_raw_custom_field_title()
469
  *
474
  $title = '';
475
 
476
  if ( $args['taxonomy'] ) {
477
+ $_data = $this->get_term_meta( $args['id'] );
478
+ $title = ! empty( $_data['doctitle'] ) ? $_data['doctitle'] : '';
 
479
  } else {
480
+ if ( $this->is_static_frontpage( $args['id'] ) ) {
481
+ $title = $this->get_option( 'homepage_title' )
482
+ ?: $this->get_custom_field( '_genesis_title', $args['id'] )
483
+ ?: ''; // precision alignment ok.
484
+ } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) {
485
  $title = $this->get_option( 'homepage_title' ) ?: '';
486
+ } else {
487
+ $title = $this->get_custom_field( '_genesis_title', $args['id'] ) ?: '';
488
  }
 
489
  }
490
 
491
  return $title;
543
  // Reset filters.
544
  $filtered = [];
545
  } else {
546
+ $filters = [ 'single_post_title', 'single_cat_title', 'single_tag_title' ];
547
  /**
548
  * Texturization happens when outputting and saving the title; however,
549
  * we want the raw title, so we won't find unexplainable issues later.
626
  if ( $args['taxonomy'] ) {
627
  $title = $this->get_generated_archive_title( \get_term( $args['id'], $args['taxonomy'] ) );
628
  } else {
629
+ if ( $this->is_real_front_page_by_id( $args['id'] ) ) {
630
  $title = $this->get_static_front_page_title();
631
  } else {
632
  $title = $this->get_generated_single_post_title( $args['id'] );
682
  return $title;
683
 
684
  $use_prefix = $this->use_generated_archive_prefix();
685
+
686
  $_tax = isset( $term->taxonomy ) ? $term->taxonomy : '';
687
 
688
  if ( ! $_query ) {
953
  * @since 3.1.0
954
  * @since 3.1.2 Added strict taxonomical check.
955
  * @since 3.1.3 Fixed conditional logic.
956
+ * @uses $this->get_title_branding_from_query()
957
+ * @uses $this->get_title_branding_from_args()
958
  *
959
  * @param string $title The title. Passed by reference.
960
+ * @param array|null $args The query arguments. Accepts 'id' and 'taxonomy'.
961
+ * Leave null to autodetermine query.
962
  */
963
  public function merge_title_branding( &$title, $args = null ) {
964
 
965
  if ( null === $args ) {
966
+ $data = $this->get_title_branding_from_query();
 
967
  } else {
968
  $this->fix_generation_args( $args );
969
+ $data = $this->get_title_branding_from_args( $args );
 
970
  }
971
 
972
+ $title = trim( $title );
973
+ $addition = trim( $data['addition'] );
974
+ $seplocation = $data['seplocation'];
975
+ $sep = $this->get_title_separator();
976
+
977
+ if ( $addition && $title ) {
978
+ if ( 'left' === $seplocation ) {
979
+ $title = "$addition $sep $title";
980
+ } else {
981
+ $title = "$title $sep $addition";
982
+ }
983
+ }
984
+ }
985
+
986
+ /**
987
+ * Returns the addition and seplocation from query.
988
+ *
989
+ * @since 3.2.2
990
+ * @see $this->merge_title_branding();
991
+ *
992
+ * @return array { 'addition', 'seplocation' }
993
+ */
994
+ protected function get_title_branding_from_query() {
995
+
996
+ if ( $this->is_real_front_page() ) {
997
  $addition = $this->get_home_page_tagline();
998
  //? Brilliant. TODO FIXME: Do an "upgrade" of this option at a 3.1.2+ release, switching title with additions in the settings description.
999
  $seplocation = 'left' === $this->get_home_title_seplocation() ? 'right' : 'left';
1002
  $seplocation = $this->get_title_seplocation();
1003
  }
1004
 
1005
+ return compact( 'addition', 'seplocation' );
1006
+ }
 
1007
 
1008
+
1009
+ /**
1010
+ * Returns the addition and seplocation from arguments.
1011
+ *
1012
+ * @since 3.2.2
1013
+ * @see $this->merge_title_branding();
1014
+ *
1015
+ * @param array $args The query arguments. Accepts 'id' and 'taxonomy'.
1016
+ * @return array { 'addition', 'seplocation' }
1017
+ */
1018
+ protected function get_title_branding_from_args( array $args ) {
1019
+
1020
+ if ( ! $args['taxonomy'] && $this->is_real_front_page_by_id( $args['id'] ) ) {
1021
+ $addition = $this->get_home_page_tagline();
1022
+ //? Brilliant. TODO FIXME: Do an "upgrade" of this option at a 3.1.2+ release, switching title with additions in the settings description.
1023
+ $seplocation = 'left' === $this->get_home_title_seplocation() ? 'right' : 'left';
1024
+ } else {
1025
+ $addition = $this->get_blogname();
1026
+ $seplocation = $this->get_title_seplocation();
1027
  }
1028
+
1029
+ return compact( 'addition', 'seplocation' );
1030
  }
1031
 
1032
  /**
1060
  *
1061
  * @since 3.1.0
1062
  * @since 3.1.2 Added strict taxonomical checks for title protection.
1063
+ * @since 3.1.3 Fixed conditional logic.
1064
  * @see $this->merge_title_prefixes()
1065
  *
1066
  * @param string $title The title. Passed by reference.
1095
  * Default 'Private: %s'.
1096
  * @param WP_Post $post Current post object.
1097
  */
1098
+ // phpcs:ignore -- WordPress doesn't have a comment, either.
1099
  $protected_title_format = (string) \apply_filters( 'protected_title_format', \__( 'Protected: %s', 'default' ), $post );
1100
+ $title = sprintf( $protected_title_format, $title );
1101
  } elseif ( isset( $post->post_status ) && 'private' === $post->post_status ) {
1102
  /**
1103
  * Filters the text prepended to the post title of private posts.
1110
  * Default 'Private: %s'.
1111
  * @param WP_Post $post Current post object.
1112
  */
1113
+ // phpcs:ignore -- WordPress doesn't have a comment, either.
1114
  $private_title_format = (string) \apply_filters( 'private_title_format', \__( 'Private: %s', 'default' ), $post );
1115
+ $title = sprintf( $private_title_format, $title );
1116
  }
1117
  }
1118
 
1169
  * @since 3.1.0
1170
  * @since 3.1.2: 1. Added filter.
1171
  * 2. Added strict taxonomical check.
1172
+ * @since 3.2.2 Now differentiates from query and parameter input.
1173
  * @see $this->merge_title_branding()
1174
+ * @uses $this->use_title_branding_from_query()
1175
+ * @uses $this->use_title_branding_from_args()
1176
  *
1177
  * @param array|null $args The query arguments. Accepts 'id' and 'taxonomy'.
1178
  * Leave null to autodetermine query.
1180
  */
1181
  public function use_title_branding( $args = null ) {
1182
 
1183
+ if ( null === $args ) {
1184
+ $use = $this->use_title_branding_from_query();
1185
+ } else {
1186
+ $this->fix_generation_args( $args );
1187
+ $use = $this->use_title_branding_from_args( $args );
1188
+ }
1189
+
1190
+ /**
1191
+ * @since 3.1.2
1192
+ * @param bool $use
1193
+ * @param array|null $args
1194
+ */
1195
+ return \apply_filters_ref_array( 'the_seo_framework_use_title_branding', [ $use, $args ] );
1196
+ }
1197
+
1198
+ /**
1199
+ * Determines whether to add or remove title branding additions in the query.
1200
+ *
1201
+ * @since 3.2.2
1202
+ * @see $this->use_title_branding()
1203
+ *
1204
+ * @return bool
1205
+ */
1206
+ protected function use_title_branding_from_query() {
1207
 
1208
+ if ( $this->is_real_front_page() ) {
1209
+ $use = $this->use_home_page_title_tagline();
1210
+ } elseif ( $this->is_singular() && ! $this->use_singular_title_branding( $this->get_the_real_ID() ) ) {
1211
+ $use = false;
1212
+ } else {
1213
+ $use = ! $this->get_option( 'title_rem_additions' );
1214
+ }
1215
 
1216
+ return $use;
1217
+ }
1218
+
1219
+ /**
1220
+ * Determines whether to add or remove title branding additions from provided arguments.
1221
+ *
1222
+ * @since 3.2.2
1223
+ * @see $this->use_title_branding()
1224
+ *
1225
+ * @param array $args The query arguments. Accepts 'id' and 'taxonomy'.
1226
+ * @return bool
1227
+ */
1228
+ protected function use_title_branding_from_args( array $args ) {
1229
+
1230
+ if ( $args['taxonomy'] ) {
1231
  $use = ! $this->get_option( 'title_rem_additions' );
1232
  } else {
1233
+ if ( $this->is_real_front_page_by_id( $args['id'] ) ) {
1234
  $use = $this->use_home_page_title_tagline();
1235
+ } elseif ( ! $this->use_singular_title_branding( $args['id'] ) ) {
1236
  $use = false;
1237
  } else {
1238
  $use = ! $this->get_option( 'title_rem_additions' );
1239
  }
1240
  }
1241
 
1242
+ return $use;
 
 
 
 
 
1243
  }
1244
 
1245
  /**
inc/classes/generate-url.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -118,10 +118,10 @@ class Generate_Url extends Generate_Title {
118
  if ( $args ) {
119
  //= See $this->create_canonical_url().
120
  $canonical_url = $this->build_canonical_url( $args );
121
- $query = false;
122
  } else {
123
  $canonical_url = $this->generate_canonical_url();
124
- $query = true;
125
  }
126
 
127
  if ( ! $canonical_url )
@@ -142,6 +142,7 @@ class Generate_Url extends Generate_Title {
142
  * Builds canonical URL from input arguments.
143
  *
144
  * @since 3.0.0
 
145
  * @see $this->create_canonical_url()
146
  *
147
  * @param array $args. Use $this->create_canonical_url().
@@ -157,16 +158,18 @@ class Generate_Url extends Generate_Title {
157
  if ( $taxonomy ) {
158
  $canonical_url = $this->get_taxonomial_canonical_url( $id, $taxonomy );
159
  } else {
160
- if ( $get_custom_field ) {
161
- $canonical_url = $this->get_singular_custom_canonical_url( $id );
162
- }
163
-
164
- if ( ! $canonical_url ) {
165
- if ( ! $id || ( $this->has_page_on_front() && $this->is_front_page_by_id( $id ) ) ) {
166
- $canonical_url = $this->get_home_canonical_url();
167
- } elseif ( $id ) {
168
- $canonical_url = $this->get_singular_canonical_url( $id );
 
169
  }
 
170
  }
171
  }
172
 
@@ -193,6 +196,7 @@ class Generate_Url extends Generate_Title {
193
  $url = $this->get_home_canonical_url();
194
  } elseif ( $this->is_singular() ) {
195
  $url = $this->get_singular_custom_canonical_url( $id );
 
196
  if ( ! $url )
197
  $url = $this->get_singular_canonical_url( $id );
198
  } elseif ( $this->is_archive() ) {
@@ -415,18 +419,18 @@ class Generate_Url extends Generate_Title {
415
  //* Determine whether the input matches query.
416
  $_paginate = true;
417
  switch ( $_get ) {
418
- case 'day' :
419
- $_day = \get_query_var( 'day' );
420
  $_paginate = $_paginate && $_day == $day; // loose comparison OK.
421
  // No break. Get month too.
422
 
423
- case 'month' :
424
- $_month = \get_query_var( 'monthnum' );
425
  $_paginate = $_paginate && $_month == $month; // loose comparison OK.
426
  // No break. Get year too.
427
 
428
- case 'year' :
429
- $_year = \get_query_var( 'year' );
430
  $_paginate = $_paginate && $_year == $year; // loose comparison OK.
431
  break;
432
  }
@@ -488,16 +492,16 @@ class Generate_Url extends Generate_Title {
488
  return $scheme;
489
 
490
  switch ( $this->get_option( 'canonical_scheme' ) ) :
491
- case 'https' :
492
  $scheme = 'https';
493
  break;
494
 
495
- case 'http' :
496
  $scheme = 'http';
497
  break;
498
 
499
  default:
500
- case 'automatic' :
501
  $scheme = $this->is_ssl() ? 'https' : 'http';
502
  break;
503
  endswitch;
@@ -554,6 +558,7 @@ class Generate_Url extends Generate_Title {
554
 
555
  if ( 'relative' === $scheme ) {
556
  $url = ltrim( preg_replace( '#^\w+://[^/]*#', '', $url ) );
 
557
  if ( '' !== $url && '/' === $url[0] )
558
  $url = '/' . ltrim( $url, "/ \t\n\r\0\x0B" );
559
  } else {
@@ -691,7 +696,7 @@ class Generate_Url extends Generate_Title {
691
  } elseif ( $this->is_date() && isset( $GLOBALS['wp_query']->query ) ) {
692
  // FIXME: Core Report: WP doesn't accept paged parameters w/ date parameters. It'll lead to the homepage.
693
  $_query = $GLOBALS['wp_query']->query;
694
- $_date = [
695
  'y' => isset( $_query['year'] ) ? $_query['year'] : '',
696
  'm' => isset( $_query['monthnum'] ) ? $_query['monthnum'] : '',
697
  'd' => isset( $_query['day'] ) ? $_query['day'] : '',
@@ -776,7 +781,7 @@ class Generate_Url extends Generate_Title {
776
  if ( $this->is_singular() && ! $this->is_singular_archive() && $this->is_multipage() ) {
777
  $_run = $this->is_real_front_page()
778
  ? $this->get_option( 'prev_next_frontpage' )
779
- : $this->get_option( 'prev_next_posts' );
780
 
781
  if ( ! $_run ) goto end;
782
 
@@ -786,7 +791,7 @@ class Generate_Url extends Generate_Title {
786
  } elseif ( $this->is_archive() || $this->is_singular_archive() || $this->is_search() ) {
787
  $_run = $this->is_real_front_page()
788
  ? $this->get_option( 'prev_next_frontpage' )
789
- : $this->get_option( 'prev_next_archives' );
790
 
791
  if ( ! $_run ) goto end;
792
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
118
  if ( $args ) {
119
  //= See $this->create_canonical_url().
120
  $canonical_url = $this->build_canonical_url( $args );
121
+ $query = false;
122
  } else {
123
  $canonical_url = $this->generate_canonical_url();
124
+ $query = true;
125
  }
126
 
127
  if ( ! $canonical_url )
142
  * Builds canonical URL from input arguments.
143
  *
144
  * @since 3.0.0
145
+ * @since 3.2.2 Now tests for the home page as page prior getting custom field data.
146
  * @see $this->create_canonical_url()
147
  *
148
  * @param array $args. Use $this->create_canonical_url().
158
  if ( $taxonomy ) {
159
  $canonical_url = $this->get_taxonomial_canonical_url( $id, $taxonomy );
160
  } else {
161
+ if ( $this->is_static_frontpage( $id ) ) {
162
+ if ( $get_custom_field ) {
163
+ $canonical_url = $this->get_singular_custom_canonical_url( $id );
164
+ }
165
+ $canonical_url = $canonical_url ?: $this->get_home_canonical_url();
166
+ } elseif ( $this->is_real_front_page_by_id( $id ) ) {
167
+ $canonical_url = $this->get_home_canonical_url();
168
+ } elseif ( $id ) {
169
+ if ( $get_custom_field ) {
170
+ $canonical_url = $this->get_singular_custom_canonical_url( $id );
171
  }
172
+ $canonical_url = $canonical_url ?: $this->get_singular_canonical_url( $id );
173
  }
174
  }
175
 
196
  $url = $this->get_home_canonical_url();
197
  } elseif ( $this->is_singular() ) {
198
  $url = $this->get_singular_custom_canonical_url( $id );
199
+
200
  if ( ! $url )
201
  $url = $this->get_singular_canonical_url( $id );
202
  } elseif ( $this->is_archive() ) {
419
  //* Determine whether the input matches query.
420
  $_paginate = true;
421
  switch ( $_get ) {
422
+ case 'day':
423
+ $_day = \get_query_var( 'day' );
424
  $_paginate = $_paginate && $_day == $day; // loose comparison OK.
425
  // No break. Get month too.
426
 
427
+ case 'month':
428
+ $_month = \get_query_var( 'monthnum' );
429
  $_paginate = $_paginate && $_month == $month; // loose comparison OK.
430
  // No break. Get year too.
431
 
432
+ case 'year':
433
+ $_year = \get_query_var( 'year' );
434
  $_paginate = $_paginate && $_year == $year; // loose comparison OK.
435
  break;
436
  }
492
  return $scheme;
493
 
494
  switch ( $this->get_option( 'canonical_scheme' ) ) :
495
+ case 'https':
496
  $scheme = 'https';
497
  break;
498
 
499
+ case 'http':
500
  $scheme = 'http';
501
  break;
502
 
503
  default:
504
+ case 'automatic':
505
  $scheme = $this->is_ssl() ? 'https' : 'http';
506
  break;
507
  endswitch;
558
 
559
  if ( 'relative' === $scheme ) {
560
  $url = ltrim( preg_replace( '#^\w+://[^/]*#', '', $url ) );
561
+
562
  if ( '' !== $url && '/' === $url[0] )
563
  $url = '/' . ltrim( $url, "/ \t\n\r\0\x0B" );
564
  } else {
696
  } elseif ( $this->is_date() && isset( $GLOBALS['wp_query']->query ) ) {
697
  // FIXME: Core Report: WP doesn't accept paged parameters w/ date parameters. It'll lead to the homepage.
698
  $_query = $GLOBALS['wp_query']->query;
699
+ $_date = [
700
  'y' => isset( $_query['year'] ) ? $_query['year'] : '',
701
  'm' => isset( $_query['monthnum'] ) ? $_query['monthnum'] : '',
702
  'd' => isset( $_query['day'] ) ? $_query['day'] : '',
781
  if ( $this->is_singular() && ! $this->is_singular_archive() && $this->is_multipage() ) {
782
  $_run = $this->is_real_front_page()
783
  ? $this->get_option( 'prev_next_frontpage' )
784
+ : $this->get_option( 'prev_next_posts' ); // precision alignment ok.
785
 
786
  if ( ! $_run ) goto end;
787
 
791
  } elseif ( $this->is_archive() || $this->is_singular_archive() || $this->is_search() ) {
792
  $_run = $this->is_real_front_page()
793
  ? $this->get_option( 'prev_next_frontpage' )
794
+ : $this->get_option( 'prev_next_archives' ); // precision alignment ok.
795
 
796
  if ( ! $_run ) goto end;
797
 
inc/classes/generate.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -42,11 +42,10 @@ class Generate extends User_Data {
42
  */
43
  protected function fix_generation_args( &$args ) {
44
  if ( is_array( $args ) ) {
45
- $defaults = [
46
  'id' => 0,
47
  'taxonomy' => '',
48
- ];
49
- $args = array_merge( $defaults, $args );
50
  } elseif ( is_numeric( $args ) ) {
51
  $args = [
52
  'id' => (int) $args,
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
42
  */
43
  protected function fix_generation_args( &$args ) {
44
  if ( is_array( $args ) ) {
45
+ $args = array_merge( [
46
  'id' => 0,
47
  'taxonomy' => '',
48
+ ], $args );
 
49
  } elseif ( is_numeric( $args ) ) {
50
  $args = [
51
  'id' => (int) $args,
inc/classes/init.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -385,7 +385,7 @@ class Init extends Query {
385
  $output = $this->object_cache_get( $cache_key );
386
  } else {
387
  $cache_key = '';
388
- $output = false;
389
  }
390
 
391
  if ( false === $output ) :
@@ -543,7 +543,7 @@ class Init extends Query {
543
  exit;
544
  }
545
 
546
- \wp_redirect( $url, $redirect_type );
547
  exit;
548
  }
549
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
385
  $output = $this->object_cache_get( $cache_key );
386
  } else {
387
  $cache_key = '';
388
+ $output = false;
389
  }
390
 
391
  if ( false === $output ) :
543
  exit;
544
  }
545
 
546
+ \wp_redirect( $url, $redirect_type ); // phpcs:ignore -- intended feature. Disable via $this->allow_external_redirect().
547
  exit;
548
  }
549
 
inc/classes/inpost.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -36,10 +36,11 @@ class Inpost extends Profile {
36
  * Defines inpost nonce name.
37
  *
38
  * @since 2.7.0
 
39
  *
40
  * @var string The nonce name.
41
  */
42
- public $inpost_nonce_name = 'tsf_inpost_seo_settings';
43
 
44
  /**
45
  * Defines inpost nonce field.
@@ -163,7 +164,7 @@ class Inpost extends Profile {
163
  if ( $this->is_front_page_by_id( $this->get_the_real_ID() ) ) {
164
  if ( $this->can_access_settings() ) {
165
  $schema = \is_rtl() ? '%2$s - %1$s' : '%1$s - %2$s';
166
- $title = sprintf(
167
  $schema,
168
  \__( 'Homepage SEO Settings', 'autodescription' ),
169
  $this->make_info(
@@ -239,7 +240,7 @@ class Inpost extends Profile {
239
  }
240
  } elseif ( isset( $object->taxonomy ) ) {
241
  //* Singular name.
242
- $type = $this->get_tax_type_label( $object->taxonomy );
243
  $is_term = true;
244
  }
245
 
@@ -331,6 +332,8 @@ class Inpost extends Profile {
331
  * @since 2.9.0
332
  */
333
  \do_action( 'the_seo_framework_pre_page_inpost_box' );
 
 
334
  $this->get_view( 'inpost/seo-settings-singular', get_defined_vars() );
335
  /**
336
  * @since 2.9.0
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
36
  * Defines inpost nonce name.
37
  *
38
  * @since 2.7.0
39
+ * @since 3.2.0 Added '_nonce' suffix.
40
  *
41
  * @var string The nonce name.
42
  */
43
+ public $inpost_nonce_name = 'tsf_inpost_seo_settings_nonce';
44
 
45
  /**
46
  * Defines inpost nonce field.
164
  if ( $this->is_front_page_by_id( $this->get_the_real_ID() ) ) {
165
  if ( $this->can_access_settings() ) {
166
  $schema = \is_rtl() ? '%2$s - %1$s' : '%1$s - %2$s';
167
+ $title = sprintf(
168
  $schema,
169
  \__( 'Homepage SEO Settings', 'autodescription' ),
170
  $this->make_info(
240
  }
241
  } elseif ( isset( $object->taxonomy ) ) {
242
  //* Singular name.
243
+ $type = $this->get_tax_type_label( $object->taxonomy );
244
  $is_term = true;
245
  }
246
 
332
  * @since 2.9.0
333
  */
334
  \do_action( 'the_seo_framework_pre_page_inpost_box' );
335
+ $this->is_gutenberg_page()
336
+ and $this->get_view( 'inpost/seo-settings-singular-gutenberg-data', get_defined_vars() );
337
  $this->get_view( 'inpost/seo-settings-singular', get_defined_vars() );
338
  /**
339
  * @since 2.9.0
inc/classes/load.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -42,9 +42,9 @@ final class Load extends Feed implements Debug_Interface {
42
  * @var bool Whether transients are enabled.
43
  * @var bool Whether script debugging is enabled.
44
  */
45
- public $the_seo_framework_debug = false,
46
- $the_seo_framework_use_transients = true,
47
- $script_debug = false;
48
 
49
  /**
50
  * Constructor, setup debug vars and then load parent constructor.
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
42
  * @var bool Whether transients are enabled.
43
  * @var bool Whether script debugging is enabled.
44
  */
45
+ public $the_seo_framework_debug = false;
46
+ public $the_seo_framework_use_transients = true;
47
+ public $script_debug = false;
48
 
49
  /**
50
  * Constructor, setup debug vars and then load parent constructor.
inc/classes/metaboxes.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -38,6 +38,7 @@ class Metaboxes extends Site_Options {
38
  *
39
  * @since 2.3.6
40
  * @since 2.6.0 Refactored.
 
41
  *
42
  * @param string $id The Nav Tab ID
43
  * @param array $tabs the tab content {
@@ -68,15 +69,15 @@ class Metaboxes extends Site_Options {
68
  $count = 1;
69
  foreach ( $tabs as $tab => $value ) :
70
  $dashicon = isset( $value['dashicon'] ) ? $value['dashicon'] : '';
71
- $name = isset( $value['name'] ) ? $value['name'] : '';
72
 
73
  printf(
74
  '<div class=tsf-tab>%s</div>',
75
  vsprintf(
76
  '<input type=radio class="tsf-tabs-radio tsf-input-not-saved" id=%1$s name="%2$s" %3$s><label for=%1$s class=tsf-nav-tab>%4$s</label>',
77
  [
78
- \esc_attr( $id . '-tab-' . $tab ),
79
- \esc_attr( $id . '-tabs' ),
80
  ( 1 === $count ? 'checked' : '' ),
81
  sprintf(
82
  '%s%s',
@@ -101,8 +102,8 @@ class Metaboxes extends Site_Options {
101
  $count = 1;
102
  foreach ( $tabs as $tab => $value ) :
103
 
104
- $the_id = $id . '-tab-' . $tab . '-content';
105
- $the_name = $id . '-tabs-content';
106
 
107
  //* Current tab for JS.
108
  $current = 1 === $count ? ' tsf-active-tab-content' : '';
@@ -113,7 +114,7 @@ class Metaboxes extends Site_Options {
113
  //* No-JS tabs.
114
  if ( $use_tabs ) :
115
  $dashicon = isset( $value['dashicon'] ) ? $value['dashicon'] : '';
116
- $name = isset( $value['name'] ) ? $value['name'] : '';
117
 
118
  ?>
119
  <div class="hide-if-js tsf-content-no-js">
@@ -311,28 +312,6 @@ class Metaboxes extends Site_Options {
311
  \do_action( 'the_seo_framework_description_metabox_after' );
312
  }
313
 
314
- /**
315
- * Description meta box general tab.
316
- *
317
- * @since 2.6.0
318
- * @since 3.1.0 Is now protected.
319
- * @see $this->description_metabox() Callback for Description Settings box.
320
- */
321
- protected function description_metabox_general_tab() {
322
- $this->get_view( 'metaboxes/description-metabox', [], 'general' );
323
- }
324
-
325
- /**
326
- * Description meta box additions tab.
327
- *
328
- * @since 2.6.0
329
- * @since 3.1.0 Is now protected.
330
- * @see $this->description_metabox() Callback for Description Settings box.
331
- */
332
- protected function description_metabox_additions_tab() {
333
- $this->get_view( 'metaboxes/description-metabox', [], 'additions' );
334
- }
335
-
336
  /**
337
  * Robots meta box on the Site SEO Settings page.
338
  *
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
38
  *
39
  * @since 2.3.6
40
  * @since 2.6.0 Refactored.
41
+ * @since 3.1.0 Now prefixes the IDs.
42
  *
43
  * @param string $id The Nav Tab ID
44
  * @param array $tabs the tab content {
69
  $count = 1;
70
  foreach ( $tabs as $tab => $value ) :
71
  $dashicon = isset( $value['dashicon'] ) ? $value['dashicon'] : '';
72
+ $name = isset( $value['name'] ) ? $value['name'] : '';
73
 
74
  printf(
75
  '<div class=tsf-tab>%s</div>',
76
  vsprintf(
77
  '<input type=radio class="tsf-tabs-radio tsf-input-not-saved" id=%1$s name="%2$s" %3$s><label for=%1$s class=tsf-nav-tab>%4$s</label>',
78
  [
79
+ \esc_attr( 'tsf-' . $id . '-tab-' . $tab ),
80
+ \esc_attr( 'tsf-' . $id . '-tabs' ),
81
  ( 1 === $count ? 'checked' : '' ),
82
  sprintf(
83
  '%s%s',
102
  $count = 1;
103
  foreach ( $tabs as $tab => $value ) :
104
 
105
+ $the_id = 'tsf-' . $id . '-tab-' . $tab . '-content';
106
+ $the_name = 'tsf-' . $id . '-tabs-content';
107
 
108
  //* Current tab for JS.
109
  $current = 1 === $count ? ' tsf-active-tab-content' : '';
114
  //* No-JS tabs.
115
  if ( $use_tabs ) :
116
  $dashicon = isset( $value['dashicon'] ) ? $value['dashicon'] : '';
117
+ $name = isset( $value['name'] ) ? $value['name'] : '';
118
 
119
  ?>
120
  <div class="hide-if-js tsf-content-no-js">
312
  \do_action( 'the_seo_framework_description_metabox_after' );
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  /**
316
  * Robots meta box on the Site SEO Settings page.
317
  *
inc/classes/post-data.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -145,20 +145,20 @@ class Post_Data extends Detect {
145
 
146
  foreach ( $data as $key => &$value ) :
147
  switch ( $key ) :
148
- case '_genesis_title' :
149
- case '_open_graph_title' :
150
- case '_twitter_title' :
151
  $value = $this->s_title_raw( $value );
152
  continue 2;
153
 
154
- case '_genesis_description' :
155
- case '_open_graph_description' :
156
- case '_twitter_description' :
157
  $value = $this->s_description_raw( $value );
158
  continue 2;
159
 
160
- case '_genesis_canonical_uri' :
161
- case '_social_image_url' :
162
  /**
163
  * Remove unwanted query parameters. They're allowed by Google, but very much rather not.
164
  * Also, they will only cause bugs.
@@ -167,22 +167,22 @@ class Post_Data extends Detect {
167
  $value = $this->s_url_query( $value );
168
  continue 2;
169
 
170
- case '_social_image_id' :
171
  //* Bound to _social_image_url.
172
  $value = $data['_social_image_url'] ? $this->s_absint( $value ) : 0;
173
  continue 2;
174
 
175
- case 'redirect' :
176
  //* Let's keep this as the output really is.
177
  $value = $this->s_redirect_url( $value );
178
  continue 2;
179
 
180
- case '_tsf_title_no_blogname' :
181
- case '_genesis_noindex' :
182
- case '_genesis_nofollow' :
183
- case '_genesis_noarchive' :
184
- case 'exclude_local_search' :
185
- case 'exclude_from_archive' :
186
  $value = $this->s_one_zero( $value );
187
  continue 2;
188
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
145
 
146
  foreach ( $data as $key => &$value ) :
147
  switch ( $key ) :
148
+ case '_genesis_title':
149
+ case '_open_graph_title':
150
+ case '_twitter_title':
151
  $value = $this->s_title_raw( $value );
152
  continue 2;
153
 
154
+ case '_genesis_description':
155
+ case '_open_graph_description':
156
+ case '_twitter_description':
157
  $value = $this->s_description_raw( $value );
158
  continue 2;
159
 
160
+ case '_genesis_canonical_uri':
161
+ case '_social_image_url':
162
  /**
163
  * Remove unwanted query parameters. They're allowed by Google, but very much rather not.
164
  * Also, they will only cause bugs.
167
  $value = $this->s_url_query( $value );
168
  continue 2;
169
 
170
+ case '_social_image_id':
171
  //* Bound to _social_image_url.
172
  $value = $data['_social_image_url'] ? $this->s_absint( $value ) : 0;
173
  continue 2;
174
 
175
+ case 'redirect':
176
  //* Let's keep this as the output really is.
177
  $value = $this->s_redirect_url( $value );
178
  continue 2;
179
 
180
+ case '_tsf_title_no_blogname':
181
+ case '_genesis_noindex':
182
+ case '_genesis_nofollow':
183
+ case '_genesis_noarchive':
184
+ case 'exclude_local_search':
185
+ case 'exclude_from_archive':
186
  $value = $this->s_one_zero( $value );
187
  continue 2;
188
 
inc/classes/profile.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -115,7 +115,7 @@ class Profile extends Doing_It_Right {
115
  \check_admin_referer( 'update-user_' . $user_id );
116
  if ( ! \current_user_can( 'edit_user', $user_id ) ) return;
117
 
118
- if ( empty( $_POST ) )
119
  return;
120
 
121
  $user = new \WP_User( $user_id );
@@ -123,14 +123,13 @@ class Profile extends Doing_It_Right {
123
  if ( ! $user->has_cap( 'publish_posts' ) )
124
  return;
125
 
126
- $success = [];
127
  $defaults = $this->get_default_user_data();
128
 
129
  foreach ( $this->profile_settings->keys as $option => $post_key ) {
130
- if ( isset( $_POST[ $post_key ] ) ) { // CSRF ok: profile_settings->keys are static.
131
- //= Sanitizes value from $_POST.
132
- $value = $this->{$this->profile_settings->sanitation[ $option ]}( $_POST[ $post_key ] ) // Sanitization OK.
133
- ?: $defaults[ $option ];
134
 
135
  $success[] = (bool) $this->update_user_option( $user_id, $option, $value );
136
  }
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
115
  \check_admin_referer( 'update-user_' . $user_id );
116
  if ( ! \current_user_can( 'edit_user', $user_id ) ) return;
117
 
118
+ if ( empty( $_POST ) ) // input var OK.
119
  return;
120
 
121
  $user = new \WP_User( $user_id );
123
  if ( ! $user->has_cap( 'publish_posts' ) )
124
  return;
125
 
126
+ $success = [];
127
  $defaults = $this->get_default_user_data();
128
 
129
  foreach ( $this->profile_settings->keys as $option => $post_key ) {
130
+ if ( isset( $_POST[ $post_key ] ) ) { // Input var ok: profile_settings->keys are static.
131
+ $value = $this->{$this->profile_settings->sanitation[ $option ]}( $_POST[ $post_key ] ) // Input var & sanitization OK.
132
+ ?: $defaults[ $option ]; // precision alignment ok.
 
133
 
134
  $success[] = (bool) $this->update_user_option( $user_id, $option, $value );
135
  }
inc/classes/query.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -50,6 +50,7 @@ class Query extends Compat {
50
  * @since 3.1.0 1. Is now protected.
51
  * 2. Now asks for and passes $method.
52
  * 3. Now returns false on WP CLI.
 
53
  * @staticvar bool $cache : Always true if set.
54
  * @global \WP_Query $wp_query
55
  * @global \WP_Screen|null $current_screen
@@ -70,7 +71,8 @@ class Query extends Compat {
70
  if ( isset( $GLOBALS['wp_query']->query ) || isset( $GLOBALS['current_screen'] ) )
71
  return $cache = true;
72
 
73
- $this->do_query_error_notice( $method );
 
74
 
75
  return false;
76
  }
@@ -82,6 +84,7 @@ class Query extends Compat {
82
  *
83
  * @param string $method The original caller method.
84
  */
 
85
  protected function do_query_error_notice( $method ) {
86
 
87
  $message = "You've initiated a method that uses queries too early.";
@@ -95,16 +98,12 @@ class Query extends Compat {
95
  $this->_doing_it_wrong( \esc_html( $method ), \esc_html( $message ), '2.9.0' );
96
 
97
  //* Backtrace debugging.
98
- if ( $this->the_seo_framework_debug ) {
99
- static $_more = true;
100
- $catch_all = false;
101
- $depth = 10;
102
- if ( $catch_all || $_more ) {
103
- error_log( var_export( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $depth ), true ) );
104
- $_more = false;
105
- }
106
- }
107
- }
108
 
109
  /**
110
  * Returns the post type name from current screen.
@@ -220,9 +219,7 @@ class Query extends Compat {
220
  * @return int the ID.
221
  */
222
  public function get_the_front_page_ID() { // phpcs:ignore -- ID is capitalized because WordPress does that too: get_the_ID().
223
-
224
  static $front_id;
225
-
226
  return isset( $front_id )
227
  ? $front_id
228
  : $front_id = ( $this->has_page_on_front() ? (int) \get_option( 'page_on_front' ) : 0 );
@@ -268,13 +265,9 @@ class Query extends Compat {
268
 
269
  if ( isset( $cache ) ) return $cache;
270
 
271
- if ( $this->is_admin() ) {
272
- global $current_screen;
273
- return $cache = ! empty( $current_screen->taxonomy ) ? $current_screen->taxonomy : '';
274
- } else {
275
- $_object = \get_queried_object();
276
- return $cache = ! empty( $_object->taxonomy ) ? $_object->taxonomy : '';
277
- }
278
  }
279
 
280
  /**
@@ -372,11 +365,7 @@ class Query extends Compat {
372
  */
373
  public function is_archive_admin() {
374
  global $current_screen;
375
-
376
- if ( isset( $current_screen->base ) && ( 'edit-tags' === $current_screen->base || 'term' === $current_screen->base ) )
377
- return true;
378
-
379
- return false;
380
  }
381
 
382
  /**
@@ -394,13 +383,9 @@ class Query extends Compat {
394
 
395
  global $current_screen;
396
 
397
- $is_term_edit = false;
398
- if ( isset( $current_screen->base ) && ( 'term' === $current_screen->base ) )
399
- $is_term_edit = true;
400
-
401
  $this->set_query_cache(
402
  __METHOD__,
403
- $is_term_edit
404
  );
405
 
406
  return $is_term_edit;
@@ -416,11 +401,7 @@ class Query extends Compat {
416
  */
417
  public function is_post_edit() {
418
  global $current_screen;
419
-
420
- if ( isset( $current_screen->base ) && 'post' === $current_screen->base )
421
- return true;
422
-
423
- return false;
424
  }
425
 
426
  /**
@@ -433,11 +414,7 @@ class Query extends Compat {
433
  */
434
  public function is_wp_lists_edit() {
435
  global $current_screen;
436
-
437
- if ( isset( $current_screen->base ) && in_array( $current_screen->base, [ 'edit-tags', 'edit' ], true ) )
438
- return true;
439
-
440
- return false;
441
  }
442
 
443
  /**
@@ -476,6 +453,9 @@ class Query extends Compat {
476
  */
477
  public function is_blog_page( $id = 0 ) {
478
 
 
 
 
479
  $id = $id ?: $this->get_the_real_ID();
480
 
481
  if ( null !== $cache = $this->get_query_cache( __METHOD__, null, $id ) )
@@ -484,15 +464,14 @@ class Query extends Compat {
484
  $is_blog_page = false;
485
 
486
  static $pfp = null;
 
487
  if ( is_null( $pfp ) )
488
  $pfp = (int) \get_option( 'page_for_posts' );
489
 
490
- if ( $this->has_page_on_front() ) {
491
- if ( $id && $id === $pfp && false === \is_archive() ) {
492
- $is_blog_page = true;
493
- } elseif ( \is_home() ) {
494
- $is_blog_page = true;
495
- }
496
  }
497
 
498
  $this->set_query_cache(
@@ -628,13 +607,35 @@ class Query extends Compat {
628
  return $is_front_page;
629
  }
630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
  /**
632
  * Checks for front page by input ID.
633
  *
634
- * Returns true if on SEO settings page and when ID is 0.
 
 
635
  *
636
  * @since 2.9.0
637
  * @since 2.9.3 Now tests for archive and 404 before testing home page as blog.
 
638
  *
639
  * @param int The page ID, required. Can be 0.
640
  * @return bool True if ID if for the home page.
@@ -649,33 +650,27 @@ class Query extends Compat {
649
  $is_front_page = false;
650
  $sof = \get_option( 'show_on_front' );
651
 
652
- //* Elegant Themes Support. Yay.
653
- if ( 0 === $id && $this->is_home() ) {
654
- if ( 'page' !== $sof && 'posts' !== $sof )
655
- $is_front_page = true;
656
- }
657
-
658
  //* Compare against $id
659
- if ( false === $is_front_page ) {
660
- if ( 'page' === $sof ) {
661
- if ( (int) \get_option( 'page_on_front' ) === $id ) {
662
- $is_front_page = true;
663
- }
664
- } elseif ( 'posts' === $sof ) {
665
- if ( 0 === $id ) {
666
- //* 0 as ID causes many issues. Just test for is_home().
667
- if ( $this->is_home() ) {
668
- $is_front_page = true;
669
- }
670
- } elseif ( (int) \get_option( 'page_for_posts' ) === $id ) {
671
  $is_front_page = true;
672
  }
 
 
 
 
 
 
 
673
  }
674
  }
675
 
676
- if ( false === $is_front_page && 0 === $id && $this->is_seo_settings_page() )
677
- $is_front_page = true;
678
-
679
  $this->set_query_cache(
680
  __METHOD__,
681
  $is_front_page,
@@ -823,11 +818,7 @@ class Query extends Compat {
823
  */
824
  public function is_single_admin() {
825
  global $current_screen;
826
-
827
- if ( isset( $current_screen->post_type ) && 'post' === $current_screen->post_type )
828
- return true;
829
-
830
- return false;
831
  }
832
 
833
  /**
@@ -849,7 +840,7 @@ class Query extends Compat {
849
 
850
  if ( is_int( $post_types ) ) {
851
  //* Cache ID. Core is_singular() doesn't accept integers.
852
- $id = $post_types;
853
  $post_types = '';
854
  }
855
 
@@ -888,15 +879,13 @@ class Query extends Compat {
888
  * @return bool Post Type is singular
889
  */
890
  public function is_singular_admin( $post_id = null ) {
891
- global $current_screen;
892
 
893
  if ( isset( $post_id ) ) {
894
  $post = \get_post( $post_id );
895
- if ( $post && $post instanceof \WP_Post )
896
- return true;
897
  } else {
898
- if ( isset( $current_screen->base ) && ( 'edit' === $current_screen->base || 'post' === $current_screen->base ) )
899
- return true;
900
  }
901
 
902
  return false;
@@ -1060,9 +1049,7 @@ class Query extends Compat {
1060
  * @return bool True if SSL, false otherwise.
1061
  */
1062
  public function is_ssl() {
1063
-
1064
  static $cache = null;
1065
-
1066
  return isset( $cache ) ? $cache : $cache = \is_ssl();
1067
  }
1068
 
@@ -1089,11 +1076,9 @@ class Query extends Compat {
1089
  if ( null !== $cache = $this->get_query_cache( __METHOD__ ) )
1090
  return $cache;
1091
 
1092
- $page = $this->is_menu_page( $this->seo_settings_page_hook );
1093
-
1094
  $this->set_query_cache(
1095
  __METHOD__,
1096
- $page
1097
  );
1098
 
1099
  return $page;
@@ -1125,11 +1110,9 @@ class Query extends Compat {
1125
  global $page_hook;
1126
 
1127
  if ( isset( $page_hook ) ) {
1128
- if ( $page_hook === $pagehook )
1129
- return true;
1130
  } elseif ( $this->is_admin() && $pageslug ) {
1131
- if ( ! empty( $_GET['page'] ) && $pageslug === $_GET['page'] )
1132
- return true;
1133
  }
1134
 
1135
  return false;
@@ -1280,8 +1263,8 @@ class Query extends Compat {
1280
  * Handles object cache for the query class.
1281
  *
1282
  * @since 2.7.0
1283
- * @staticvar bool $can_cache_query : True when this function can run.
1284
- * @staticvar mixed $cache : The cached query.
1285
  * @see $this->set_query_cache(); to set query cache.
1286
  *
1287
  * @param string $method The method that wants to cache, used as the key to set or get.
@@ -1302,7 +1285,7 @@ class Query extends Compat {
1302
 
1303
  static $can_cache_query = null;
1304
 
1305
- if ( is_null( $can_cache_query ) ) {
1306
  if ( $this->can_cache_query( $method ) ) {
1307
  $can_cache_query = true;
1308
  } else {
@@ -1313,6 +1296,7 @@ class Query extends Compat {
1313
  static $cache = [];
1314
 
1315
  if ( func_num_args() > 2 ) {
 
1316
  $hash = isset( $value_to_set ) ? serialize( (array) func_get_arg( 2 ) ) : serialize( array_slice( func_get_args(), 2 ) );
1317
  } else {
1318
  $hash = false;
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
50
  * @since 3.1.0 1. Is now protected.
51
  * 2. Now asks for and passes $method.
52
  * 3. Now returns false on WP CLI.
53
+ * @since 3.2.2 No longer spits out errors on production websites.
54
  * @staticvar bool $cache : Always true if set.
55
  * @global \WP_Query $wp_query
56
  * @global \WP_Screen|null $current_screen
71
  if ( isset( $GLOBALS['wp_query']->query ) || isset( $GLOBALS['current_screen'] ) )
72
  return $cache = true;
73
 
74
+ $this->the_seo_framework_debug
75
+ and $this->do_query_error_notice( $method );
76
 
77
  return false;
78
  }
84
  *
85
  * @param string $method The original caller method.
86
  */
87
+ // phpcs:disable -- Method unused in production.
88
  protected function do_query_error_notice( $method ) {
89
 
90
  $message = "You've initiated a method that uses queries too early.";
98
  $this->_doing_it_wrong( \esc_html( $method ), \esc_html( $message ), '2.9.0' );
99
 
100
  //* Backtrace debugging.
101
+ // $depth = 10;
102
+ // if ( $_more ) {
103
+ // error_log( var_export( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $depth ), true ) );
104
+ // $_more = false;
105
+ // }
106
+ } // phpcs:enable
 
 
 
 
107
 
108
  /**
109
  * Returns the post type name from current screen.
219
  * @return int the ID.
220
  */
221
  public function get_the_front_page_ID() { // phpcs:ignore -- ID is capitalized because WordPress does that too: get_the_ID().
 
222
  static $front_id;
 
223
  return isset( $front_id )
224
  ? $front_id
225
  : $front_id = ( $this->has_page_on_front() ? (int) \get_option( 'page_on_front' ) : 0 );
265
 
266
  if ( isset( $cache ) ) return $cache;
267
 
268
+ $_object = $this->is_admin() ? $GLOBALS['current_screen'] : \get_queried_object();
269
+
270
+ return $cache = ! empty( $_object->taxonomy ) ? $_object->taxonomy : '';
 
 
 
 
271
  }
272
 
273
  /**
365
  */
366
  public function is_archive_admin() {
367
  global $current_screen;
368
+ return isset( $current_screen->base ) && in_array( $current_screen->base, [ 'edit-tags', 'term' ], true );
 
 
 
 
369
  }
370
 
371
  /**
383
 
384
  global $current_screen;
385
 
 
 
 
 
386
  $this->set_query_cache(
387
  __METHOD__,
388
+ $is_term_edit = isset( $current_screen->base ) && ( 'term' === $current_screen->base )
389
  );
390
 
391
  return $is_term_edit;
401
  */
402
  public function is_post_edit() {
403
  global $current_screen;
404
+ return isset( $current_screen->base ) && 'post' === $current_screen->base;
 
 
 
 
405
  }
406
 
407
  /**
414
  */
415
  public function is_wp_lists_edit() {
416
  global $current_screen;
417
+ return isset( $current_screen->base ) && in_array( $current_screen->base, [ 'edit-tags', 'edit' ], true );
 
 
 
 
418
  }
419
 
420
  /**
453
  */
454
  public function is_blog_page( $id = 0 ) {
455
 
456
+ if ( ! $this->has_page_on_front() )
457
+ return false;
458
+
459
  $id = $id ?: $this->get_the_real_ID();
460
 
461
  if ( null !== $cache = $this->get_query_cache( __METHOD__, null, $id ) )
464
  $is_blog_page = false;
465
 
466
  static $pfp = null;
467
+
468
  if ( is_null( $pfp ) )
469
  $pfp = (int) \get_option( 'page_for_posts' );
470
 
471
+ if ( $id && $id === $pfp && false === \is_archive() ) {
472
+ $is_blog_page = true;
473
+ } elseif ( \is_home() ) {
474
+ $is_blog_page = true;
 
 
475
  }
476
 
477
  $this->set_query_cache(
607
  return $is_front_page;
608
  }
609
 
610
+ /**
611
+ * Checks for front page by input ID without engaging into the query.
612
+ *
613
+ * @NOTE This doesn't check for anomalies in the query.
614
+ * So, don't use this to test user-engaged WordPress queries, ever.
615
+ * WARNING: This will lead to **FALSE POSITIVES** for Date, PTA, Search, and other archives.
616
+ *
617
+ * @see $this->is_front_page_by_id(), which supports query checking.
618
+ * @see $this->is_real_front_page(), which solely uses query checking.
619
+ *
620
+ * @since 3.2.2
621
+ *
622
+ * @param int $id The tested ID.
623
+ * @return bool
624
+ */
625
+ public function is_real_front_page_by_id( $id ) {
626
+ return $id === $this->get_the_front_page_ID();
627
+ }
628
+
629
  /**
630
  * Checks for front page by input ID.
631
  *
632
+ * Doesn't always return true when the ID is 0, although the home page might be.
633
+ * This is because it checks for the query, to prevent conflicts.
634
+ * @see $this->is_real_front_page_by_id().
635
  *
636
  * @since 2.9.0
637
  * @since 2.9.3 Now tests for archive and 404 before testing home page as blog.
638
+ * @since 3.2.2: Removed SEO settings page check. This now returns false on that page.
639
  *
640
  * @param int The page ID, required. Can be 0.
641
  * @return bool True if ID if for the home page.
650
  $is_front_page = false;
651
  $sof = \get_option( 'show_on_front' );
652
 
 
 
 
 
 
 
653
  //* Compare against $id
654
+ if ( 'page' === $sof ) {
655
+ if ( (int) \get_option( 'page_on_front' ) === $id ) {
656
+ $is_front_page = true;
657
+ }
658
+ } elseif ( 'posts' === $sof ) {
659
+ if ( 0 === $id ) {
660
+ //* 0 as ID causes many issues. Just test for is_home().
661
+ if ( $this->is_home() ) {
 
 
 
 
662
  $is_front_page = true;
663
  }
664
+ } elseif ( (int) \get_option( 'page_for_posts' ) === $id ) {
665
+ $is_front_page = true;
666
+ }
667
+ } else {
668
+ // Elegant Themes' Extra support
669
+ if ( 0 === $id && $this->is_home() ) {
670
+ $is_front_page = true;
671
  }
672
  }
673
 
 
 
 
674
  $this->set_query_cache(
675
  __METHOD__,
676
  $is_front_page,
818
  */
819
  public function is_single_admin() {
820
  global $current_screen;
821
+ return isset( $current_screen->post_type ) && 'post' === $current_screen->post_type;
 
 
 
 
822
  }
823
 
824
  /**
840
 
841
  if ( is_int( $post_types ) ) {
842
  //* Cache ID. Core is_singular() doesn't accept integers.
843
+ $id = $post_types;
844
  $post_types = '';
845
  }
846
 
879
  * @return bool Post Type is singular
880
  */
881
  public function is_singular_admin( $post_id = null ) {
 
882
 
883
  if ( isset( $post_id ) ) {
884
  $post = \get_post( $post_id );
885
+ return $post && $post instanceof \WP_Post;
 
886
  } else {
887
+ global $current_screen;
888
+ return isset( $current_screen->base ) && in_array( $current_screen->base, [ 'edit', 'post' ], true );
889
  }
890
 
891
  return false;
1049
  * @return bool True if SSL, false otherwise.
1050
  */
1051
  public function is_ssl() {
 
1052
  static $cache = null;
 
1053
  return isset( $cache ) ? $cache : $cache = \is_ssl();
1054
  }
1055
 
1076
  if ( null !== $cache = $this->get_query_cache( __METHOD__ ) )
1077
  return $cache;
1078
 
 
 
1079
  $this->set_query_cache(
1080
  __METHOD__,
1081
+ $page = $this->is_menu_page( $this->seo_settings_page_hook )
1082
  );
1083
 
1084
  return $page;
1110
  global $page_hook;
1111
 
1112
  if ( isset( $page_hook ) ) {
1113
+ return $page_hook === $pagehook;
 
1114
  } elseif ( $this->is_admin() && $pageslug ) {
1115
+ return ! empty( $_GET['page'] ) && $pageslug === $_GET['page']; // CSRF, input var OK.
 
1116
  }
1117
 
1118
  return false;
1263
  * Handles object cache for the query class.
1264
  *
1265
  * @since 2.7.0
1266
+ * @staticvar null|bool $can_cache_query : True when this function can run.
1267
+ * @staticvar mixed $cache : The cached query values.
1268
  * @see $this->set_query_cache(); to set query cache.
1269
  *
1270
  * @param string $method The method that wants to cache, used as the key to set or get.
1285
 
1286
  static $can_cache_query = null;
1287
 
1288
+ if ( null === $can_cache_query ) {
1289
  if ( $this->can_cache_query( $method ) ) {
1290
  $can_cache_query = true;
1291
  } else {
1296
  static $cache = [];
1297
 
1298
  if ( func_num_args() > 2 ) {
1299
+ // phpcs:ignore -- No objects are inserted, nor is this ever unserialized.
1300
  $hash = isset( $value_to_set ) ? serialize( (array) func_get_arg( 2 ) ) : serialize( array_slice( func_get_args(), 2 ) );
1301
  } else {
1302
  $hash = false;
inc/classes/render.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -767,9 +767,9 @@ class Render extends Admin_Init {
767
  if ( ! $this->output_published_time() )
768
  return '';
769
 
770
- $id = $this->get_the_real_ID();
771
-
772
  $post = \get_post( $id );
 
773
  $post_date_gmt = $post->post_date_gmt;
774
 
775
  if ( '0000-00-00 00:00:00' === $post_date_gmt )
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
767
  if ( ! $this->output_published_time() )
768
  return '';
769
 
770
+ $id = $this->get_the_real_ID();
 
771
  $post = \get_post( $id );
772
+
773
  $post_date_gmt = $post->post_date_gmt;
774
 
775
  if ( '0000-00-00 00:00:00' === $post_date_gmt )
inc/classes/sanitize.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -59,9 +59,8 @@ class Sanitize extends Admin_Pages {
59
  *
60
  * @since 2.2.9
61
  */
62
- if ( empty( $_POST )
63
- || ! isset( $_POST[ $this->settings_field ] )
64
- || ! is_array( $_POST[ $this->settings_field ] ) ) // CSRF ok: This is just a performance check.
65
  return $validated = false;
66
 
67
  //* This is also handled in /wp-admin/options.php. Nevertheless, one might register outside of scope.
@@ -161,14 +160,6 @@ class Sanitize extends Admin_Pages {
161
  ]
162
  );
163
 
164
- $this->add_option_filter(
165
- 's_description_separator',
166
- $this->settings_field,
167
- [
168
- 'description_separator',
169
- ]
170
- );
171
-
172
  $this->add_option_filter(
173
  's_description',
174
  $this->settings_field,
@@ -259,8 +250,6 @@ class Sanitize extends Admin_Pages {
259
  'title_strip_tags',
260
 
261
  'auto_description',
262
- 'description_additions',
263
- 'description_blogname',
264
 
265
  'category_noindex',
266
  'tag_noindex',
@@ -615,41 +604,37 @@ class Sanitize extends Admin_Pages {
615
  * filter function name as a callback
616
  */
617
  protected function get_available_filters() {
618
-
619
- $default_filters = [
620
- 's_left_right' => [ $this, 's_left_right' ],
621
- 's_left_right_home' => [ $this, 's_left_right_home' ],
622
- 's_title_separator' => [ $this, 's_title_separator' ],
623
- 's_description_separator' => [ $this, 's_description_separator' ],
624
- 's_description' => [ $this, 's_description' ],
625
- 's_description_raw' => [ $this, 's_description_raw' ],
626
- 's_title' => [ $this, 's_title' ],
627
- 's_title_raw' => [ $this, 's_title_raw' ],
628
- 's_knowledge_type' => [ $this, 's_knowledge_type' ],
629
- 's_alter_query_type' => [ $this, 's_alter_query_type' ],
630
- 's_one_zero' => [ $this, 's_one_zero' ],
631
- 's_disabled_post_types' => [ $this, 's_disabled_post_types' ],
632
- 's_post_types' => [ $this, 's_post_types' ],
633
- 's_numeric_string' => [ $this, 's_numeric_string' ],
634
- 's_no_html' => [ $this, 's_no_html' ],
635
- 's_no_html_space' => [ $this, 's_no_html_space' ],
636
- 's_absint' => [ $this, 's_absint' ],
637
- 's_safe_html' => [ $this, 's_safe_html' ],
638
- 's_url' => [ $this, 's_url' ],
639
- 's_url_query' => [ $this, 's_url_query' ],
640
- 's_facebook_profile' => [ $this, 's_facebook_profile' ],
641
- 's_twitter_name' => [ $this, 's_twitter_name' ],
642
- 's_twitter_card' => [ $this, 's_twitter_card' ],
643
- 's_canonical_scheme' => [ $this, 's_canonical_scheme' ],
644
- 's_min_max_sitemap' => [ $this, 's_min_max_sitemap' ],
645
- ];
646
-
647
  /**
648
  * @since 2.2.2
649
  * @param array $default_filters Array with keys of sanitization types
650
  * and values of the filter function name as a callback
651
  */
652
- return (array) \apply_filters( 'the_seo_framework_available_sanitizer_filters', $default_filters );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  }
654
 
655
  /**
@@ -678,34 +663,6 @@ class Sanitize extends Admin_Pages {
678
  return (string) $previous;
679
  }
680
 
681
- /**
682
- * Returns the description separator value string.
683
- *
684
- * @since 2.2.2
685
- * @since 2.8.0 Method is now public.
686
- *
687
- * @param mixed $new_value Should be identical to any of the $this->description_separator values
688
- * @return string Description separator option
689
- */
690
- public function s_description_separator( $new_value ) {
691
-
692
- //* Use the same as title_separator
693
- $description_separator = $this->get_separator_list();
694
-
695
- $key = array_key_exists( $new_value, $description_separator );
696
-
697
- if ( $key )
698
- return (string) $new_value;
699
-
700
- $previous = $this->get_option( 'description_separator' );
701
-
702
- //* Fallback to default if empty.
703
- if ( empty( $previous ) )
704
- $previous = $this->get_default_option( 'description_separator' );
705
-
706
- return (string) $previous;
707
- }
708
-
709
  /**
710
  * Escapes and beautifies description.
711
  *
@@ -985,8 +942,8 @@ class Sanitize extends Admin_Pages {
985
  */
986
  public function s_alter_query_type( $new_value ) {
987
  switch ( $new_value ) {
988
- case 'in_query' :
989
- case 'post_query' :
990
  return (string) $new_value;
991
  break;
992
 
@@ -1288,7 +1245,6 @@ class Sanitize extends Admin_Pages {
1288
  $url = strip_tags( $new_value );
1289
 
1290
  if ( $url ) :
1291
-
1292
  /**
1293
  * Sanitize the redirect URL to only a relative link and removes first slash
1294
  * @requires WP 4.1.0 and up to prevent adding upon itself.
@@ -1303,7 +1259,7 @@ class Sanitize extends Admin_Pages {
1303
  . '((www.)?)' // 3: maybe www.
1304
  . '(.*\.[a-zA-Z0-9]*)' // 4: any legal domain with tld
1305
  . '(?:\/)?' // 5: maybe trailing slash
1306
- . '/';
1307
 
1308
  //* If link is relative, make it full again
1309
  if ( ! preg_match( $pattern, $url ) ) {
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
59
  *
60
  * @since 2.2.9
61
  */
62
+ if ( empty( $_POST[ $this->settings_field ] ) // Input var ok.
63
+ || ! is_array( $_POST[ $this->settings_field ] ) ) // Input var, CSRF ok: This is just a performance check.
 
64
  return $validated = false;
65
 
66
  //* This is also handled in /wp-admin/options.php. Nevertheless, one might register outside of scope.
160
  ]
161
  );
162
 
 
 
 
 
 
 
 
 
163
  $this->add_option_filter(
164
  's_description',
165
  $this->settings_field,
250
  'title_strip_tags',
251
 
252
  'auto_description',
 
 
253
 
254
  'category_noindex',
255
  'tag_noindex',
604
  * filter function name as a callback
605
  */
606
  protected function get_available_filters() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  /**
608
  * @since 2.2.2
609
  * @param array $default_filters Array with keys of sanitization types
610
  * and values of the filter function name as a callback
611
  */
612
+ return (array) \apply_filters( 'the_seo_framework_available_sanitizer_filters', [
613
+ 's_left_right' => [ $this, 's_left_right' ],
614
+ 's_left_right_home' => [ $this, 's_left_right_home' ],
615
+ 's_title_separator' => [ $this, 's_title_separator' ],
616
+ 's_description' => [ $this, 's_description' ],
617
+ 's_description_raw' => [ $this, 's_description_raw' ],
618
+ 's_title' => [ $this, 's_title' ],
619
+ 's_title_raw' => [ $this, 's_title_raw' ],
620
+ 's_knowledge_type' => [ $this, 's_knowledge_type' ],
621
+ 's_alter_query_type' => [ $this, 's_alter_query_type' ],
622
+ 's_one_zero' => [ $this, 's_one_zero' ],
623
+ 's_disabled_post_types' => [ $this, 's_disabled_post_types' ],
624
+ 's_post_types' => [ $this, 's_post_types' ],
625
+ 's_numeric_string' => [ $this, 's_numeric_string' ],
626
+ 's_no_html' => [ $this, 's_no_html' ],
627
+ 's_no_html_space' => [ $this, 's_no_html_space' ],
628
+ 's_absint' => [ $this, 's_absint' ],
629
+ 's_safe_html' => [ $this, 's_safe_html' ],
630
+ 's_url' => [ $this, 's_url' ],
631
+ 's_url_query' => [ $this, 's_url_query' ],
632
+ 's_facebook_profile' => [ $this, 's_facebook_profile' ],
633
+ 's_twitter_name' => [ $this, 's_twitter_name' ],
634
+ 's_twitter_card' => [ $this, 's_twitter_card' ],
635
+ 's_canonical_scheme' => [ $this, 's_canonical_scheme' ],
636
+ 's_min_max_sitemap' => [ $this, 's_min_max_sitemap' ],
637
+ ] );
638
  }
639
 
640
  /**
663
  return (string) $previous;
664
  }
665
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  /**
667
  * Escapes and beautifies description.
668
  *
942
  */
943
  public function s_alter_query_type( $new_value ) {
944
  switch ( $new_value ) {
945
+ case 'in_query':
946
+ case 'post_query':
947
  return (string) $new_value;
948
  break;
949
 
1245
  $url = strip_tags( $new_value );
1246
 
1247
  if ( $url ) :
 
1248
  /**
1249
  * Sanitize the redirect URL to only a relative link and removes first slash
1250
  * @requires WP 4.1.0 and up to prevent adding upon itself.
1259
  . '((www.)?)' // 3: maybe www.
1260
  . '(.*\.[a-zA-Z0-9]*)' // 4: any legal domain with tld
1261
  . '(?:\/)?' // 5: maybe trailing slash
1262
+ . '/'; // precision alignment OK.
1263
 
1264
  //* If link is relative, make it full again
1265
  if ( ! preg_match( $pattern, $url ) ) {
inc/classes/silencer.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
inc/classes/site-options.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -77,6 +77,7 @@ class Site_Options extends Sanitize {
77
  * @since 2.2.7
78
  * @param array $options The default site options.
79
  */
 
80
  return (array) \apply_filters(
81
  'the_seo_framework_default_site_options',
82
  [
@@ -116,9 +117,6 @@ class Site_Options extends Sanitize {
116
 
117
  // Description.
118
  'auto_description' => 1, // Enables auto description.
119
- 'description_separator' => 'pipe', // Description separator, dropdown
120
- 'description_additions' => 0, // "Title on Blogname" within Description
121
- 'description_blogname' => 1, // "on Blogname" within Description
122
 
123
  // Robots index.
124
  'category_noindex' => 0, // Category Archive robots noindex
@@ -266,6 +264,7 @@ class Site_Options extends Sanitize {
266
  'ld_json_breadcrumbs' => 1, // LD+Json Breadcrumbs
267
  ]
268
  );
 
269
  }
270
 
271
  /**
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
77
  * @since 2.2.7
78
  * @param array $options The default site options.
79
  */
80
+ // phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned -- precision alignment OK.
81
  return (array) \apply_filters(
82
  'the_seo_framework_default_site_options',
83
  [
117
 
118
  // Description.
119
  'auto_description' => 1, // Enables auto description.
 
 
 
120
 
121
  // Robots index.
122
  'category_noindex' => 0, // Category Archive robots noindex
264
  'ld_json_breadcrumbs' => 1, // LD+Json Breadcrumbs
265
  ]
266
  );
267
+ // phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
268
  }
269
 
270
  /**
inc/classes/sitemaps.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -1031,6 +1031,7 @@ class Sitemaps extends Metaboxes {
1031
 
1032
  /**
1033
  * @since 2.5.2
 
1034
  * @example return value: [ 'http://example.com' => [ 'lastmod' => '14-01-2018', 'priority' => 0.9 ] ]
1035
  * @param array $custom_urls : {
1036
  * @param string (key) $url The absolute url to the page. : array {
@@ -1050,9 +1051,13 @@ class Sitemaps extends Metaboxes {
1050
  $url = $args;
1051
  }
1052
 
 
 
 
 
1053
  $content .= "\t<url>\n";
1054
  //* No need to use static vars
1055
- $content .= "\t\t<loc>" . \esc_url_raw( $url, [ 'http', 'https' ] ) . "</loc>\n";
1056
 
1057
  if ( isset( $args['lastmod'] ) && $args['lastmod'] ) {
1058
  $content .= "\t\t<lastmod>" . \mysql2date( $timestamp_format, $args['lastmod'], false ) . "</lastmod>\n";
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
1031
 
1032
  /**
1033
  * @since 2.5.2
1034
+ * @since 3.2.2 Invalid URLs are now skipped.
1035
  * @example return value: [ 'http://example.com' => [ 'lastmod' => '14-01-2018', 'priority' => 0.9 ] ]
1036
  * @param array $custom_urls : {
1037
  * @param string (key) $url The absolute url to the page. : array {
1051
  $url = $args;
1052
  }
1053
 
1054
+ $_url = \esc_url_raw( $url, [ 'http', 'https' ] );
1055
+
1056
+ if ( ! $_url ) continue;
1057
+
1058
  $content .= "\t<url>\n";
1059
  //* No need to use static vars
1060
+ $content .= "\t\t<loc>" . $_url . "</loc>\n";
1061
 
1062
  if ( isset( $args['lastmod'] ) && $args['lastmod'] ) {
1063
  $content .= "\t\t<lastmod>" . \mysql2date( $timestamp_format, $args['lastmod'], false ) . "</lastmod>\n";
inc/classes/term-data.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -190,18 +190,18 @@ class Term_Data extends Post_Data {
190
 
191
  foreach ( (array) $data as $key => $value ) :
192
  switch ( $key ) :
193
- case 'doctitle' :
194
  $data[ $key ] = $this->s_title_raw( $value );
195
  continue 2;
196
 
197
- case 'description' :
198
  $data[ $key ] = $this->s_description_raw( $value );
199
  continue 2;
200
 
201
- case 'noindex' :
202
- case 'nofollow' :
203
- case 'noarchive' :
204
- case 'saved_flag' :
205
  $data[ $key ] = $this->s_one_zero( $value );
206
  continue 2;
207
 
@@ -281,7 +281,7 @@ class Term_Data extends Post_Data {
281
  if ( $this->is_admin() ) {
282
  $taxonomy = $this->get_current_taxonomy();
283
  if ( $taxonomy ) {
284
- $term_id = $id ?: $this->get_the_real_admin_ID();
285
  $term[ $id ] = \get_term_by( 'id', $term_id, $taxonomy );
286
  }
287
  } else {
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
190
 
191
  foreach ( (array) $data as $key => $value ) :
192
  switch ( $key ) :
193
+ case 'doctitle':
194
  $data[ $key ] = $this->s_title_raw( $value );
195
  continue 2;
196
 
197
+ case 'description':
198
  $data[ $key ] = $this->s_description_raw( $value );
199
  continue 2;
200
 
201
+ case 'noindex':
202
+ case 'nofollow':
203
+ case 'noarchive':
204
+ case 'saved_flag':
205
  $data[ $key ] = $this->s_one_zero( $value );
206
  continue 2;
207
 
281
  if ( $this->is_admin() ) {
282
  $taxonomy = $this->get_current_taxonomy();
283
  if ( $taxonomy ) {
284
+ $term_id = $id ?: $this->get_the_real_admin_ID();
285
  $term[ $id ] = \get_term_by( 'id', $term_id, $taxonomy );
286
  }
287
  } else {
inc/classes/user-data.class.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -51,9 +51,11 @@ class User_Data extends Term_Data {
51
  * Returns the current post author ID.
52
  *
53
  * @since 3.0.0
 
 
54
  * @staticvar $cache
55
  *
56
- * @return int|bool Post author on success, false on failure.
57
  */
58
  public function get_current_post_author_id() {
59
 
@@ -62,9 +64,16 @@ class User_Data extends Term_Data {
62
  if ( isset( $cache ) )
63
  return $cache;
64
 
65
- $post = \get_post( $this->get_the_real_ID() );
 
 
 
 
 
 
 
66
 
67
- return $cache = isset( $post->post_author ) ? (int) $post->post_author : false;
68
  }
69
 
70
  /**
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
51
  * Returns the current post author ID.
52
  *
53
  * @since 3.0.0
54
+ * @since 3.2.2: 1. Now no longer returns the latest post author ID on home-as-blog pages.
55
+ * 2. Now always returns an integer.
56
  * @staticvar $cache
57
  *
58
+ * @return int Post author ID on success, 0 on failure.
59
  */
60
  public function get_current_post_author_id() {
61
 
64
  if ( isset( $cache ) )
65
  return $cache;
66
 
67
+ if ( $this->is_singular() ) {
68
+ $post = \get_post( $this->get_the_real_ID() );
69
+ $cache = isset( $post->post_author ) ? (int) $post->post_author : 0;
70
+ }
71
+ // This works... but the function name needs to be rewritten; Also, the related meta yields no social "SEO" value.
72
+ // elseif ( $this->is_author() ) {
73
+ // $cache = $this->get_the_real_ID();
74
+ // }
75
 
76
+ return $cache ?: $cache = 0;
77
  }
78
 
79
  /**
inc/functions/api.php CHANGED
@@ -10,7 +10,7 @@ namespace {
10
 
11
  /**
12
  * The SEO Framework plugin
13
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
14
  *
15
  * This program is free software: you can redistribute it and/or modify
16
  * it under the terms of the GNU General Public License version 3 as published
10
 
11
  /**
12
  * The SEO Framework plugin
13
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
14
  *
15
  * This program is free software: you can redistribute it and/or modify
16
  * it under the terms of the GNU General Public License version 3 as published
inc/functions/deprecated.php CHANGED
@@ -6,7 +6,7 @@
6
 
7
  /**
8
  * The SEO Framework plugin
9
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
10
  *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License version 3 as published
@@ -62,7 +62,7 @@ function the_seo_framework_version() {
62
 
63
  \the_seo_framework()->_deprecated_function( __FUNCTION__, '3.1.0', 'THE_SEO_FRAMEWORK_VERSION' );
64
 
65
- if ( the_seo_framework_active() )
66
  return THE_SEO_FRAMEWORK_VERSION;
67
 
68
  return null;
6
 
7
  /**
8
  * The SEO Framework plugin
9
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
10
  *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License version 3 as published
62
 
63
  \the_seo_framework()->_deprecated_function( __FUNCTION__, '3.1.0', 'THE_SEO_FRAMEWORK_VERSION' );
64
 
65
+ if ( the_seo_framework()->loaded )
66
  return THE_SEO_FRAMEWORK_VERSION;
67
 
68
  return null;
inc/functions/tsfem-suggestion.php CHANGED
@@ -6,7 +6,7 @@
6
 
7
  /**
8
  * The SEO Framework plugin
9
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
10
  *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License version 3 as published
@@ -57,9 +57,9 @@ function the_seo_framework_load_extension_manager_suggestion() {
57
  //? 4a
58
  if ( defined( 'TSF_EXTENSION_MANAGER_VERSION' ) ) return;
59
  //= PHP<5.5 can't write in empty()
60
- $plugin = get_plugins( '/the-seo-framework-extension-manager' );
61
  //? 4b
62
- if ( ! empty( $plugin ) ) return;
63
 
64
  /** @source https://github.com/sybrew/The-SEO-Framework-Extension-Manager/blob/34674828a9e79bf72584e23aaa4a82ea1f154229/bootstrap/envtest.php#L51-L62 */
65
  $_req = [
@@ -79,8 +79,6 @@ function the_seo_framework_load_extension_manager_suggestion() {
79
  //? 5
80
  if ( true !== $envtest ) return;
81
 
82
- the_seo_framework_enqueue_installer_scripts();
83
-
84
  add_action( 'admin_notices', 'the_seo_framework_suggest_extension_manager' );
85
  }
86
 
@@ -92,112 +90,16 @@ function the_seo_framework_load_extension_manager_suggestion() {
92
  */
93
  function the_seo_framework_suggest_extension_manager() {
94
 
95
- $plugin_slug = 'the-seo-framework-extension-manager';
96
- $em_text = __( 'Extension Manager', 'autodescription' );
97
-
98
- /**
99
- * @source https://github.com/WordPress/WordPress/blob/4.9-branch/wp-admin/import.php#L162-L178
100
- * @uses Spaghetti.
101
- * @see WP Core class Plugin_Installer_Skin
102
- */
103
- $url = add_query_arg( [
104
- 'tab' => 'plugin-information',
105
- 'plugin' => $plugin_slug,
106
- 'from' => 'plugins',
107
- 'TB_iframe' => 'true',
108
- 'width' => 600,
109
- 'height' => 550,
110
- ], network_admin_url( 'plugin-install.php' ) );
111
- $tsfem_details_link = sprintf(
112
- '<a href="%1$s" id=tsf-tsfem-tb class="thickbox open-plugin-details-modal" aria-label="%2$s">%3$s</a>',
113
- esc_url( $url ),
114
- /* translators: %s: Plugin name */
115
- esc_attr( sprintf( __( 'More information about %s', 'autodescription' ), $em_text ) ),
116
- esc_html( $em_text )
117
- );
118
  $suggestion = sprintf(
119
- /* translators: 1. "A feature, e.g. Focus keywords", 2: Extension Manager. */
120
- esc_html__( 'Looking for %1$s? Try out the %2$s for free.', 'autodescription' ),
121
  sprintf(
122
- '<strong>%s</strong>',
123
- esc_html__( 'Focus keywords', 'autodescription' )
124
- ),
125
- $tsfem_details_link
126
  );
127
 
128
- /**
129
- * @source https://github.com/WordPress/WordPress/blob/4.9-branch/wp-admin/import.php#L125-L138
130
- * @uses Bolognese sauce.
131
- * @see The closest bowl of spaghetti. Or WordPress\Administration\wp.updates/updates.js
132
- * This joke was brought to you by the incomplete API of WP Shiny Updates, where
133
- * WP's import.php has been directly injected into, rather than "calling" it via its API.
134
- * Therefore, leaving the incompleteness undiscovered internally.
135
- * @TODO Open core track ticket.
136
- */
137
- $url = wp_nonce_url( add_query_arg( [
138
- 'action' => 'install-plugin',
139
- 'plugin' => $plugin_slug,
140
- 'from' => 'plugins',
141
- ], self_admin_url( 'update.php' ) ), 'install-plugin_' . $plugin_slug );
142
- $action = sprintf(
143
- '<a href="%1$s" id=tsf-tsfem-install class="install-now button button-small" data-slug="%2$s" data-name="%3$s" aria-label="%4$s">%5$s</a>',
144
- esc_url( $url ),
145
- esc_attr( $plugin_slug ),
146
- esc_attr( $em_text ),
147
- /* translators: %s: Extension Manager */
148
- esc_attr( sprintf( __( 'Install the %s', 'autodescription' ), $em_text ) ),
149
- esc_html__( 'Install Now', 'autodescription' )
150
- );
151
-
152
- $text = is_rtl() ? $action . ' ' . $suggestion : $suggestion . ' ' . $action;
153
-
154
  //= This loads the JS files.
155
- the_seo_framework()->do_dismissible_notice( $text, 'updated', false, false );
156
- }
157
-
158
- /**
159
- * Loads scripts for TSFEM "Shiny Updates" implementation for WP 4.6 and later.
160
- *
161
- * @since 3.0.6
162
- * @since 3.1.0 No longer checks WP version, the requirements of this plugin is equal.
163
- * @access private
164
- */
165
- function the_seo_framework_enqueue_installer_scripts() {
166
-
167
- $deps = [
168
- 'plugin-install',
169
- 'updates',
170
- ];
171
- $scriptname = 'tsfinstaller';
172
- $suffix = the_seo_framework()->script_debug ? '' : '.min';
173
-
174
- $strings = [
175
- 'slug' => 'the-seo-framework-extension-manager',
176
- 'canEnhance' => true || the_seo_framework()->wp_version( '4.6' ),
177
- ];
178
-
179
- wp_register_script( $scriptname, THE_SEO_FRAMEWORK_DIR_URL . "lib/js/installer/{$scriptname}{$suffix}.js", $deps, THE_SEO_FRAMEWORK_VERSION, true );
180
- wp_localize_script( $scriptname, "{$scriptname}L10n", $strings );
181
-
182
- add_action( 'admin_print_styles', 'the_seo_framework_print_installer_styles' );
183
- add_action( 'admin_footer', 'wp_print_request_filesystem_credentials_modal' );
184
- add_action( 'admin_footer', 'wp_print_admin_notice_templates' );
185
-
186
- wp_enqueue_style( 'plugin-install' );
187
- wp_enqueue_script( $scriptname );
188
- add_thickbox();
189
- }
190
-
191
- /**
192
- * Outputs "button-small" "Shiny Updates" compatibility style.
193
- *
194
- * @since 3.0.6
195
- * @staticvar bool $printed Prevents duplicate writing.
196
- * @access private
197
- */
198
- function the_seo_framework_print_installer_styles() {
199
- static $printed = false;
200
- if ( $printed ) return;
201
- echo '<style type="text/css">#tsf-tsfem-install.updating-message:before{font-size:16px;vertical-align:top}</style>';
202
- $printed = true;
203
  }
6
 
7
  /**
8
  * The SEO Framework plugin
9
+ * Copyright (C) 2018 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
10
  *
11
  * This program is free software: you can redistribute it and/or modify
12
  * it under the terms of the GNU General Public License version 3 as published
57
  //? 4a
58
  if ( defined( 'TSF_EXTENSION_MANAGER_VERSION' ) ) return;
59
  //= PHP<5.5 can't write in empty()
60
+ $plugin = get_plugins();
61
  //? 4b
62
+ if ( ! empty( $plugin['the-seo-framework-extension-manager/the-seo-framework-extension-manager.php'] ) ) return;
63
 
64
  /** @source https://github.com/sybrew/The-SEO-Framework-Extension-Manager/blob/34674828a9e79bf72584e23aaa4a82ea1f154229/bootstrap/envtest.php#L51-L62 */
65
  $_req = [
79
  //? 5
80
  if ( true !== $envtest ) return;
81
 
 
 
82
  add_action( 'admin_notices', 'the_seo_framework_suggest_extension_manager' );
83
  }
84
 
90
  */
91
  function the_seo_framework_suggest_extension_manager() {
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  $suggestion = sprintf(
94
+ /* translators: %s: SEO extensions link. */
95
+ esc_html__( 'Looking for more SEO functionality? Check out %s.', 'autodescription' ),
96
  sprintf(
97
+ '<a href="%s" target=_blank rel="noopener noreferrer">%s</a>',
98
+ 'https://theseoframework.com/extensions/',
99
+ esc_html__( "The SEO Framework's extensions", 'autodescription' )
100
+ )
101
  );
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  //= This loads the JS files.
104
+ the_seo_framework()->do_dismissible_notice( $suggestion, 'updated', false, false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
inc/interfaces/debug.interface.php CHANGED
@@ -8,7 +8,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -43,7 +43,7 @@ interface Debug_Interface {
43
  * @param string $version The version of WordPress that deprecated the function.
44
  * @param string $replacement Optional. The function that should have been called. Default null.
45
  */
46
- public function _deprecated_filter( $filter, $version, $replacement = null );
47
 
48
  /**
49
  * Mark a function as deprecated and inform when it has been used.
@@ -59,7 +59,7 @@ interface Debug_Interface {
59
  * @param string $version The version of WordPress that deprecated the function.
60
  * @param string $replacement Optional. The function that should have been called. Default null.
61
  */
62
- public function _deprecated_function( $function, $version, $replacement = null );
63
 
64
  /**
65
  * Mark a function as deprecated and inform when it has been used.
@@ -75,7 +75,7 @@ interface Debug_Interface {
75
  * @param string $message A message explaining what has been done incorrectly.
76
  * @param string $version The version of WordPress where the message was added.
77
  */
78
- public function _doing_it_wrong( $function, $message, $version );
79
 
80
  /**
81
  * Mark a property or method inaccessible when it has been used.
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
43
  * @param string $version The version of WordPress that deprecated the function.
44
  * @param string $replacement Optional. The function that should have been called. Default null.
45
  */
46
+ public function _deprecated_filter( $filter, $version, $replacement = null ); // phpcs:ignore -- Internal function.
47
 
48
  /**
49
  * Mark a function as deprecated and inform when it has been used.
59
  * @param string $version The version of WordPress that deprecated the function.
60
  * @param string $replacement Optional. The function that should have been called. Default null.
61
  */
62
+ public function _deprecated_function( $function, $version, $replacement = null ); // phpcs:ignore -- Internal function.
63
 
64
  /**
65
  * Mark a function as deprecated and inform when it has been used.
75
  * @param string $message A message explaining what has been done incorrectly.
76
  * @param string $version The version of WordPress where the message was added.
77
  */
78
+ public function _doing_it_wrong( $function, $message, $version ); // phpcs:ignore -- Internal function.
79
 
80
  /**
81
  * Mark a property or method inaccessible when it has been used.
inc/views/inpost/seo-settings-singular-gutenberg-data.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package The_SEO_Framework\Views\Inpost
4
+ */
5
+
6
+ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() and $this instanceof $_this or die;
7
+
8
+ printf(
9
+ '<div id=%s data-post-id=%d style=display:none></div>',
10
+ 'tsf-gutenberg-data-holder',
11
+ $this->get_the_real_ID()
12
+ );
inc/views/inpost/seo-settings-singular.php CHANGED
@@ -304,8 +304,12 @@ switch ( $instance ) :
304
  break;
305
 
306
  case 'inpost_social':
 
 
307
  if ( $this->is_static_frontpage( $post_id ) ) {
308
  // Gets custom fields from SEO settings.
 
 
309
  $home_og_title = $this->get_option( 'homepage_og_title' );
310
  $home_og_desc = $this->get_option( 'homepage_og_description' );
311
  $home_tw_title = $this->get_option( 'homepage_twitter_title' );
@@ -316,17 +320,21 @@ switch ( $instance ) :
316
  $custom_og_desc = $this->get_custom_field( '_open_graph_description', $post_id );
317
 
318
  //! OG input falls back to default input.
319
- $og_tit_placeholder = $home_og_title ?: $custom_og_title ?: $this->get_generated_open_graph_title( [ 'id' => $post_id ] );
 
 
320
  $og_desc_placeholder = $home_og_desc
321
- ?: $this->get_description_from_custom_field( [ 'id' => $post_id ] )
322
  ?: $this->get_generated_open_graph_description( [ 'id' => $post_id ] );
323
 
324
  //! Twitter input falls back to OG input.
325
- $tw_tit_placeholder = $home_tw_title ?: $og_tit_placeholder;
 
326
  $tw_desc_placeholder = $home_tw_desc
327
  ?: $home_og_desc
328
  ?: $custom_og_desc
329
- ?: $this->get_description_from_custom_field( [ 'id' => $post_id ] )
 
330
  ?: $this->get_generated_twitter_description( [ 'id' => $post_id ] );
331
  } else {
332
  // Gets custom fields.
@@ -335,11 +343,11 @@ switch ( $instance ) :
335
 
336
  //! OG input falls back to default input.
337
  $og_tit_placeholder = $this->get_generated_open_graph_title( [ 'id' => $post_id ] );
338
- $og_desc_placeholder = $this->get_generated_open_graph_description( [ 'id' => $post_id ] );
339
 
340
  //! Twitter input falls back to OG input.
341
  $tw_tit_placeholder = $custom_og_title ?: $og_tit_placeholder;
342
- $tw_desc_placeholder = $custom_og_desc ?: $this->get_generated_twitter_description( [ 'id' => $post_id ] );
343
  }
344
 
345
  $show_og = (bool) $this->get_option( 'og_tags' );
304
  break;
305
 
306
  case 'inpost_social':
307
+ $desc_from_custom_field = $this->get_description_from_custom_field( [ 'id' => $post_id ] );
308
+
309
  if ( $this->is_static_frontpage( $post_id ) ) {
310
  // Gets custom fields from SEO settings.
311
+ $home_desc = $this->get_option( 'homepage_description' );
312
+
313
  $home_og_title = $this->get_option( 'homepage_og_title' );
314
  $home_og_desc = $this->get_option( 'homepage_og_description' );
315
  $home_tw_title = $this->get_option( 'homepage_twitter_title' );
320
  $custom_og_desc = $this->get_custom_field( '_open_graph_description', $post_id );
321
 
322
  //! OG input falls back to default input.
323
+ $og_tit_placeholder = $home_og_title
324
+ ?: $custom_og_title
325
+ ?: $this->get_generated_open_graph_title( [ 'id' => $post_id ] );
326
  $og_desc_placeholder = $home_og_desc
327
+ ?: $desc_from_custom_field
328
  ?: $this->get_generated_open_graph_description( [ 'id' => $post_id ] );
329
 
330
  //! Twitter input falls back to OG input.
331
+ $tw_tit_placeholder = $home_tw_title
332
+ ?: $og_tit_placeholder;
333
  $tw_desc_placeholder = $home_tw_desc
334
  ?: $home_og_desc
335
  ?: $custom_og_desc
336
+ ?: $home_desc
337
+ ?: $desc_from_custom_field
338
  ?: $this->get_generated_twitter_description( [ 'id' => $post_id ] );
339
  } else {
340
  // Gets custom fields.
343
 
344
  //! OG input falls back to default input.
345
  $og_tit_placeholder = $this->get_generated_open_graph_title( [ 'id' => $post_id ] );
346
+ $og_desc_placeholder = $desc_from_custom_field ?: $this->get_generated_open_graph_description( [ 'id' => $post_id ] );
347
 
348
  //! Twitter input falls back to OG input.
349
  $tw_tit_placeholder = $custom_og_title ?: $og_tit_placeholder;
350
+ $tw_desc_placeholder = $custom_og_desc ?: $desc_from_custom_field ?: $this->get_generated_twitter_description( [ 'id' => $post_id ] );
351
  }
352
 
353
  $show_og = (bool) $this->get_option( 'og_tags' );
inc/views/metaboxes/description-metabox.php CHANGED
@@ -10,52 +10,15 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_description_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_description_metabox_main' :
14
  ?>
15
  <h4><?php printf( esc_html__( 'Description Settings', 'autodescription' ) ); ?></h4>
16
  <?php
17
  $this->description( __( 'The meta description can be used to determine the text used under the title on search engine results pages.', 'autodescription' ) );
18
 
19
- /**
20
- * Parse tabs content.
21
- *
22
- * @since 2.6.0
23
- *
24
- * @param array $default_tabs { 'id' = The identifier =>
25
- * array(
26
- * 'name' => The name
27
- * 'callback' => The callback function, use array for method calling
28
- * 'dashicon' => Desired dashicon
29
- * )
30
- * }
31
- */
32
- $default_tabs = [
33
- 'general' => [
34
- 'name' => esc_html__( 'General', 'autodescription' ),
35
- 'callback' => [ $this, 'description_metabox_general_tab' ],
36
- 'dashicon' => 'admin-generic',
37
- ],
38
- 'additions' => [
39
- 'name' => esc_html__( 'Additions', 'autodescription' ),
40
- 'callback' => [ $this, 'description_metabox_additions_tab' ],
41
- 'dashicon' => 'plus',
42
- ],
43
- ];
44
-
45
- /**
46
- * @since 2.6.0
47
- * @param array $defaults The default tabs.
48
- * @param array $args The args added on the callback.
49
- */
50
- $defaults = (array) apply_filters( 'the_seo_framework_description_settings_tabs', $default_tabs, $args );
51
-
52
- $tabs = wp_parse_args( $args, $defaults );
53
-
54
- $this->nav_tab_wrapper( 'description', $tabs, '2.6.0' );
55
- break;
56
-
57
- case 'the_seo_framework_description_metabox_general' :
58
  ?>
 
 
59
  <h4><?php esc_html_e( 'Automated Description Settings', 'autodescription' ); ?></h4>
60
  <?php
61
  $this->description(
@@ -77,112 +40,6 @@ switch ( $instance ) :
77
  );
78
  break;
79
 
80
- case 'the_seo_framework_description_metabox_additions' :
81
- $language = $this->google_language();
82
-
83
- $blogname = $this->escape_description( $this->get_blogname() );
84
- $sep = esc_html( $this->get_separator( 'description' ) );
85
-
86
- //* Generate example.
87
- $page_title = $this->escape_description( __( 'Example Title', 'autodescription' ) );
88
- $on = $this->escape_description( _x( 'on', 'Placement. e.g. Post Title "on" Blog Name', 'autodescription' ) );
89
- $excerpt = $this->escape_description( __( 'This is an example excerpt...', 'autodescription' ) );
90
-
91
- //* Put it together.
92
- $example = '<span id="tsf-description-additions-js">'
93
- . $page_title
94
- . '<span id="tsf-on-blogname-js">' . " $on " . $blogname . '</span>'
95
- . '<span id="autodescription-descsep-js">' . " $sep " . '</span>'
96
- . '</span>'
97
- . $excerpt;
98
-
99
- $nojs_additions = '';
100
- //* Add or remove additions based on option.
101
- if ( $this->add_description_additions() ) {
102
- $description_blogname_additions = $this->get_option( 'description_blogname' );
103
-
104
- $nojs_additions = $description_blogname_additions ? $page_title . " $on " . $blogname : $page_title;
105
- $nojs_additions = $nojs_additions . " $sep ";
106
- }
107
-
108
- $example_nojs = $nojs_additions . $excerpt;
109
-
110
- ?>
111
- <h4><?php esc_html_e( 'Automated Description Additions Settings', 'autodescription' ); ?></h4>
112
- <?php
113
- $this->description( __( 'To create a more organic description, additions can be added before the description.', 'autodescription' ) );
114
- $this->description( __( 'The additions consist of the page title, the blog name, and a separator.', 'autodescription' ) );
115
- ?>
116
-
117
- <h4><?php esc_html_e( 'Example Automated Description Output', 'autodescription' ); ?></h4>
118
- <p class="hide-if-no-js"><?php echo $this->code_wrap_noesc( $example ); ?></p>
119
- <p class="hide-if-js"><?php echo $this->code_wrap( $example_nojs ); ?></p>
120
-
121
- <hr>
122
-
123
- <h4><?php esc_html_e( 'Enable Additions', 'autodescription' ); ?></h4>
124
- <div id="tsf-description-additions-toggle">
125
- <?php
126
- $info = $this->make_info(
127
- __( 'This creates better automated meta descriptions.', 'autodescription' ),
128
- 'https://support.google.com/webmasters/answer/35624?hl=' . $language . '#meta-descriptions',
129
- false
130
- );
131
- $this->wrap_fields(
132
- $this->make_checkbox(
133
- 'description_additions',
134
- esc_html__( 'Add additions to automated description?', 'autodescription' ) . ' ' . $info,
135
- '',
136
- false
137
- ),
138
- true
139
- );
140
- ?>
141
- </div>
142
-
143
- <h4><?php esc_html_e( 'Add Blogname to Additions', 'autodescription' ); ?></h4>
144
- <div id="tsf-description-onblogname-toggle">
145
- <?php
146
- $this->wrap_fields(
147
- $this->make_checkbox(
148
- 'description_blogname',
149
- esc_html__( 'Add the blog name to the additions?', 'autodescription' ),
150
- '',
151
- false
152
- ),
153
- true
154
- );
155
- ?>
156
- </div>
157
- <?php
158
-
159
- //* Let's use the same separators as for the title.
160
- $description_separator = $this->get_separator_list();
161
- $sep_option = $this->get_option( 'description_separator' );
162
- $sep_option = $sep_option ? $sep_option : 'pipe';
163
-
164
- // FIXME: what a mess...
165
- ?>
166
- <fieldset>
167
- <legend>
168
- <h4><?php esc_html_e( 'Description Separator', 'autodescription' ); ?></h4>
169
- <?php $this->description( __( 'When additions are enabled, this separator will go in-between the additions and the excerpt.', 'autodescription' ) ); ?>
170
- </legend>
171
- <p id="tsf-description-separator" class="tsf-fields">
172
- <?php foreach ( $description_separator as $name => $html ) { ?>
173
- <input type="radio" name="<?php $this->field_name( 'description_separator' ); ?>" id="<?php $this->field_id( 'description_separator' . $name ); ?>" value="<?php echo esc_attr( $name ); ?>" <?php checked( $sep_option, $name ); ?> />
174
- <label for="<?php $this->field_id( 'description_separator' . $name ); ?>">
175
- <?php
176
- echo $html; // xss ok
177
- ?>
178
- </label>
179
- <?php } ?>
180
- </p>
181
- </fieldset>
182
-
183
- <?php
184
- break;
185
-
186
  default:
187
  break;
188
  endswitch;
10
  $instance = $this->get_view_instance( 'the_seo_framework_description_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_description_metabox_main':
14
  ?>
15
  <h4><?php printf( esc_html__( 'Description Settings', 'autodescription' ) ); ?></h4>
16
  <?php
17
  $this->description( __( 'The meta description can be used to determine the text used under the title on search engine results pages.', 'autodescription' ) );
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  ?>
20
+ <hr>
21
+
22
  <h4><?php esc_html_e( 'Automated Description Settings', 'autodescription' ); ?></h4>
23
  <?php
24
  $this->description(
40
  );
41
  break;
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  default:
44
  break;
45
  endswitch;
inc/views/metaboxes/feed-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_feed_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_feed_metabox_main' :
14
  ?>
15
  <h4><?php esc_html_e( 'Content Feed Settings', 'autodescription' ); ?></h4>
16
  <?php
10
  $instance = $this->get_view_instance( 'the_seo_framework_feed_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_feed_metabox_main':
14
  ?>
15
  <h4><?php esc_html_e( 'Content Feed Settings', 'autodescription' ); ?></h4>
16
  <?php
inc/views/metaboxes/general-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_general_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_general_metabox_main' :
14
  $default_tabs = [
15
  // 'general' => [
16
  // 'name' => __( 'General', 'autodescription' ),
@@ -56,11 +56,11 @@ switch ( $instance ) :
56
  $this->nav_tab_wrapper( 'general', $tabs, '2.8.0' );
57
  break;
58
 
59
- case 'the_seo_framework_general_metabox_general' :
60
  echo 'Nothing to see here yet.';
61
  break;
62
 
63
- case 'the_seo_framework_general_metabox_layout' :
64
  ?>
65
  <h4><?php esc_html_e( 'Administrative Layout Settings', 'autodescription' ); ?></h4>
66
  <?php
@@ -93,7 +93,7 @@ switch ( $instance ) :
93
  <?php
94
 
95
  $pixel_info = $this->make_info(
96
- __( 'The pixel counter computes whether the input will fit on search engine Result Pages.', 'autodescription' ),
97
  '',
98
  false
99
  );
@@ -119,7 +119,7 @@ switch ( $instance ) :
119
  ], true );
120
  break;
121
 
122
- case 'the_seo_framework_general_metabox_performance' :
123
  ?>
124
  <h4><?php esc_html_e( 'Performance Settings', 'autodescription' ); ?></h4>
125
  <?php
@@ -255,7 +255,7 @@ switch ( $instance ) :
255
  'cache_object',
256
  esc_html__( 'Enable object cache?', 'autodescription' )
257
  . ' ' . $this->make_info( __( 'Object cache generally works faster than transient cache.', 'autodescription' ), '', false ),
258
- esc_html__( 'An object cache handler has been detected. If you enable this option, you might wish to disable description and Schema transient caching.', 'autodescription' ),
259
  false
260
  ),
261
  true
@@ -263,7 +263,7 @@ switch ( $instance ) :
263
  endif;
264
  break;
265
 
266
- case 'the_seo_framework_general_metabox_canonical' :
267
  ?>
268
  <h4><?php esc_html_e( 'Canonical URL Settings', 'autodescription' ); ?></h4>
269
  <?php
@@ -318,7 +318,7 @@ switch ( $instance ) :
318
  break;
319
 
320
 
321
- case 'the_seo_framework_general_metabox_timestamps' :
322
  //* Sets timezone according to WordPress settings.
323
  $this->set_timezone();
324
 
@@ -376,7 +376,7 @@ switch ( $instance ) :
376
  <?php
377
  break;
378
 
379
- case 'the_seo_framework_general_metabox_posttypes' :
380
  ?>
381
  <h4><?php esc_html_e( 'Post Type Settings', 'autodescription' ); ?></h4>
382
  <?php
10
  $instance = $this->get_view_instance( 'the_seo_framework_general_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_general_metabox_main':
14
  $default_tabs = [
15
  // 'general' => [
16
  // 'name' => __( 'General', 'autodescription' ),
56
  $this->nav_tab_wrapper( 'general', $tabs, '2.8.0' );
57
  break;
58
 
59
+ case 'the_seo_framework_general_metabox_general':
60
  echo 'Nothing to see here yet.';
61
  break;
62
 
63
+ case 'the_seo_framework_general_metabox_layout':
64
  ?>
65
  <h4><?php esc_html_e( 'Administrative Layout Settings', 'autodescription' ); ?></h4>
66
  <?php
93
  <?php
94
 
95
  $pixel_info = $this->make_info(
96
+ __( 'The pixel counter computes whether the input will fit on search engine result pages.', 'autodescription' ),
97
  '',
98
  false
99
  );
119
  ], true );
120
  break;
121
 
122
+ case 'the_seo_framework_general_metabox_performance':
123
  ?>
124
  <h4><?php esc_html_e( 'Performance Settings', 'autodescription' ); ?></h4>
125
  <?php
255
  'cache_object',
256
  esc_html__( 'Enable object cache?', 'autodescription' )
257
  . ' ' . $this->make_info( __( 'Object cache generally works faster than transient cache.', 'autodescription' ), '', false ),
258
+ esc_html__( 'An object cache handler has been detected. If you enable this option, you might wish to disable the Schema.org transient caching.', 'autodescription' ),
259
  false
260
  ),
261
  true
263
  endif;
264
  break;
265
 
266
+ case 'the_seo_framework_general_metabox_canonical':
267
  ?>
268
  <h4><?php esc_html_e( 'Canonical URL Settings', 'autodescription' ); ?></h4>
269
  <?php
318
  break;
319
 
320
 
321
+ case 'the_seo_framework_general_metabox_timestamps':
322
  //* Sets timezone according to WordPress settings.
323
  $this->set_timezone();
324
 
376
  <?php
377
  break;
378
 
379
+ case 'the_seo_framework_general_metabox_posttypes':
380
  ?>
381
  <h4><?php esc_html_e( 'Post Type Settings', 'autodescription' ); ?></h4>
382
  <?php
inc/views/metaboxes/homepage-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_homepage_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_homepage_metabox_main' :
14
  $this->description( __( 'These settings will take precedence over the settings set within the Home Page edit screen, if any.', 'autodescription' ) );
15
  ?>
16
  <hr>
@@ -64,7 +64,7 @@ switch ( $instance ) :
64
  $this->nav_tab_wrapper( 'homepage', $tabs, '2.6.0' );
65
  break;
66
 
67
- case 'the_seo_framework_homepage_metabox_general' :
68
  $language = $this->google_language();
69
  $home_id = $this->get_the_front_page_ID();
70
 
@@ -214,7 +214,7 @@ switch ( $instance ) :
214
  }
215
  break;
216
 
217
- case 'the_seo_framework_homepage_metabox_additions' :
218
  //* Fetches escaped title parts.
219
  $home_id = $this->get_the_front_page_ID();
220
  $_example_title = $this->escape_title(
@@ -225,7 +225,7 @@ switch ( $instance ) :
225
  $_example_blogname = $this->escape_title( $this->get_home_page_tagline() ?: $this->get_static_untitled_title() );
226
  $_example_separator = esc_html( $this->get_separator( 'title' ) );
227
 
228
- $example_left = '<em><span class="tsf-custom-title-js">' . $_example_title . '</span><span class="tsf-custom-blogname-js"><span class="tsf-sep-js"> ' . $_example_separator . ' </span><span class="tsf-custom-tagline-js">' . $_example_blogname . '</span></em>';
229
  $example_right = '<em><span class="tsf-custom-blogname-js"><span class="tsf-custom-tagline-js">' . $_example_blogname . '</span><span class="tsf-sep-js"> ' . $_example_separator . ' </span></span><span class="tsf-custom-title-js">' . $_example_title . '</span></em>';
230
 
231
  ?>
@@ -277,7 +277,7 @@ switch ( $instance ) :
277
  <?php
278
  break;
279
 
280
- case 'the_seo_framework_homepage_metabox_robots' :
281
  $language = $this->google_language();
282
 
283
  //* Get home page ID. If blog on front, it's 0.
@@ -385,7 +385,7 @@ switch ( $instance ) :
385
  );
386
  break;
387
 
388
- case 'the_seo_framework_homepage_metabox_social' :
389
  $language = $this->google_language();
390
 
391
  //* Get home page ID. If blog on front, it's 0.
10
  $instance = $this->get_view_instance( 'the_seo_framework_homepage_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_homepage_metabox_main':
14
  $this->description( __( 'These settings will take precedence over the settings set within the Home Page edit screen, if any.', 'autodescription' ) );
15
  ?>
16
  <hr>
64
  $this->nav_tab_wrapper( 'homepage', $tabs, '2.6.0' );
65
  break;
66
 
67
+ case 'the_seo_framework_homepage_metabox_general':
68
  $language = $this->google_language();
69
  $home_id = $this->get_the_front_page_ID();
70
 
214
  }
215
  break;
216
 
217
+ case 'the_seo_framework_homepage_metabox_additions':
218
  //* Fetches escaped title parts.
219
  $home_id = $this->get_the_front_page_ID();
220
  $_example_title = $this->escape_title(
225
  $_example_blogname = $this->escape_title( $this->get_home_page_tagline() ?: $this->get_static_untitled_title() );
226
  $_example_separator = esc_html( $this->get_separator( 'title' ) );
227
 
228
+ $example_left = '<em><span class="tsf-custom-title-js">' . $_example_title . '</span><span class="tsf-custom-blogname-js"><span class="tsf-sep-js"> ' . $_example_separator . ' </span><span class="tsf-custom-tagline-js">' . $_example_blogname . '</span></span></em>';
229
  $example_right = '<em><span class="tsf-custom-blogname-js"><span class="tsf-custom-tagline-js">' . $_example_blogname . '</span><span class="tsf-sep-js"> ' . $_example_separator . ' </span></span><span class="tsf-custom-title-js">' . $_example_title . '</span></em>';
230
 
231
  ?>
277
  <?php
278
  break;
279
 
280
+ case 'the_seo_framework_homepage_metabox_robots':
281
  $language = $this->google_language();
282
 
283
  //* Get home page ID. If blog on front, it's 0.
385
  );
386
  break;
387
 
388
+ case 'the_seo_framework_homepage_metabox_social':
389
  $language = $this->google_language();
390
 
391
  //* Get home page ID. If blog on front, it's 0.
inc/views/metaboxes/robots-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_robots_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_robots_metabox_main' :
14
  //* Robots types
15
  $types = [
16
  'category' => __( 'Category', 'autodescription' ),
@@ -95,7 +95,7 @@ switch ( $instance ) :
95
  $this->nav_tab_wrapper( 'robots', $tabs, '2.2.4' );
96
  break;
97
 
98
- case 'the_seo_framework_robots_metabox_general' :
99
  ?>
100
  <h4><?php esc_html_e( 'Paginated Archive Settings', 'autodescription' ); ?></h4>
101
  <?php
@@ -112,7 +112,7 @@ switch ( $instance ) :
112
  );
113
  break;
114
 
115
- case 'the_seo_framework_robots_metabox_no' :
116
  $ro_value = $robots['value'];
117
  $ro_name = esc_html( $robots['name'] );
118
  $ro_i18n = $robots['desc'];
10
  $instance = $this->get_view_instance( 'the_seo_framework_robots_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_robots_metabox_main':
14
  //* Robots types
15
  $types = [
16
  'category' => __( 'Category', 'autodescription' ),
95
  $this->nav_tab_wrapper( 'robots', $tabs, '2.2.4' );
96
  break;
97
 
98
+ case 'the_seo_framework_robots_metabox_general':
99
  ?>
100
  <h4><?php esc_html_e( 'Paginated Archive Settings', 'autodescription' ); ?></h4>
101
  <?php
112
  );
113
  break;
114
 
115
+ case 'the_seo_framework_robots_metabox_no':
116
  $ro_value = $robots['value'];
117
  $ro_name = esc_html( $robots['name'] );
118
  $ro_i18n = $robots['desc'];
inc/views/metaboxes/schema-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_schema_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_schema_metabox_main' :
14
  ?>
15
  <h4><?php esc_html_e( 'Schema.org Output Settings', 'autodescription' ); ?></h4>
16
  <?php
@@ -65,11 +65,11 @@ switch ( $instance ) :
65
  $this->nav_tab_wrapper( 'schema', $tabs, '2.8.0' );
66
  break;
67
 
68
- case 'the_seo_framework_schema_metabox_general' :
69
  //* Emptied @ 3.0.0
70
  break;
71
 
72
- case 'the_seo_framework_schema_metabox_structure' :
73
  ?>
74
  <h4><?php esc_html_e( 'Site Structure Options', 'autodescription' ); ?></h4>
75
  <?php
@@ -112,7 +112,7 @@ switch ( $instance ) :
112
  ), true );
113
  break;
114
 
115
- case 'the_seo_framework_schema_metabox_presence' :
116
  ?>
117
  <h4><?php esc_html_e( 'Authorized Presence Options', 'autodescription' ); ?></h4>
118
  <?php
10
  $instance = $this->get_view_instance( 'the_seo_framework_schema_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_schema_metabox_main':
14
  ?>
15
  <h4><?php esc_html_e( 'Schema.org Output Settings', 'autodescription' ); ?></h4>
16
  <?php
65
  $this->nav_tab_wrapper( 'schema', $tabs, '2.8.0' );
66
  break;
67
 
68
+ case 'the_seo_framework_schema_metabox_general':
69
  //* Emptied @ 3.0.0
70
  break;
71
 
72
+ case 'the_seo_framework_schema_metabox_structure':
73
  ?>
74
  <h4><?php esc_html_e( 'Site Structure Options', 'autodescription' ); ?></h4>
75
  <?php
112
  ), true );
113
  break;
114
 
115
+ case 'the_seo_framework_schema_metabox_presence':
116
  ?>
117
  <h4><?php esc_html_e( 'Authorized Presence Options', 'autodescription' ); ?></h4>
118
  <?php
inc/views/metaboxes/social-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_social_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_social_metabox_main' :
14
  /**
15
  * Parse tabs content.
16
  *
@@ -59,7 +59,7 @@ switch ( $instance ) :
59
  $this->nav_tab_wrapper( 'social', $tabs, '2.2.2' );
60
  break;
61
 
62
- case 'the_seo_framework_social_metabox_general' :
63
  ?>
64
  <h4><?php esc_html_e( 'Social Meta Tags Settings', 'autodescription' ); ?></h4>
65
  <?php
@@ -89,7 +89,7 @@ switch ( $instance ) :
89
  'facebook_tags',
90
  __( 'Output Facebook meta tags?', 'autodescription' ),
91
  /* translators: %s = Facebook */
92
- sprintf( __( 'Output various tags targetted at %s.', 'autodescription' ), 'Facebook' ),
93
  true
94
  ),
95
  true
@@ -101,7 +101,7 @@ switch ( $instance ) :
101
  'twitter_tags',
102
  __( 'Output Twitter meta tags?', 'autodescription' ),
103
  /* translators: %s = Facebook */
104
- sprintf( __( 'Output various tags targetted at %s.', 'autodescription' ), 'Twitter' ),
105
  true
106
  ),
107
  true
@@ -158,7 +158,7 @@ switch ( $instance ) :
158
  );
159
  break;
160
 
161
- case 'the_seo_framework_social_metabox_facebook' :
162
  $fb_author = $this->get_option( 'facebook_author' );
163
  $fb_author_placeholder = _x( 'https://www.facebook.com/YourPersonalProfile', 'Example Facebook Personal URL', 'autodescription' );
164
 
@@ -224,7 +224,7 @@ switch ( $instance ) :
224
  <?php
225
  break;
226
 
227
- case 'the_seo_framework_social_metabox_twitter' :
228
  $tw_site = $this->get_option( 'twitter_site' );
229
  $tw_site_placeholder = _x( '@your-site-username', 'Twitter @username', 'autodescription' );
230
 
@@ -309,7 +309,7 @@ switch ( $instance ) :
309
  <?php
310
  break;
311
 
312
- case 'the_seo_framework_social_metabox_postdates' :
313
  $posts_i18n = esc_html__( 'Posts', 'autodescription' );
314
  $home_i18n = esc_html__( 'Home Page', 'autodescription' );
315
 
10
  $instance = $this->get_view_instance( 'the_seo_framework_social_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_social_metabox_main':
14
  /**
15
  * Parse tabs content.
16
  *
59
  $this->nav_tab_wrapper( 'social', $tabs, '2.2.2' );
60
  break;
61
 
62
+ case 'the_seo_framework_social_metabox_general':
63
  ?>
64
  <h4><?php esc_html_e( 'Social Meta Tags Settings', 'autodescription' ); ?></h4>
65
  <?php
89
  'facebook_tags',
90
  __( 'Output Facebook meta tags?', 'autodescription' ),
91
  /* translators: %s = Facebook */
92
+ sprintf( __( 'Output various tags targeted at %s.', 'autodescription' ), 'Facebook' ),
93
  true
94
  ),
95
  true
101
  'twitter_tags',
102
  __( 'Output Twitter meta tags?', 'autodescription' ),
103
  /* translators: %s = Facebook */
104
+ sprintf( __( 'Output various tags targeted at %s.', 'autodescription' ), 'Twitter' ),
105
  true
106
  ),
107
  true
158
  );
159
  break;
160
 
161
+ case 'the_seo_framework_social_metabox_facebook':
162
  $fb_author = $this->get_option( 'facebook_author' );
163
  $fb_author_placeholder = _x( 'https://www.facebook.com/YourPersonalProfile', 'Example Facebook Personal URL', 'autodescription' );
164
 
224
  <?php
225
  break;
226
 
227
+ case 'the_seo_framework_social_metabox_twitter':
228
  $tw_site = $this->get_option( 'twitter_site' );
229
  $tw_site_placeholder = _x( '@your-site-username', 'Twitter @username', 'autodescription' );
230
 
309
  <?php
310
  break;
311
 
312
+ case 'the_seo_framework_social_metabox_postdates':
313
  $posts_i18n = esc_html__( 'Posts', 'autodescription' );
314
  $home_i18n = esc_html__( 'Home Page', 'autodescription' );
315
 
inc/views/metaboxes/title-metabox.php CHANGED
@@ -87,7 +87,7 @@ switch ( $instance ) :
87
  'left' => $additions_left,
88
  'right' => $additions_right,
89
  ],
90
- 'showleft' => $showleft,
91
  ],
92
  ],
93
  ];
@@ -189,7 +189,7 @@ switch ( $instance ) :
189
 
190
  <hr>
191
 
192
- <h4><?php esc_html_e( 'Remove Blogname from Title', 'autodescription' ); ?></h4>
193
  <div id="tsf-title-additions-toggle">
194
  <?php
195
  $info = $this->make_info(
@@ -201,7 +201,7 @@ switch ( $instance ) :
201
  $this->wrap_fields(
202
  $this->make_checkbox(
203
  'title_rem_additions',
204
- esc_html__( 'Remove Blogname from title?', 'autodescription' ) . ' ' . $info,
205
  '',
206
  false
207
  ),
@@ -264,7 +264,7 @@ switch ( $instance ) :
264
  <hr>
265
 
266
  <h4><?php esc_html_e( 'Archive Title Prefixes', 'autodescription' ); ?></h4>
267
- <div id="title-prefixes-toggle">
268
  <?php
269
  $info = $this->make_info(
270
  __( "The prefix helps visitors and search engines determine what kind of page they're visiting.", 'autodescription' ),
87
  'left' => $additions_left,
88
  'right' => $additions_right,
89
  ],
90
+ 'showleft' => $showleft,
91
  ],
92
  ],
93
  ];
189
 
190
  <hr>
191
 
192
+ <h4><?php esc_html_e( 'Blog Name', 'autodescription' ); ?></h4>
193
  <div id="tsf-title-additions-toggle">
194
  <?php
195
  $info = $this->make_info(
201
  $this->wrap_fields(
202
  $this->make_checkbox(
203
  'title_rem_additions',
204
+ esc_html__( 'Remove blog name from the title?', 'autodescription' ) . ' ' . $info,
205
  '',
206
  false
207
  ),
264
  <hr>
265
 
266
  <h4><?php esc_html_e( 'Archive Title Prefixes', 'autodescription' ); ?></h4>
267
+ <div id="tsf-title-prefixes-toggle">
268
  <?php
269
  $info = $this->make_info(
270
  __( "The prefix helps visitors and search engines determine what kind of page they're visiting.", 'autodescription' ),
inc/views/metaboxes/webmaster-metabox.php CHANGED
@@ -10,7 +10,7 @@ defined( 'THE_SEO_FRAMEWORK_PRESENT' ) and $_this = the_seo_framework_class() an
10
  $instance = $this->get_view_instance( 'the_seo_framework_webmaster_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
- case 'the_seo_framework_webmaster_metabox_main' :
14
  $site_url = $this->get_homepage_permalink();
15
  $language = $this->google_language();
16
 
10
  $instance = $this->get_view_instance( 'the_seo_framework_webmaster_metabox', $instance );
11
 
12
  switch ( $instance ) :
13
+ case 'the_seo_framework_webmaster_metabox_main':
14
  $site_url = $this->get_homepage_permalink();
15
  $language = $this->google_language();
16
 
language/autodescription.pot CHANGED
@@ -1,168 +1,174 @@
1
- # Copyright (C) 2018 The SEO Framework
2
  # This file is distributed under the same license as the The SEO Framework package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: The SEO Framework 3.1.0\n"
6
- "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/autodescription\n"
7
- "POT-Creation-Date: 2018-09-13 22:44:39+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
- #: bootstrap/upgrade.php:288
16
  msgid "Twitter Photo Cards have been deprecated. Your site now uses Summary Cards when applicable."
17
  msgstr ""
18
 
19
- #: bootstrap/upgrade.php:319
20
  msgid "The previous sitemap timestamp settings have been converted into new global timestamp settings."
21
  msgstr ""
22
 
23
- #: inc/classes/admin-init.class.php:223 inc/classes/admin-pages.class.php:1010
24
  msgid "Select Image"
25
  msgstr ""
26
 
27
- #: inc/classes/admin-init.class.php:224 inc/classes/admin-pages.class.php:1005
28
  msgctxt "Button hover"
29
  msgid "Select social image"
30
  msgstr ""
31
 
32
- #: inc/classes/admin-init.class.php:225
33
  msgid "Change Image"
34
  msgstr ""
35
 
36
- #: inc/classes/admin-init.class.php:226
37
  msgid "Remove Image"
38
  msgstr ""
39
 
40
- #: inc/classes/admin-init.class.php:227
41
  msgid "Remove selected social image"
42
  msgstr ""
43
 
44
- #: inc/classes/admin-init.class.php:228
45
  msgctxt "Frame title"
46
  msgid "Select Social Image"
47
  msgstr ""
48
 
49
- #: inc/classes/admin-init.class.php:229 inc/classes/admin-init.class.php:238
50
  msgid "Use this image"
51
  msgstr ""
52
 
53
- #: inc/classes/admin-init.class.php:232 inc/classes/admin-pages.class.php:1044
54
  msgid "Select Logo"
55
  msgstr ""
56
 
57
- #: inc/classes/admin-init.class.php:234
58
  msgid "Change Logo"
59
  msgstr ""
60
 
61
- #: inc/classes/admin-init.class.php:235
62
  msgid "Remove Logo"
63
  msgstr ""
64
 
65
- #: inc/classes/admin-init.class.php:236
66
  msgid "Unset selected logo"
67
  msgstr ""
68
 
69
- #: inc/classes/admin-init.class.php:237
70
  msgctxt "Frame title"
71
  msgid "Select Logo"
72
  msgstr ""
73
 
74
  #. translators: %s = term name
75
 
76
- #: inc/classes/admin-init.class.php:271
 
 
 
 
 
 
77
  msgid "Make primary %s"
78
  msgstr ""
79
 
80
  #. translators: %s = term name
81
 
82
- #: inc/classes/admin-init.class.php:273
83
  msgid "Primary %s"
84
  msgstr ""
85
 
86
- #: inc/classes/admin-init.class.php:486
87
  msgid "The changes you made will be lost if you navigate away from this page."
88
  msgstr ""
89
 
90
- #: inc/classes/admin-init.class.php:487
91
  msgid "Are you sure you want to reset all SEO settings to their defaults?"
92
  msgstr ""
93
 
94
- #: inc/classes/admin-init.class.php:488
95
- #: inc/classes/generate-title.class.php:1013
96
  msgid "Private: %s"
97
  msgstr ""
98
 
99
- #: inc/classes/admin-init.class.php:489
100
- #: inc/classes/generate-title.class.php:999
101
  msgid "Protected: %s"
102
  msgstr ""
103
 
104
  #. translators: Pixel counter. 1: width, 2: guideline
105
 
106
- #: inc/classes/admin-init.class.php:491
107
  msgid "%1$d out of %2$d pixels are used."
108
  msgstr ""
109
 
110
- #: inc/classes/admin-init.class.php:680
111
  msgid "There's no content."
112
  msgstr ""
113
 
114
- #: inc/classes/admin-init.class.php:681
115
  msgid "It's too short and it should have more information."
116
  msgstr ""
117
 
118
- #: inc/classes/admin-init.class.php:682
119
  msgid "It's short and it could have more information."
120
  msgstr ""
121
 
122
- #: inc/classes/admin-init.class.php:683
123
  msgid "It's long and it might get truncated in search."
124
  msgstr ""
125
 
126
- #: inc/classes/admin-init.class.php:684
127
  msgid "It's too long and it will get truncated in search."
128
  msgstr ""
129
 
130
- #: inc/classes/admin-init.class.php:685
131
  msgid "Length is good."
132
  msgstr ""
133
 
134
- #: inc/classes/admin-init.class.php:688
135
  msgctxt "The string is empty"
136
  msgid "Empty"
137
  msgstr ""
138
 
139
- #: inc/classes/admin-init.class.php:689
140
  msgid "Far too short"
141
  msgstr ""
142
 
143
- #: inc/classes/admin-init.class.php:690
144
  msgid "Too short"
145
  msgstr ""
146
 
147
- #: inc/classes/admin-init.class.php:691
148
  msgid "Too long"
149
  msgstr ""
150
 
151
- #: inc/classes/admin-init.class.php:692
152
  msgid "Far too long"
153
  msgstr ""
154
 
155
- #: inc/classes/admin-init.class.php:693
156
  msgid "Good"
157
  msgstr ""
158
 
159
  #. translators: %s = Redirect URL markdown
160
 
161
- #: inc/classes/admin-init.class.php:807
162
  msgid "There has been an error redirecting. Refresh the page or follow [this link](%s)."
163
  msgstr ""
164
 
165
- #: inc/classes/admin-init.class.php:889 inc/classes/admin-init.class.php:949
166
  msgid "Image could not be processed."
167
  msgstr ""
168
 
@@ -270,11 +276,7 @@ msgstr ""
270
  msgid "About"
271
  msgstr ""
272
 
273
- #: inc/classes/core.class.php:250
274
- msgid "https://wordpress.org/plugins/the-seo-framework-extension-manager/"
275
- msgstr ""
276
-
277
- #: inc/classes/core.class.php:251
278
  msgctxt "Plugin extensions"
279
  msgid "Extensions"
280
  msgstr ""
@@ -323,7 +325,6 @@ msgstr ""
323
  #. translators: %d = page number. Front-end output.
324
 
325
  #: inc/classes/deprecated.class.php:314
326
- #: inc/classes/generate-title.class.php:963
327
  msgid "Page %d"
328
  msgstr ""
329
 
@@ -571,173 +572,172 @@ msgctxt "The content source"
571
  msgid "Source"
572
  msgstr ""
573
 
574
- #. translators: 1: Description additions, 2: Description separator, 3: Excerpt
575
- #. translators: 1: Title, 2: on, 3: Blogname
576
-
577
- #: inc/classes/generate-description.class.php:438
578
- #: inc/classes/generate-description.class.php:731
579
- msgid "%1$s %2$s %3$s"
580
- msgstr ""
581
-
582
  #. translators: %s = Blog page title. Front-end output.
583
 
584
- #: inc/classes/generate-description.class.php:698
585
  msgid "Latest posts: %s"
586
  msgstr ""
587
 
588
- #: inc/classes/generate-description.class.php:713
589
- #: inc/views/metaboxes/description-metabox.php:88
590
  msgctxt "Placement. e.g. Post Title \"on\" Blog Name"
591
  msgid "on"
592
  msgstr ""
593
 
 
 
 
 
 
 
594
  #. translators: Category archive title. 1: Category name
595
 
596
- #: inc/classes/generate-title.class.php:657
597
- #: inc/classes/generate-title.class.php:677
598
  msgid "Category: %s"
599
  msgstr ""
600
 
601
  #. translators: Tag archive title. 1: Tag name
602
 
603
- #: inc/classes/generate-title.class.php:661
604
- #: inc/classes/generate-title.class.php:681
605
  msgid "Tag: %s"
606
  msgstr ""
607
 
608
  #. translators: Taxonomy term archive title. 1: Taxonomy singular name, 2:
609
  #. Current taxonomy term
610
 
611
- #: inc/classes/generate-title.class.php:667
612
- #: inc/classes/generate-title.class.php:729
613
  msgid "%1$s: %2$s"
614
  msgstr ""
615
 
616
- #: inc/classes/generate-title.class.php:671
617
- #: inc/classes/generate-title.class.php:732
618
  msgid "Archives"
619
  msgstr ""
620
 
621
  #. translators: Author archive title. 1: Author name
622
 
623
- #: inc/classes/generate-title.class.php:685
624
  msgid "Author: %s"
625
  msgstr ""
626
 
627
- #: inc/classes/generate-title.class.php:688
628
  msgctxt "yearly archives date format"
629
  msgid "Y"
630
  msgstr ""
631
 
632
  #. translators: Yearly archive title. 1: Year
633
 
634
- #: inc/classes/generate-title.class.php:690
635
  msgid "Year: %s"
636
  msgstr ""
637
 
638
- #: inc/classes/generate-title.class.php:692
639
  msgctxt "monthly archives date format"
640
  msgid "F Y"
641
  msgstr ""
642
 
643
  #. translators: Monthly archive title. 1: Month name and year
644
 
645
- #: inc/classes/generate-title.class.php:694
646
  msgid "Month: %s"
647
  msgstr ""
648
 
649
- #: inc/classes/generate-title.class.php:696
650
  msgctxt "daily archives date format"
651
  msgid "F j, Y"
652
  msgstr ""
653
 
654
  #. translators: Daily archive title. 1: Date
655
 
656
- #: inc/classes/generate-title.class.php:698
657
  msgid "Day: %s"
658
  msgstr ""
659
 
660
- #: inc/classes/generate-title.class.php:702
661
  msgctxt "post format archive title"
662
  msgid "Asides"
663
  msgstr ""
664
 
665
- #: inc/classes/generate-title.class.php:704
666
  msgctxt "post format archive title"
667
  msgid "Galleries"
668
  msgstr ""
669
 
670
- #: inc/classes/generate-title.class.php:706
671
  msgctxt "post format archive title"
672
  msgid "Images"
673
  msgstr ""
674
 
675
- #: inc/classes/generate-title.class.php:708
676
  msgctxt "post format archive title"
677
  msgid "Videos"
678
  msgstr ""
679
 
680
- #: inc/classes/generate-title.class.php:710
681
  msgctxt "post format archive title"
682
  msgid "Quotes"
683
  msgstr ""
684
 
685
- #: inc/classes/generate-title.class.php:712
686
  msgctxt "post format archive title"
687
  msgid "Links"
688
  msgstr ""
689
 
690
- #: inc/classes/generate-title.class.php:714
691
  msgctxt "post format archive title"
692
  msgid "Statuses"
693
  msgstr ""
694
 
695
- #: inc/classes/generate-title.class.php:716
696
  msgctxt "post format archive title"
697
  msgid "Audio"
698
  msgstr ""
699
 
700
- #: inc/classes/generate-title.class.php:718
701
  msgctxt "post format archive title"
702
  msgid "Chats"
703
  msgstr ""
704
 
705
  #. translators: Post type archive title. 1: Post type name
706
 
707
- #: inc/classes/generate-title.class.php:723
708
  msgid "Archives: %s"
709
  msgstr ""
710
 
711
- #: inc/classes/generate-title.class.php:883
712
  msgid "Untitled"
713
  msgstr ""
714
 
715
  #. translators: %s: search phrase
716
 
717
- #: inc/classes/generate-title.class.php:895
718
  msgid "Search Results for &#8220;%s&#8221;"
719
  msgstr ""
720
 
721
- #: inc/classes/inpost.class.php:168 inc/classes/inpost.class.php:176
 
 
 
 
722
  msgid "Homepage SEO Settings"
723
  msgstr ""
724
 
725
- #: inc/classes/inpost.class.php:170
726
  msgid "The SEO Settings take precedence over these settings."
727
  msgstr ""
728
 
729
  #. translators: %s = Post Type
730
  #. translators: %s = Term type
731
 
732
- #: inc/classes/inpost.class.php:180 inc/views/inpost/seo-settings-tt.php:67
733
  msgid "%s SEO Settings"
734
  msgstr ""
735
 
736
  #. translators: %s = Post type name
737
 
738
- #: inc/classes/inpost.class.php:287
739
- #: inc/views/metaboxes/description-metabox.php:34
740
- #: inc/views/metaboxes/homepage-metabox.php:34
741
  #: inc/views/metaboxes/robots-metabox.php:61
742
  #: inc/views/metaboxes/sitemaps-metabox.php:29
743
  #: inc/views/metaboxes/social-metabox.php:29
@@ -745,11 +745,11 @@ msgstr ""
745
  msgid "General"
746
  msgstr ""
747
 
748
- #: inc/classes/inpost.class.php:293 inc/views/metaboxes/homepage-metabox.php:49
749
  msgid "Social"
750
  msgstr ""
751
 
752
- #: inc/classes/inpost.class.php:299
753
  msgid "Visibility"
754
  msgstr ""
755
 
@@ -801,34 +801,14 @@ msgstr ""
801
  msgid "Sitemap is generated on %s"
802
  msgstr ""
803
 
804
- #: inc/functions/tsfem-suggestion.php:96
805
- msgid "Extension Manager"
806
- msgstr ""
807
-
808
- #. translators: %s: Plugin name
809
-
810
- #: inc/functions/tsfem-suggestion.php:115
811
- msgid "More information about %s"
812
- msgstr ""
813
-
814
- #. translators: 1. "A feature, e.g. Focus keywords", 2: Extension Manager.
815
 
816
- #: inc/functions/tsfem-suggestion.php:120
817
- msgid "Looking for %1$s? Try out the %2$s for free."
818
  msgstr ""
819
 
820
- #: inc/functions/tsfem-suggestion.php:123
821
- msgid "Focus keywords"
822
- msgstr ""
823
-
824
- #. translators: %s: Extension Manager
825
-
826
- #: inc/functions/tsfem-suggestion.php:148
827
- msgid "Install the %s"
828
- msgstr ""
829
-
830
- #: inc/functions/tsfem-suggestion.php:149
831
- msgid "Install Now"
832
  msgstr ""
833
 
834
  #: inc/views/inpost/seo-settings-singular.php:31
@@ -942,34 +922,34 @@ msgstr ""
942
  msgid "This will force visitors to go to another URL."
943
  msgstr ""
944
 
945
- #: inc/views/inpost/seo-settings-singular.php:355
946
  #: inc/views/metaboxes/homepage-metabox.php:427
947
  msgid "Open Graph Title"
948
  msgstr ""
949
 
950
- #: inc/views/inpost/seo-settings-singular.php:378
951
  #: inc/views/metaboxes/homepage-metabox.php:451
952
  msgid "Open Graph Description"
953
  msgstr ""
954
 
955
- #: inc/views/inpost/seo-settings-singular.php:399
956
  #: inc/views/metaboxes/homepage-metabox.php:479
957
  msgid "Twitter Title"
958
  msgstr ""
959
 
960
- #: inc/views/inpost/seo-settings-singular.php:422
961
  #: inc/views/metaboxes/homepage-metabox.php:503
962
  msgid "Twitter Description"
963
  msgstr ""
964
 
965
- #: inc/views/inpost/seo-settings-singular.php:450
966
  #: inc/views/metaboxes/homepage-metabox.php:556
967
  msgid "Social Image URL"
968
  msgstr ""
969
 
970
  #. translators: %s = Post type name
971
 
972
- #: inc/views/inpost/seo-settings-singular.php:456
973
  msgid "Set preferred %s Social Image URL location."
974
  msgstr ""
975
 
@@ -995,80 +975,22 @@ msgstr ""
995
  msgid "Description Settings"
996
  msgstr ""
997
 
998
- #: inc/views/metaboxes/description-metabox.php:39
999
- #: inc/views/metaboxes/homepage-metabox.php:39
1000
- #: inc/views/metaboxes/title-metabox.php:71
1001
- msgid "Additions"
1002
- msgstr ""
1003
-
1004
- #: inc/views/metaboxes/description-metabox.php:59
1005
  msgid "Automated Description Settings"
1006
  msgstr ""
1007
 
1008
- #: inc/views/metaboxes/description-metabox.php:62
1009
  msgid "A description can be automatically generated for every page."
1010
  msgstr ""
1011
 
1012
- #: inc/views/metaboxes/description-metabox.php:65
1013
  msgid "Open Graph and Twitter Cards require descriptions. Therefore, it is best to leave this option enabled."
1014
  msgstr ""
1015
 
1016
- #: inc/views/metaboxes/description-metabox.php:72
1017
  msgid "Automatically generate description?"
1018
  msgstr ""
1019
 
1020
- #: inc/views/metaboxes/description-metabox.php:87
1021
- msgid "Example Title"
1022
- msgstr ""
1023
-
1024
- #: inc/views/metaboxes/description-metabox.php:89
1025
- msgid "This is an example excerpt..."
1026
- msgstr ""
1027
-
1028
- #: inc/views/metaboxes/description-metabox.php:111
1029
- msgid "Automated Description Additions Settings"
1030
- msgstr ""
1031
-
1032
- #: inc/views/metaboxes/description-metabox.php:113
1033
- msgid "To create a more organic description, additions can be added before the description."
1034
- msgstr ""
1035
-
1036
- #: inc/views/metaboxes/description-metabox.php:114
1037
- msgid "The additions consist of the page title, the blog name, and a separator."
1038
- msgstr ""
1039
-
1040
- #: inc/views/metaboxes/description-metabox.php:117
1041
- msgid "Example Automated Description Output"
1042
- msgstr ""
1043
-
1044
- #: inc/views/metaboxes/description-metabox.php:123
1045
- msgid "Enable Additions"
1046
- msgstr ""
1047
-
1048
- #: inc/views/metaboxes/description-metabox.php:127
1049
- msgid "This creates better automated meta descriptions."
1050
- msgstr ""
1051
-
1052
- #: inc/views/metaboxes/description-metabox.php:134
1053
- msgid "Add additions to automated description?"
1054
- msgstr ""
1055
-
1056
- #: inc/views/metaboxes/description-metabox.php:143
1057
- msgid "Add Blogname to Additions"
1058
- msgstr ""
1059
-
1060
- #: inc/views/metaboxes/description-metabox.php:149
1061
- msgid "Add the blog name to the additions?"
1062
- msgstr ""
1063
-
1064
- #: inc/views/metaboxes/description-metabox.php:168
1065
- msgid "Description Separator"
1066
- msgstr ""
1067
-
1068
- #: inc/views/metaboxes/description-metabox.php:169
1069
- msgid "When additions are enabled, this separator will go in-between the additions and the excerpt."
1070
- msgstr ""
1071
-
1072
  #: inc/views/metaboxes/feed-metabox.php:15
1073
  msgid "Content Feed Settings"
1074
  msgstr ""
@@ -1171,7 +1093,7 @@ msgid "Counter Settings"
1171
  msgstr ""
1172
 
1173
  #: inc/views/metaboxes/general-metabox.php:96
1174
- msgid "The pixel counter computes whether the input will fit on search engine Result Pages."
1175
  msgstr ""
1176
 
1177
  #: inc/views/metaboxes/general-metabox.php:101
@@ -1285,7 +1207,7 @@ msgid "Object cache generally works faster than transient cache."
1285
  msgstr ""
1286
 
1287
  #: inc/views/metaboxes/general-metabox.php:258
1288
- msgid "An object cache handler has been detected. If you enable this option, you might wish to disable description and Schema transient caching."
1289
  msgstr ""
1290
 
1291
  #: inc/views/metaboxes/general-metabox.php:268
@@ -1409,6 +1331,11 @@ msgstr ""
1409
  msgid "These settings will take precedence over the settings set within the Home Page edit screen, if any."
1410
  msgstr ""
1411
 
 
 
 
 
 
1412
  #: inc/views/metaboxes/homepage-metabox.php:44
1413
  msgid "Robots"
1414
  msgstr ""
@@ -2051,7 +1978,7 @@ msgstr ""
2051
 
2052
  #: inc/views/metaboxes/social-metabox.php:92
2053
  #: inc/views/metaboxes/social-metabox.php:104
2054
- msgid "Output various tags targetted at %s."
2055
  msgstr ""
2056
 
2057
  #: inc/views/metaboxes/social-metabox.php:102
@@ -2255,7 +2182,7 @@ msgid "If the title consists of two parts (original title, pagination, and blogn
2255
  msgstr ""
2256
 
2257
  #: inc/views/metaboxes/title-metabox.php:192
2258
- msgid "Remove Blogname from Title"
2259
  msgstr ""
2260
 
2261
  #: inc/views/metaboxes/title-metabox.php:196
@@ -2263,7 +2190,7 @@ msgid "This might decouple your posts and pages from the rest of the website."
2263
  msgstr ""
2264
 
2265
  #: inc/views/metaboxes/title-metabox.php:204
2266
- msgid "Remove Blogname from title?"
2267
  msgstr ""
2268
 
2269
  #: inc/views/metaboxes/title-metabox.php:213
@@ -2399,7 +2326,7 @@ msgid "https://theseoframework.com/"
2399
  msgstr ""
2400
 
2401
  #. Description of the plugin/theme
2402
- msgid "An automated, advanced, accessible, unbranded and extremely fast SEO solution for any WordPress website."
2403
  msgstr ""
2404
 
2405
  #. Author of the plugin/theme
1
+ # Copyright (C) 2019 The SEO Framework
2
  # This file is distributed under the same license as the The SEO Framework package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: The SEO Framework 3.2.2\n"
6
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/the-seo-framework\n"
7
+ "POT-Creation-Date: 2019-01-21 21:55:27+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
+ #: bootstrap/upgrade.php:321
16
  msgid "Twitter Photo Cards have been deprecated. Your site now uses Summary Cards when applicable."
17
  msgstr ""
18
 
19
+ #: bootstrap/upgrade.php:351
20
  msgid "The previous sitemap timestamp settings have been converted into new global timestamp settings."
21
  msgstr ""
22
 
23
+ #: inc/classes/admin-init.class.php:263 inc/classes/admin-pages.class.php:1010
24
  msgid "Select Image"
25
  msgstr ""
26
 
27
+ #: inc/classes/admin-init.class.php:264 inc/classes/admin-pages.class.php:1005
28
  msgctxt "Button hover"
29
  msgid "Select social image"
30
  msgstr ""
31
 
32
+ #: inc/classes/admin-init.class.php:265
33
  msgid "Change Image"
34
  msgstr ""
35
 
36
+ #: inc/classes/admin-init.class.php:266
37
  msgid "Remove Image"
38
  msgstr ""
39
 
40
+ #: inc/classes/admin-init.class.php:267
41
  msgid "Remove selected social image"
42
  msgstr ""
43
 
44
+ #: inc/classes/admin-init.class.php:268
45
  msgctxt "Frame title"
46
  msgid "Select Social Image"
47
  msgstr ""
48
 
49
+ #: inc/classes/admin-init.class.php:269 inc/classes/admin-init.class.php:278
50
  msgid "Use this image"
51
  msgstr ""
52
 
53
+ #: inc/classes/admin-init.class.php:272 inc/classes/admin-pages.class.php:1044
54
  msgid "Select Logo"
55
  msgstr ""
56
 
57
+ #: inc/classes/admin-init.class.php:274
58
  msgid "Change Logo"
59
  msgstr ""
60
 
61
+ #: inc/classes/admin-init.class.php:275
62
  msgid "Remove Logo"
63
  msgstr ""
64
 
65
+ #: inc/classes/admin-init.class.php:276
66
  msgid "Unset selected logo"
67
  msgstr ""
68
 
69
+ #: inc/classes/admin-init.class.php:277
70
  msgctxt "Frame title"
71
  msgid "Select Logo"
72
  msgstr ""
73
 
74
  #. translators: %s = term name
75
 
76
+ #: inc/classes/admin-init.class.php:315
77
+ msgid "Select Primary %s"
78
+ msgstr ""
79
+
80
+ #. translators: %s = term name
81
+
82
+ #: inc/classes/admin-init.class.php:320
83
  msgid "Make primary %s"
84
  msgstr ""
85
 
86
  #. translators: %s = term name
87
 
88
+ #: inc/classes/admin-init.class.php:322
89
  msgid "Primary %s"
90
  msgstr ""
91
 
92
+ #: inc/classes/admin-init.class.php:573
93
  msgid "The changes you made will be lost if you navigate away from this page."
94
  msgstr ""
95
 
96
+ #: inc/classes/admin-init.class.php:574
97
  msgid "Are you sure you want to reset all SEO settings to their defaults?"
98
  msgstr ""
99
 
100
+ #: inc/classes/admin-init.class.php:576
101
+ #: inc/classes/generate-title.class.php:1114
102
  msgid "Private: %s"
103
  msgstr ""
104
 
105
+ #: inc/classes/admin-init.class.php:578
106
+ #: inc/classes/generate-title.class.php:1099
107
  msgid "Protected: %s"
108
  msgstr ""
109
 
110
  #. translators: Pixel counter. 1: width, 2: guideline
111
 
112
+ #: inc/classes/admin-init.class.php:580
113
  msgid "%1$d out of %2$d pixels are used."
114
  msgstr ""
115
 
116
+ #: inc/classes/admin-init.class.php:767
117
  msgid "There's no content."
118
  msgstr ""
119
 
120
+ #: inc/classes/admin-init.class.php:768
121
  msgid "It's too short and it should have more information."
122
  msgstr ""
123
 
124
+ #: inc/classes/admin-init.class.php:769
125
  msgid "It's short and it could have more information."
126
  msgstr ""
127
 
128
+ #: inc/classes/admin-init.class.php:770
129
  msgid "It's long and it might get truncated in search."
130
  msgstr ""
131
 
132
+ #: inc/classes/admin-init.class.php:771
133
  msgid "It's too long and it will get truncated in search."
134
  msgstr ""
135
 
136
+ #: inc/classes/admin-init.class.php:772
137
  msgid "Length is good."
138
  msgstr ""
139
 
140
+ #: inc/classes/admin-init.class.php:775
141
  msgctxt "The string is empty"
142
  msgid "Empty"
143
  msgstr ""
144
 
145
+ #: inc/classes/admin-init.class.php:776
146
  msgid "Far too short"
147
  msgstr ""
148
 
149
+ #: inc/classes/admin-init.class.php:777
150
  msgid "Too short"
151
  msgstr ""
152
 
153
+ #: inc/classes/admin-init.class.php:778
154
  msgid "Too long"
155
  msgstr ""
156
 
157
+ #: inc/classes/admin-init.class.php:779
158
  msgid "Far too long"
159
  msgstr ""
160
 
161
+ #: inc/classes/admin-init.class.php:780
162
  msgid "Good"
163
  msgstr ""
164
 
165
  #. translators: %s = Redirect URL markdown
166
 
167
+ #: inc/classes/admin-init.class.php:894
168
  msgid "There has been an error redirecting. Refresh the page or follow [this link](%s)."
169
  msgstr ""
170
 
171
+ #: inc/classes/admin-init.class.php:980 inc/classes/admin-init.class.php:1040
172
  msgid "Image could not be processed."
173
  msgstr ""
174
 
276
  msgid "About"
277
  msgstr ""
278
 
279
+ #: inc/classes/core.class.php:241
 
 
 
 
280
  msgctxt "Plugin extensions"
281
  msgid "Extensions"
282
  msgstr ""
325
  #. translators: %d = page number. Front-end output.
326
 
327
  #: inc/classes/deprecated.class.php:314
 
328
  msgid "Page %d"
329
  msgstr ""
330
 
572
  msgid "Source"
573
  msgstr ""
574
 
 
 
 
 
 
 
 
 
575
  #. translators: %s = Blog page title. Front-end output.
576
 
577
+ #: inc/classes/generate-description.class.php:671
578
  msgid "Latest posts: %s"
579
  msgstr ""
580
 
581
+ #: inc/classes/generate-description.class.php:680
 
582
  msgctxt "Placement. e.g. Post Title \"on\" Blog Name"
583
  msgid "on"
584
  msgstr ""
585
 
586
+ #. translators: 1: Title, 2: on, 3: Blogname
587
+
588
+ #: inc/classes/generate-description.class.php:684
589
+ msgid "%1$s %2$s %3$s"
590
+ msgstr ""
591
+
592
  #. translators: Category archive title. 1: Category name
593
 
594
+ #: inc/classes/generate-title.class.php:693
595
+ #: inc/classes/generate-title.class.php:713
596
  msgid "Category: %s"
597
  msgstr ""
598
 
599
  #. translators: Tag archive title. 1: Tag name
600
 
601
+ #: inc/classes/generate-title.class.php:697
602
+ #: inc/classes/generate-title.class.php:717
603
  msgid "Tag: %s"
604
  msgstr ""
605
 
606
  #. translators: Taxonomy term archive title. 1: Taxonomy singular name, 2:
607
  #. Current taxonomy term
608
 
609
+ #: inc/classes/generate-title.class.php:703
610
+ #: inc/classes/generate-title.class.php:765
611
  msgid "%1$s: %2$s"
612
  msgstr ""
613
 
614
+ #: inc/classes/generate-title.class.php:707
615
+ #: inc/classes/generate-title.class.php:768
616
  msgid "Archives"
617
  msgstr ""
618
 
619
  #. translators: Author archive title. 1: Author name
620
 
621
+ #: inc/classes/generate-title.class.php:721
622
  msgid "Author: %s"
623
  msgstr ""
624
 
625
+ #: inc/classes/generate-title.class.php:724
626
  msgctxt "yearly archives date format"
627
  msgid "Y"
628
  msgstr ""
629
 
630
  #. translators: Yearly archive title. 1: Year
631
 
632
+ #: inc/classes/generate-title.class.php:726
633
  msgid "Year: %s"
634
  msgstr ""
635
 
636
+ #: inc/classes/generate-title.class.php:728
637
  msgctxt "monthly archives date format"
638
  msgid "F Y"
639
  msgstr ""
640
 
641
  #. translators: Monthly archive title. 1: Month name and year
642
 
643
+ #: inc/classes/generate-title.class.php:730
644
  msgid "Month: %s"
645
  msgstr ""
646
 
647
+ #: inc/classes/generate-title.class.php:732
648
  msgctxt "daily archives date format"
649
  msgid "F j, Y"
650
  msgstr ""
651
 
652
  #. translators: Daily archive title. 1: Date
653
 
654
+ #: inc/classes/generate-title.class.php:734
655
  msgid "Day: %s"
656
  msgstr ""
657
 
658
+ #: inc/classes/generate-title.class.php:738
659
  msgctxt "post format archive title"
660
  msgid "Asides"
661
  msgstr ""
662
 
663
+ #: inc/classes/generate-title.class.php:740
664
  msgctxt "post format archive title"
665
  msgid "Galleries"
666
  msgstr ""
667
 
668
+ #: inc/classes/generate-title.class.php:742
669
  msgctxt "post format archive title"
670
  msgid "Images"
671
  msgstr ""
672
 
673
+ #: inc/classes/generate-title.class.php:744
674
  msgctxt "post format archive title"
675
  msgid "Videos"
676
  msgstr ""
677
 
678
+ #: inc/classes/generate-title.class.php:746
679
  msgctxt "post format archive title"
680
  msgid "Quotes"
681
  msgstr ""
682
 
683
+ #: inc/classes/generate-title.class.php:748
684
  msgctxt "post format archive title"
685
  msgid "Links"
686
  msgstr ""
687
 
688
+ #: inc/classes/generate-title.class.php:750
689
  msgctxt "post format archive title"
690
  msgid "Statuses"
691
  msgstr ""
692
 
693
+ #: inc/classes/generate-title.class.php:752
694
  msgctxt "post format archive title"
695
  msgid "Audio"
696
  msgstr ""
697
 
698
+ #: inc/classes/generate-title.class.php:754
699
  msgctxt "post format archive title"
700
  msgid "Chats"
701
  msgstr ""
702
 
703
  #. translators: Post type archive title. 1: Post type name
704
 
705
+ #: inc/classes/generate-title.class.php:759
706
  msgid "Archives: %s"
707
  msgstr ""
708
 
709
+ #: inc/classes/generate-title.class.php:919
710
  msgid "Untitled"
711
  msgstr ""
712
 
713
  #. translators: %s: search phrase
714
 
715
+ #: inc/classes/generate-title.class.php:931
716
  msgid "Search Results for &#8220;%s&#8221;"
717
  msgstr ""
718
 
719
+ #: inc/classes/generate-title.class.php:1048
720
+ msgid "Page %s"
721
+ msgstr ""
722
+
723
+ #: inc/classes/inpost.class.php:169 inc/classes/inpost.class.php:177
724
  msgid "Homepage SEO Settings"
725
  msgstr ""
726
 
727
+ #: inc/classes/inpost.class.php:171
728
  msgid "The SEO Settings take precedence over these settings."
729
  msgstr ""
730
 
731
  #. translators: %s = Post Type
732
  #. translators: %s = Term type
733
 
734
+ #: inc/classes/inpost.class.php:181 inc/views/inpost/seo-settings-tt.php:67
735
  msgid "%s SEO Settings"
736
  msgstr ""
737
 
738
  #. translators: %s = Post type name
739
 
740
+ #: inc/classes/inpost.class.php:288 inc/views/metaboxes/homepage-metabox.php:34
 
 
741
  #: inc/views/metaboxes/robots-metabox.php:61
742
  #: inc/views/metaboxes/sitemaps-metabox.php:29
743
  #: inc/views/metaboxes/social-metabox.php:29
745
  msgid "General"
746
  msgstr ""
747
 
748
+ #: inc/classes/inpost.class.php:294 inc/views/metaboxes/homepage-metabox.php:49
749
  msgid "Social"
750
  msgstr ""
751
 
752
+ #: inc/classes/inpost.class.php:300
753
  msgid "Visibility"
754
  msgstr ""
755
 
801
  msgid "Sitemap is generated on %s"
802
  msgstr ""
803
 
804
+ #. translators: %s: SEO extensions link.
 
 
 
 
 
 
 
 
 
 
805
 
806
+ #: inc/functions/tsfem-suggestion.php:95
807
+ msgid "Looking for more SEO functionality? Check out %s."
808
  msgstr ""
809
 
810
+ #: inc/functions/tsfem-suggestion.php:99
811
+ msgid "The SEO Framework's extensions"
 
 
 
 
 
 
 
 
 
 
812
  msgstr ""
813
 
814
  #: inc/views/inpost/seo-settings-singular.php:31
922
  msgid "This will force visitors to go to another URL."
923
  msgstr ""
924
 
925
+ #: inc/views/inpost/seo-settings-singular.php:363
926
  #: inc/views/metaboxes/homepage-metabox.php:427
927
  msgid "Open Graph Title"
928
  msgstr ""
929
 
930
+ #: inc/views/inpost/seo-settings-singular.php:386
931
  #: inc/views/metaboxes/homepage-metabox.php:451
932
  msgid "Open Graph Description"
933
  msgstr ""
934
 
935
+ #: inc/views/inpost/seo-settings-singular.php:407
936
  #: inc/views/metaboxes/homepage-metabox.php:479
937
  msgid "Twitter Title"
938
  msgstr ""
939
 
940
+ #: inc/views/inpost/seo-settings-singular.php:430
941
  #: inc/views/metaboxes/homepage-metabox.php:503
942
  msgid "Twitter Description"
943
  msgstr ""
944
 
945
+ #: inc/views/inpost/seo-settings-singular.php:458
946
  #: inc/views/metaboxes/homepage-metabox.php:556
947
  msgid "Social Image URL"
948
  msgstr ""
949
 
950
  #. translators: %s = Post type name
951
 
952
+ #: inc/views/inpost/seo-settings-singular.php:464
953
  msgid "Set preferred %s Social Image URL location."
954
  msgstr ""
955
 
975
  msgid "Description Settings"
976
  msgstr ""
977
 
978
+ #: inc/views/metaboxes/description-metabox.php:22
 
 
 
 
 
 
979
  msgid "Automated Description Settings"
980
  msgstr ""
981
 
982
+ #: inc/views/metaboxes/description-metabox.php:25
983
  msgid "A description can be automatically generated for every page."
984
  msgstr ""
985
 
986
+ #: inc/views/metaboxes/description-metabox.php:28
987
  msgid "Open Graph and Twitter Cards require descriptions. Therefore, it is best to leave this option enabled."
988
  msgstr ""
989
 
990
+ #: inc/views/metaboxes/description-metabox.php:35
991
  msgid "Automatically generate description?"
992
  msgstr ""
993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
994
  #: inc/views/metaboxes/feed-metabox.php:15
995
  msgid "Content Feed Settings"
996
  msgstr ""
1093
  msgstr ""
1094
 
1095
  #: inc/views/metaboxes/general-metabox.php:96
1096
+ msgid "The pixel counter computes whether the input will fit on search engine result pages."
1097
  msgstr ""
1098
 
1099
  #: inc/views/metaboxes/general-metabox.php:101
1207
  msgstr ""
1208
 
1209
  #: inc/views/metaboxes/general-metabox.php:258
1210
+ msgid "An object cache handler has been detected. If you enable this option, you might wish to disable the Schema.org transient caching."
1211
  msgstr ""
1212
 
1213
  #: inc/views/metaboxes/general-metabox.php:268
1331
  msgid "These settings will take precedence over the settings set within the Home Page edit screen, if any."
1332
  msgstr ""
1333
 
1334
+ #: inc/views/metaboxes/homepage-metabox.php:39
1335
+ #: inc/views/metaboxes/title-metabox.php:71
1336
+ msgid "Additions"
1337
+ msgstr ""
1338
+
1339
  #: inc/views/metaboxes/homepage-metabox.php:44
1340
  msgid "Robots"
1341
  msgstr ""
1978
 
1979
  #: inc/views/metaboxes/social-metabox.php:92
1980
  #: inc/views/metaboxes/social-metabox.php:104
1981
+ msgid "Output various tags targeted at %s."
1982
  msgstr ""
1983
 
1984
  #: inc/views/metaboxes/social-metabox.php:102
2182
  msgstr ""
2183
 
2184
  #: inc/views/metaboxes/title-metabox.php:192
2185
+ msgid "Blog Name"
2186
  msgstr ""
2187
 
2188
  #: inc/views/metaboxes/title-metabox.php:196
2190
  msgstr ""
2191
 
2192
  #: inc/views/metaboxes/title-metabox.php:204
2193
+ msgid "Remove blog name from the title?"
2194
  msgstr ""
2195
 
2196
  #: inc/views/metaboxes/title-metabox.php:213
2326
  msgstr ""
2327
 
2328
  #. Description of the plugin/theme
2329
+ msgid "An automated, advanced, accessible, unbranded and extremely fast SEO solution for your WordPress website."
2330
  msgstr ""
2331
 
2332
  #. Author of the plugin/theme
lib/css/pt.css CHANGED
@@ -1,3 +1,10 @@
 
 
 
 
 
 
 
1
  /**
2
  * Primary category selectors.
3
  */
1
+ /**
2
+ * Gutenberg only:
3
+ */
4
+ .tsf-pt-gb-selector {
5
+ margin-top: 8px;
6
+ }
7
+
8
  /**
9
  * Primary category selectors.
10
  */
lib/css/pt.min.css CHANGED
@@ -1 +1 @@
1
- .tsf-is-primary-term{font-weight:600}.tsf-primary-term-selector{margin:0;padding:0;float:right;line-height:inherit;display:block}.tsf-primary-term-selector input{vertical-align:middle;height:14px;width:14px;min-width:14px;line-height:inherit;margin:0;padding:0;pointer-events:none}.tsf-primary-term-selector input:checked:before{width:6px;height:6px;margin:3px;line-height:inherit}.tsf-primary-term-selector-help-wrap{position:absolute;top:0;right:25px}@media screen and (max-width:782px){.tsf-primary-term-selector input{height:18px;width:18px;min-width:18px}.tsf-primary-term-selector input:checked:before{width:8px;height:8px;margin:4px}}
1
+ .tsf-pt-gb-selector{margin-top:8px}.tsf-is-primary-term{font-weight:600}.tsf-primary-term-selector{margin:0;padding:0;float:right;line-height:inherit;display:block}.tsf-primary-term-selector input{vertical-align:middle;height:14px;width:14px;min-width:14px;line-height:inherit;margin:0;padding:0;pointer-events:none}.tsf-primary-term-selector input:checked:before{width:6px;height:6px;margin:3px;line-height:inherit}.tsf-primary-term-selector-help-wrap{position:absolute;top:0;right:25px}@media screen and (max-width:782px){.tsf-primary-term-selector input{height:18px;width:18px;min-width:18px}.tsf-primary-term-selector input:checked:before{width:8px;height:8px;margin:4px}}
lib/js/gutenberg.js CHANGED
@@ -10,7 +10,7 @@
10
 
11
  /**
12
  * The SEO Framework plugin
13
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
14
  *
15
  * This program is free software: you can redistribute it and/or modify
16
  * it under the terms of the GNU General Public License version 3 as published
10
 
11
  /**
12
  * The SEO Framework plugin
13
+ * Copyright (C) 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
14
  *
15
  * This program is free software: you can redistribute it and/or modify
16
  * it under the terms of the GNU General Public License version 3 as published
lib/js/installer/tsfinstaller.js DELETED
@@ -1,285 +0,0 @@
1
- /**
2
- * This file holds the TSF's TSFEM installer JS code.
3
- * Serve JavaScript as an addition, not as a means.
4
- *
5
- * @author Sybre Waaijer <https://cyberwire.nl/>
6
- * @link https://wordpress.org/plugins/autodescription/
7
- */
8
-
9
- 'use strict';
10
-
11
- /**
12
- * Hooks into WordPress' updates handler.
13
- * This is a self-constructed function assigned as an object.
14
- *
15
- * @since 3.0.6
16
- *
17
- * @constructor
18
- * @param {!jQuery} $ jQuery object.
19
- */
20
- window.tsfinstaller = function( $ ) {
21
-
22
- var $document = $( document );
23
-
24
- /**
25
- * Updates the UI appropriately after a successful TSFEM install.
26
- *
27
- * @since 3.0.6
28
- * @credit wp.updates.installImporterSuccess
29
- *
30
- * @function
31
- * @typedef {object} installTsfemSuccess
32
- * @param {object} response Response from the server.
33
- * @param {string} response.slug Slug of the installed plugin.
34
- * @param {string} response.pluginName Name of the installed plugin.
35
- * @param {string} response.activateUrl URL to activate the just installed plugin.
36
- */
37
- const installTsfemSuccess = function( response ) {
38
- wp.updates.addAdminNotice( {
39
- id: 'install-success',
40
- className: 'notice-success is-dismissible',
41
- message: wp.updates.l10n.installedMsg.replace( '%s', response.activateUrl + '&from=plugins' )
42
- } );
43
-
44
- $( '[data-slug="' + response.slug + '"]' )
45
- .removeClass( 'install-now updating-message' )
46
- .addClass( 'activate-now' )
47
- .attr({
48
- 'href': response.activateUrl + '&from=plugins',
49
- 'aria-label': wp.updates.l10n.activatePluginLabel.replace( '%s', response.pluginName )
50
- })
51
- .text( wp.updates.l10n.activatePlugin );
52
-
53
- wp.a11y.speak( wp.updates.l10n.installedMsg, 'polite' );
54
-
55
- $document.trigger( 'tsf-tsfem-install-success', response );
56
- }
57
-
58
- /**
59
- * Updates the UI appropriately after a failed TSFEM install.
60
- *
61
- * @since 3.0.6
62
- * @credit wp.updates.installImporterError
63
- *
64
- * @function
65
- * @typedef {object} installTsfemError
66
- * @param {object} response Response from the server.
67
- * @param {string} response.slug Slug of the plugin to be installed.
68
- * @param {string=} response.pluginName Optional. Name of the plugin to be installed.
69
- * @param {string} response.errorCode Error code for the error that occurred.
70
- * @param {string} response.errorMessage The error that occurred.
71
- */
72
- const installTsfemError = function( response ) {
73
- var errorMessage = wp.updates.l10n.installFailed.replace( '%s', response.errorMessage ),
74
- $installLink = $( '[data-slug="' + response.slug + '"]' ),
75
- pluginName = $installLink.data( 'name' );
76
-
77
- if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
78
- return;
79
- }
80
-
81
- if ( wp.updates.maybeHandleCredentialError( response, 'install-plugin' ) ) {
82
- return;
83
- }
84
-
85
- wp.updates.addAdminNotice( {
86
- id: response.errorCode,
87
- className: 'notice-error is-dismissible',
88
- message: errorMessage
89
- } );
90
-
91
- $installLink
92
- .removeClass( 'updating-message' )
93
- .text( wp.updates.l10n.installNow )
94
- .attr( 'aria-label', wp.updates.l10n.pluginInstallNowLabel.replace( '%s', pluginName ) );
95
-
96
- wp.a11y.speak( errorMessage, 'assertive' );
97
-
98
- $document.trigger( 'tsf-tsfem-install-error', response );
99
- }
100
-
101
- /**
102
- * Adds installation hooks on DOMContentLoaded.
103
- *
104
- * @since 3.0.6
105
- *
106
- * @function
107
- * @param {event} event
108
- */
109
- const onReady = ( event ) => {
110
- if ( ! wp || ! wp.updates ) return;
111
-
112
- var prev_addCallbacks = wp.updates._addCallbacks;
113
-
114
- /**
115
- * Hooks into the installation button, to prevent redirect.
116
- *
117
- * WordPress normally enforces a redirect when the actionable page uses index.php.
118
- * Indicating that it's not a "valid" installation page. Which is odd, as
119
- * it perfectly allows any other action. Plus it allows this action on any other page,
120
- * but the admin "main === index.php" dashboard page, too.
121
- *
122
- * @source https://github.com/WordPress/WordPress/blob/4.9-branch/wp-admin/js/updates.js#L2395-L2415
123
- */
124
- $( '#plugin_install_from_iframe' ).on( 'click', function( event ) {
125
- var target = window.parent === window ? null : window.parent,
126
- install;
127
-
128
- //= Let the default handler take over.
129
- if ( -1 === window.parent.location.pathname.indexOf( 'index.php' ) )
130
- return;
131
-
132
- //= Only enact when the slug matches.
133
- if ( $( this ).data( 'slug' ) !== tsfinstallerL10n.slug )
134
- return;
135
-
136
- $.support.postMessage = !! window.postMessage;
137
-
138
- if ( false === $.support.postMessage || null === target ) {
139
- return;
140
- }
141
-
142
- event.preventDefault();
143
-
144
- install = {
145
- action: 'install-plugin',
146
- data: {
147
- slug: $( this ).data( 'slug' )
148
- }
149
- };
150
-
151
- target.postMessage( JSON.stringify( install ), window.location.origin );
152
- } );
153
-
154
- //= Direct attach as WP is using preventDefault() when capturing.
155
- $( '#tsf-tsfem-tb' ).on( 'click', function( event ) {
156
- var canReset = false;
157
-
158
- /**
159
- * Overwrite installer callback catcher.
160
- *
161
- * This could ONLY possibly conflict with import.php as of WP-4.6.0~4.9.6.
162
- * Even then, it recovers itself via the resetter (fail-secures/safes).
163
- * Making only super-humans (if even) viable for a UI bug.
164
- */
165
- wp.updates._addCallbacks = function( data, action ) {
166
- if ( 'install-plugin' === action && tsfinstallerL10n.slug === data.slug ) {
167
- data.success = installTsfemSuccess;
168
- data.error = installTsfemError;
169
-
170
- let $button = $( '[data-slug="' + data.slug + '"]' );
171
- $button
172
- .addClass( 'updating-message' )
173
- .attr( 'aria-label', wp.updates.l10n.pluginInstallingLabel.replace( '%s', $button.data( 'name' ) ) )
174
- .text( wp.updates.l10n.installing );
175
-
176
- canReset = true;
177
- // console.log( 'overwritten' );
178
- }
179
- // console.log( 'slug: ' + data.slug );
180
-
181
- return data;
182
- }
183
-
184
- // Thread lightly: Pure magic below.
185
- $( window ).on( 'message', ( event ) => {
186
- let message;
187
- try {
188
- message = $.parseJSON( event.originalEvent.data );
189
- } catch ( e ) {
190
- return;
191
- }
192
- if ( ! message || 'undefined' === typeof message.action ) {
193
- return;
194
- }
195
- if ( message.action === 'install-plugin' ) {
196
- //= Fail safe.
197
- canReset = false;
198
- } else {
199
- //= Fail secure.
200
- canReset = true;
201
- }
202
- } );
203
- var resetTicker, cbs;
204
- const resetCb = () => {
205
- wp.updates._addCallbacks = prev_addCallbacks;
206
- clearInterval( resetTicker );
207
- $document.off( cbs, resetCb );
208
- // console.log( 'reset' );
209
- }
210
- const checkReset = () => {
211
- canReset && resetCb;
212
- // console.log( 'checked' );
213
- }
214
- const prepareReset = () => {
215
- resetTicker = setInterval( checkReset, 100 );
216
- setTimeout( resetCb, 750 );
217
- // console.log( 'prepared' );
218
- }
219
- cbs = 'wp-plugin-installing wp-plugin-install-error wp-plugin-install-success';
220
- //= Fail secure.
221
- $( 'body' ).one( 'thickbox:removed', prepareReset );
222
- $document.one( cbs, resetCb );
223
- } );
224
-
225
- $document.on( 'click', '#tsf-tsfem-install', function( event ) {
226
- var $button = $( event.target );
227
-
228
- if ( $button.hasClass( 'activate-now' ) ) {
229
- //? Follow link, activating the plugin.
230
- return;
231
- }
232
- event.preventDefault();
233
-
234
- if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
235
- return;
236
- }
237
-
238
- if ( $button.html() !== wp.updates.l10n.installing ) {
239
- $button.data( 'originaltext', $button.html() );
240
- }
241
-
242
- $button
243
- .addClass( 'updating-message' )
244
- .attr( 'aria-label', wp.updates.l10n.pluginInstallingLabel.replace( '%s', $button.data( 'name' ) ) )
245
- .text( wp.updates.l10n.installing );
246
-
247
- if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
248
- wp.updates.requestFilesystemCredentials( event );
249
-
250
- $document.on( 'credential-modal-cancel', function() {
251
- $button
252
- .removeClass( 'updating-message' )
253
- .text( wp.updates.l10n.installNow )
254
- .attr( 'aria-label', wp.updates.l10n.installNowLabel.replace( '%s', $button.data( 'name' ) ) );
255
-
256
- wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
257
- } );
258
- }
259
-
260
- wp.updates.installPlugin( {
261
- slug: $button.data( 'slug' ),
262
- pagenow: pagenow,
263
- success: installTsfemSuccess,
264
- error: installTsfemError
265
- } );
266
- } );
267
- }
268
-
269
- return {
270
- /**
271
- * Runs this script on DOMContentLoaded when WordPress Shiny Updates is
272
- * available.
273
- *
274
- * @since 3.0.6
275
- *
276
- * @function
277
- */
278
- load: function() {
279
- tsfinstallerL10n.canEnhance
280
- && $( document.body ).ready( onReady );
281
- }
282
- };
283
- }( jQuery );
284
- //= Run before jQuery.ready() === DOMContentLoaded
285
- jQuery( window.tsfinstaller.load );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/js/installer/tsfinstaller.min.js DELETED
@@ -1 +0,0 @@
1
- 'use strict';window.tsfinstaller=function(a){var b=a(document),c=function(g){wp.updates.addAdminNotice({id:'install-success',className:'notice-success is-dismissible',message:wp.updates.l10n.installedMsg.replace('%s',g.activateUrl+'&from=plugins')}),a('[data-slug="'+g.slug+'"]').removeClass('install-now updating-message').addClass('activate-now').attr({href:g.activateUrl+'&from=plugins','aria-label':wp.updates.l10n.activatePluginLabel.replace('%s',g.pluginName)}).text(wp.updates.l10n.activatePlugin),wp.a11y.speak(wp.updates.l10n.installedMsg,'polite'),b.trigger('tsf-tsfem-install-success',g)},d=function(g){var h=wp.updates.l10n.installFailed.replace('%s',g.errorMessage),i=a('[data-slug="'+g.slug+'"]'),j=i.data('name');!wp.updates.isValidResponse(g,'install')||wp.updates.maybeHandleCredentialError(g,'install-plugin')||(wp.updates.addAdminNotice({id:g.errorCode,className:'notice-error is-dismissible',message:h}),i.removeClass('updating-message').text(wp.updates.l10n.installNow).attr('aria-label',wp.updates.l10n.pluginInstallNowLabel.replace('%s',j)),wp.a11y.speak(h,'assertive'),b.trigger('tsf-tsfem-install-error',g))},f=function(){if(wp&&wp.updates){var h=wp.updates._addCallbacks;a('#plugin_install_from_iframe').on('click',function(i){var k,j=window.parent===window?null:window.parent;-1!==window.parent.location.pathname.indexOf('index.php')&&a(this).data('slug')===tsfinstallerL10n.slug&&(a.support.postMessage=!!window.postMessage,!1===a.support.postMessage||null===j||(i.preventDefault(),k={action:'install-plugin',data:{slug:a(this).data('slug')}},j.postMessage(JSON.stringify(k),window.location.origin)))}),a('#tsf-tsfem-tb').on('click',function(){var j=!1;wp.updates._addCallbacks=function(p,q){if('install-plugin'===q&&tsfinstallerL10n.slug===p.slug){p.success=c,p.error=d;var r=a('[data-slug="'+p.slug+'"]');r.addClass('updating-message').attr('aria-label',wp.updates.l10n.pluginInstallingLabel.replace('%s',r.data('name'))).text(wp.updates.l10n.installing),j=!0}return p},a(window).on('message',function(p){var q;try{q=a.parseJSON(p.originalEvent.data)}catch(r){return}q&&'undefined'!=typeof q.action&&('install-plugin'===q.action?j=!1:j=!0)});var k,l,m=function(){wp.updates._addCallbacks=h,clearInterval(k),b.off(l,m)},n=function(){};l='wp-plugin-installing wp-plugin-install-error wp-plugin-install-success',a('body').one('thickbox:removed',function o(){k=setInterval(n,100),setTimeout(m,750)}),b.one(l,m)}),b.on('click','#tsf-tsfem-install',function(i){var j=a(i.target);j.hasClass('activate-now')||(i.preventDefault(),j.hasClass('updating-message')||j.hasClass('button-disabled')||(j.html()!==wp.updates.l10n.installing&&j.data('originaltext',j.html()),j.addClass('updating-message').attr('aria-label',wp.updates.l10n.pluginInstallingLabel.replace('%s',j.data('name'))).text(wp.updates.l10n.installing),wp.updates.shouldRequestFilesystemCredentials&&!wp.updates.ajaxLocked&&(wp.updates.requestFilesystemCredentials(i),b.on('credential-modal-cancel',function(){j.removeClass('updating-message').text(wp.updates.l10n.installNow).attr('aria-label',wp.updates.l10n.installNowLabel.replace('%s',j.data('name'))),wp.a11y.speak(wp.updates.l10n.updateCancel,'polite')})),wp.updates.installPlugin({slug:j.data('slug'),pagenow:pagenow,success:c,error:d})))})}};return{load:function load(){tsfinstallerL10n.canEnhance&&a(document.body).ready(f)}}}(jQuery),jQuery(window.tsfinstaller.load);
 
lib/js/media.js CHANGED
@@ -8,7 +8,7 @@
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2018-2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
lib/js/pt-gb.js ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file holds The SEO Framework plugin's JS code for Primary Term Selection for Gutenberg.
3
+ *
4
+ * @author Sybre Waaijer <https://cyberwire.nl/>
5
+ * @link <https://wordpress.org/plugins/autodescription/>
6
+ */
7
+
8
+ /**
9
+ * The SEO Framework plugin
10
+ * Copyright (C) 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
11
+ *
12
+ * This program is free software: you can redistribute it and/or modify
13
+ * it under the terms of the GNU General Public License version 3 as published
14
+ * by the Free Software Foundation.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ /**
28
+ * Holds tsfPTGB (tsf primary term Gutenberg) values in an object to avoid polluting global namespace.
29
+ *
30
+ * This is a self-constructed function assigned as an object.
31
+ *
32
+ * @since 3.2.0
33
+ *
34
+ * @constructor
35
+ * @param {!jQuery} $ jQuery object.
36
+ */
37
+ window.tsfPTGB = function( $ ) {
38
+
39
+ /**
40
+ * Data property injected by WordPress l10n handler.
41
+ *
42
+ * @since 3.2.0
43
+ * @access private
44
+ * @type {(Object<string, *>)|boolean|null} l10n Localized strings
45
+ */
46
+ var l10n = 'undefined' !== typeof tsfPTL10n && tsfPTL10n;
47
+
48
+ const { addFilter } = wp.hooks;
49
+ const { createElement, Fragment } = wp.element;
50
+ const { SelectControl } = wp.components;
51
+ const { addQueryArgs } = wp.url;
52
+ const apiFetch = wp.apiFetch;
53
+ const { invoke } = lodash;
54
+
55
+ const DEFAULT_QUERY = {
56
+ per_page: -1,
57
+ orderby: 'id',
58
+ order: 'asc',
59
+ _fields: 'id,name',
60
+ };
61
+
62
+ /**
63
+ * Initializes primary term selection for gutenberg.
64
+ *
65
+ * @function
66
+ * @return {undefined}
67
+ */
68
+ const _initPrimaryTerm = () => {
69
+
70
+ if ( ! tsf.hasInput || ! Object.keys( l10n.taxonomies ).length )
71
+ return;
72
+
73
+ let taxonomies = l10n.taxonomies,
74
+ inputTemplate = wp.template( 'tsf-primary-term-selector' ),
75
+ registeredFields = {};
76
+
77
+ const geti18n = ( taxonomy, what ) => what in taxonomies[ taxonomy ].i18n && taxonomies[ taxonomy ].i18n[ what ] || '';
78
+
79
+ const getPrimaryTermHolder = taxonomy => document.getElementById( `autodescription[_primary_term_${taxonomy}]` );
80
+ const getPrimaryTermID = taxonomy => +getPrimaryTermHolder( taxonomy ).value;
81
+ const setPrimaryTermID = ( taxonomy, id ) => +( getPrimaryTermHolder( taxonomy ).value = +id );
82
+
83
+ const addDataInput = ( taxonomy ) => {
84
+ let wrap = document.getElementById( 'tsf-gutenberg-data-holder' );
85
+ if ( ! wrap ) return registeredFields[ taxonomy ] = false;
86
+
87
+ let template = inputTemplate( { 'taxonomy' : taxonomies[ taxonomy ] } );
88
+ return registeredFields[ taxonomy ] = !! $( template ).appendTo( wrap );
89
+ }
90
+ const hasDataInput = ( taxonomy ) => registeredFields[ taxonomy ];
91
+
92
+ const revalidatePrimaryTerm = ( taxonomy, terms ) => {
93
+ if ( terms.indexOf( getPrimaryTermID( taxonomy ) ) < 0 ) {
94
+ // Set to first found term, or empty the value if no term is selected.
95
+ if ( 0 in terms ) {
96
+ setPrimaryTermID( taxonomy, terms[0] );
97
+ } else {
98
+ setPrimaryTermID( taxonomy, 0 );
99
+ }
100
+ }
101
+ }
102
+
103
+ // Hook data handles.
104
+ (()=>{
105
+ for ( let taxonomy in taxonomies ) {
106
+ addDataInput( taxonomy );
107
+ }
108
+ })();
109
+
110
+ var dataStores = {};
111
+ class DataStore {
112
+ constructor( slug ) {
113
+ this.slug = slug;
114
+ this.reset();
115
+ }
116
+
117
+ registeredData() {
118
+ return !! Object.keys( this.data ).length;
119
+ }
120
+
121
+ reset() {
122
+ this.data = {};
123
+ }
124
+
125
+ read() {
126
+ return this.data;
127
+ }
128
+
129
+ get( what ) {
130
+ return what in this.data && this.data[ what ] || null;
131
+ }
132
+
133
+ set( what, value ) {
134
+ return this.data[ what ] = value;
135
+ }
136
+ }
137
+ const createStore = slug => dataStores[ slug ] = new DataStore( slug );
138
+ const getStore = slug => dataStores[ slug ] || createStore( slug );
139
+
140
+ class PrimaryTermSelectorHandler extends React.Component {
141
+ constructor( props ) {
142
+ super( props );
143
+
144
+ this.state = {
145
+ loading: true,
146
+ }
147
+ }
148
+
149
+ componentDidMount() {
150
+ this.updateData();
151
+ if ( this.dsAccess().registeredData() ) {
152
+ this.setState( {
153
+ loading: false,
154
+ } );
155
+ }
156
+ }
157
+
158
+ componentWillUnmount() {
159
+ invoke( this.fetchRequest, [ 'abort' ] );
160
+ invoke( this.addRequest, [ 'abort' ] );
161
+ }
162
+
163
+ componentDidUpdate( prevProps, prevState ) {
164
+ this.updateData();
165
+ if ( this.props.terms.length > 2 && ! this.dsAccess().get( 'availableTerms' ) ) {
166
+ this.fetchTerms();
167
+ } else if ( this.props.terms !== prevProps.terms ) {
168
+ let newID = this.props.terms.filter( termID => prevProps.terms.indexOf( termID ) === -1 );
169
+ if ( newID.length && ! this.isTermAvailable( newID[0] ) ) {
170
+ this.fetchTerms();
171
+ }
172
+ }
173
+ }
174
+
175
+ updateData() {
176
+ if ( ! this.dsAccess().registeredData() ) {
177
+ this.dsAccess().set( 'availableTerms', [] );
178
+ this.fetchTerms();
179
+ }
180
+
181
+ this.dsAccess().set( 'selectedTerms', this.props.terms );
182
+ }
183
+
184
+ updateTerms() {
185
+ this.updateData();
186
+ }
187
+
188
+ dsAccess() {
189
+ return getStore( this.props.slug );
190
+ }
191
+
192
+ isTermAvailable( id ) {
193
+ let availableTerms = this.dsAccess().get( 'availableTerms' );
194
+ return availableTerms.some( term => term.id === id );
195
+ }
196
+
197
+ fetchTerms() {
198
+ const { taxonomy } = this.props;
199
+ if ( ! taxonomy ) return;
200
+
201
+ this.setState( {
202
+ selectedTerms: this.props.terms,
203
+ loading: true,
204
+ } );
205
+
206
+ this.fetchRequest = apiFetch( {
207
+ path: addQueryArgs( `/wp/v2/${ taxonomy.rest_base }`, DEFAULT_QUERY ),
208
+ } );
209
+ this.fetchRequest.then(
210
+ ( terms ) => { // resolve
211
+ this.fetchRequest = null;
212
+ this.setState( {
213
+ loading: false,
214
+ } );
215
+ this.dsAccess().set( 'availableTerms', terms );
216
+ this.forceUpdate();
217
+ },
218
+ ( xhr ) => { // reject
219
+ if ( xhr.statusText === 'abort' ) {
220
+ return;
221
+ }
222
+ this.fetchRequest = null;
223
+ this.setState( {
224
+ loading: false,
225
+ } );
226
+ this.forceUpdate();
227
+ }
228
+ );
229
+ }
230
+ }
231
+
232
+ class TermSelector extends PrimaryTermSelectorHandler {
233
+ constructor( props ) {
234
+ super( props );
235
+
236
+ this.onChange = this.onChange.bind( this );
237
+ }
238
+
239
+ getTermName( id ) {
240
+ let availableTerms = this.dsAccess().get( 'availableTerms' );
241
+
242
+ let term = availableTerms.find( term => term.id === id );
243
+ return term && term.name || '';
244
+ }
245
+
246
+ getSelectOptions() {
247
+ return this.dsAccess().get( 'selectedTerms' ).sort().map( id => {
248
+ return { value: id, label: this.getTermName( id ) };
249
+ } );
250
+ }
251
+
252
+ onChange( value ) {
253
+ this.setState( {
254
+ options: this.getSelectOptions(),
255
+ value: setPrimaryTermID( this.props.slug, value )
256
+ } );
257
+ tsf.registerChange();
258
+ }
259
+
260
+ isDisabled() {
261
+ return !! this.state.loading;
262
+ }
263
+
264
+ render() {
265
+ this.updateData();
266
+ return createElement(
267
+ SelectControl,
268
+ {
269
+ label: geti18n( this.props.slug, 'selectPrimary' ),
270
+ value: getPrimaryTermID( this.props.slug ),
271
+ className: 'tsf-pt-gb-selector',
272
+ onChange: this.onChange,
273
+ options: this.state.loading ? '' : this.getSelectOptions(),
274
+ disabled: this.isDisabled(),
275
+ },
276
+ );
277
+ }
278
+ }
279
+
280
+ const primaryTermSelectorFilter = PostTaxonomyType => class extends PrimaryTermSelectorHandler {
281
+ initSelectors() {
282
+ const { slug, terms } = this.props;
283
+ if ( hasDataInput( slug ) ) {
284
+ revalidatePrimaryTerm( slug, terms );
285
+ if ( terms.length > 1 ) {
286
+ return createElement(
287
+ Fragment,
288
+ {},
289
+ createElement(
290
+ TermSelector,
291
+ this.props,
292
+ )
293
+ );
294
+ }
295
+ }
296
+ return null;
297
+ }
298
+
299
+ render() {
300
+ if ( ! this.props.slug in taxonomies ) return;
301
+
302
+ return createElement(
303
+ Fragment,
304
+ {},
305
+ createElement(
306
+ PostTaxonomyType,
307
+ this.props,
308
+ ),
309
+ this.initSelectors()
310
+ );
311
+ }
312
+ }
313
+
314
+ addFilter(
315
+ 'editor.PostTaxonomyType',
316
+ 'tsf/pt',
317
+ primaryTermSelectorFilter,
318
+ 20
319
+ );
320
+ }
321
+
322
+ //? IE11 Object.assign() alternative.
323
+ return $.extend( {
324
+ /**
325
+ * Initialises all aspects of the scripts.
326
+ * You shouldn't call this.
327
+ *
328
+ * @since 3.2.0
329
+ * @access protected
330
+ *
331
+ * @function
332
+ * @return {undefined}
333
+ */
334
+ load: function() {
335
+ $( document.body ).on( 'tsf-onload', _initPrimaryTerm );
336
+ }
337
+ }, {} );
338
+ }( jQuery );
339
+ jQuery( window.tsfPTGB.load );
lib/js/pt-gb.min.js ADDED
@@ -0,0 +1 @@
 
1
+ 'use strict';window.tsfPTGB=function(a){var b='undefined'!=typeof tsfPTL10n&&tsfPTL10n;const{addFilter:c}=wp.hooks,{createElement:d,Fragment:e}=wp.element,{SelectControl:f}=wp.components,{addQueryArgs:g}=wp.url,h=wp.apiFetch,{invoke:i}=lodash,j={per_page:-1,orderby:'id',order:'asc',_fields:'id,name'},k=()=>{if(tsf.hasInput&&Object.keys(b.taxonomies).length){let l=b.taxonomies,m=wp.template('tsf-primary-term-selector'),n={};const o=(C,D)=>D in l[C].i18n&&l[C].i18n[D]||'',p=C=>document.getElementById(`autodescription[_primary_term_${C}]`),q=C=>+p(C).value,r=(C,D)=>+(p(C).value=+D),s=C=>{let D=document.getElementById('tsf-gutenberg-data-holder');if(!D)return n[C]=!1;let E=m({taxonomy:l[C]});return n[C]=!!a(E).appendTo(D)},t=C=>n[C],u=(C,D)=>{0>D.indexOf(q(C))&&(0 in D?r(C,D[0]):r(C,0))};(()=>{for(let C in l)s(C)})();var v={};class w{constructor(C){this.slug=C,this.reset()}registeredData(){return!!Object.keys(this.data).length}reset(){this.data={}}read(){return this.data}get(C){return C in this.data&&this.data[C]||null}set(C,D){return this.data[C]=D}}const x=C=>v[C]=new w(C),y=C=>v[C]||x(C);class z extends React.Component{constructor(C){super(C),this.state={loading:!0}}componentDidMount(){this.updateData(),this.dsAccess().registeredData()&&this.setState({loading:!1})}componentWillUnmount(){i(this.fetchRequest,['abort']),i(this.addRequest,['abort'])}componentDidUpdate(C){if(this.updateData(),2<this.props.terms.length&&!this.dsAccess().get('availableTerms'))this.fetchTerms();else if(this.props.terms!==C.terms){let E=this.props.terms.filter(F=>-1===C.terms.indexOf(F));E.length&&!this.isTermAvailable(E[0])&&this.fetchTerms()}}updateData(){this.dsAccess().registeredData()||(this.dsAccess().set('availableTerms',[]),this.fetchTerms()),this.dsAccess().set('selectedTerms',this.props.terms)}updateTerms(){this.updateData()}dsAccess(){return y(this.props.slug)}isTermAvailable(C){let D=this.dsAccess().get('availableTerms');return D.some(E=>E.id===C)}fetchTerms(){const{taxonomy:C}=this.props;C&&(this.setState({selectedTerms:this.props.terms,loading:!0}),this.fetchRequest=h({path:g(`/wp/v2/${C.rest_base}`,j)}),this.fetchRequest.then(D=>{this.fetchRequest=null,this.setState({loading:!1}),this.dsAccess().set('availableTerms',D),this.forceUpdate()},D=>{'abort'===D.statusText||(this.fetchRequest=null,this.setState({loading:!1}),this.forceUpdate())}))}}class A extends z{constructor(C){super(C),this.onChange=this.onChange.bind(this)}getTermName(C){let D=this.dsAccess().get('availableTerms'),E=D.find(F=>F.id===C);return E&&E.name||''}getSelectOptions(){return this.dsAccess().get('selectedTerms').sort().map(C=>{return{value:C,label:this.getTermName(C)}})}onChange(C){this.setState({options:this.getSelectOptions(),value:r(this.props.slug,C)}),tsf.registerChange()}isDisabled(){return!!this.state.loading}render(){return this.updateData(),d(f,{label:o(this.props.slug,'selectPrimary'),value:q(this.props.slug),className:'tsf-pt-gb-selector',onChange:this.onChange,options:this.state.loading?'':this.getSelectOptions(),disabled:this.isDisabled()})}}c('editor.PostTaxonomyType','tsf/pt',C=>class extends z{initSelectors(){const{slug:D,terms:E}=this.props;return t(D)&&(u(D,E),1<E.length)?d(e,{},d(A,this.props)):null}render(){return!this.props.slug in l?void 0:d(e,{},d(C,this.props),this.initSelectors())}},20)}};return a.extend({load:function(){a(document.body).on('tsf-onload',k)}},{})}(jQuery),jQuery(window.tsfPTGB.load);
lib/js/pt.js CHANGED
@@ -8,7 +8,7 @@
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
lib/js/tsf-gbc.js ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file holds The SEO Framework plugin's JS code for forwards compatibility with Gutenberg.
3
+ *
4
+ * This is an intermediate step where I hijack old code to support the new WordPress editor.
5
+ * The current code will be rewritten later. Do not rely on this file. However, the JQ triggers
6
+ * will sustain support until further notice.
7
+ *
8
+ * @author Sybre Waaijer <https://cyberwire.nl/>
9
+ * @link <https://wordpress.org/plugins/autodescription/>
10
+ */
11
+
12
+ /**
13
+ * The SEO Framework plugin
14
+ * Copyright (C) 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
15
+ *
16
+ * This program is free software: you can redistribute it and/or modify
17
+ * it under the terms of the GNU General Public License version 3 as published
18
+ * by the Free Software Foundation.
19
+ *
20
+ * This program is distributed in the hope that it will be useful,
21
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ * GNU General Public License for more details.
24
+ *
25
+ * You should have received a copy of the GNU General Public License
26
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
27
+ */
28
+
29
+ 'use strict';
30
+
31
+ /**
32
+ * Holds tsfGBC (tsf Gutenberg Compat) values in an object to avoid polluting global namespace.
33
+ *
34
+ * This is a self-constructed function assigned as an object.
35
+ *
36
+ * @since 3.2.0
37
+ *
38
+ * @constructor
39
+ * @param {!jQuery} $ jQuery object.
40
+ */
41
+ window.tsfGBC = function( $ ) {
42
+
43
+ // const { addFilter } = wp.hooks;
44
+ // const { addQueryArgs } = wp.url;
45
+ // const apiFetch = wp.apiFetch;
46
+
47
+ const editor = wp.data.select( 'core/editor' );
48
+ const { debounce } = lodash;
49
+
50
+ /**
51
+ * Data property injected by our Scripts l10n handler.
52
+ *
53
+ * @since 3.2.0
54
+ * @access private
55
+ * @type {(Object<string, *>)|boolean|null} l10n Localized strings
56
+ */
57
+ let l10n = 'undefined' !== typeof tsfGBCL10n && tsfGBCL10n;
58
+
59
+ /**
60
+ * Post data holder.
61
+ *
62
+ * @since 3.2.0
63
+ * @access private
64
+ * @type {(Object<string, *>)|boolean|null} post data
65
+ */
66
+ let postData;
67
+
68
+ /**
69
+ * Retrieves post attribute.
70
+ *
71
+ * @since 3.2.0
72
+ * @access private
73
+ *
74
+ * @function
75
+ * @param {String} attribute
76
+ * @return {mixed|null}
77
+ */
78
+ function getPostAttribute( attribute ) {
79
+ return editor.getEditedPostAttribute( attribute );
80
+ }
81
+
82
+ /**
83
+ * Sets editor data.
84
+ *
85
+ * @since 3.2.0
86
+ * @since 3.2.2 Now sets post visibility.
87
+ * @access private
88
+ *
89
+ * @function
90
+ */
91
+ function setData() {
92
+ postData = {
93
+ title: getPostAttribute( 'title' ),
94
+ link: editor.getPermalink(),
95
+ content: getPostAttribute( 'content' ),
96
+ excerpt: getPostAttribute( 'excerpt' ),
97
+ visibility: editor.getEditedPostVisibility(),
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Returns known editor data.
103
+ *
104
+ * @since 3.2.0
105
+ * @access private
106
+ *
107
+ * @function
108
+ * @param {String} type
109
+ * @return {mixed|null}
110
+ */
111
+ function getData( type ) {
112
+ return postData[ type ] || null;
113
+ }
114
+
115
+ /**
116
+ * Assesses the editor data, and dispatches the data when changed.
117
+ *
118
+ * @since 3.2.0
119
+ * @since 3.2.2 Now dispatches visibility changes.
120
+ * @access private
121
+ *
122
+ * @function
123
+ * @return {undefined}
124
+ */
125
+ function assessData() {
126
+ let oldData = postData;
127
+ setData();
128
+ if ( oldData.title !== postData.title ) {
129
+ triggerUpdate( 'title' );
130
+ }
131
+ if ( oldData.link !== postData.link ) {
132
+ triggerUpdate( 'link' );
133
+ }
134
+ if ( oldData.content !== postData.content ) {
135
+ triggerUpdate( 'content' );
136
+ }
137
+ if ( oldData.excerpt !== postData.excerpt ) {
138
+ triggerUpdate( 'excerpt' );
139
+ }
140
+ if ( oldData.visibility !== postData.visibility ) {
141
+ triggerUpdate( 'visibility' );
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Dispatches an event of a data type, also sends data of set type.
147
+ *
148
+ * @since 3.2.0
149
+ * @access public
150
+ *
151
+ * @function
152
+ * @param {String} type
153
+ * @return {undefined}
154
+ */
155
+ const triggerUpdate = ( type ) => {
156
+ $( document ).trigger( 'tsf-updated-gutenberg-' + type, [ getData( type ) ] );
157
+ }
158
+
159
+ /**
160
+ * Maintains asynchronous save states.
161
+ * @since 3.2.0
162
+ * @access private
163
+ * @type {boolean} saved
164
+ * @type {boolean} queueSaveDone
165
+ */
166
+ let saved = false, queueSaveDone = false;
167
+ /**
168
+ * Checks if the document is saved successfully, and then dispatches an event if so.
169
+ *
170
+ * @since 3.2.0
171
+ * @access private
172
+ *
173
+ * @function
174
+ * @return {undefined}
175
+ */
176
+ function saveDispatcher() {
177
+ if ( ! saved && ( editor.isSavingPost() || editor.isAutosavingPost() ) ) {
178
+ saved = true;
179
+ } else if ( saved ) {
180
+ if ( editor.didPostSaveRequestSucceed() ) {
181
+ dispatchSavedEvent();
182
+ } else {
183
+ saved = false;
184
+ }
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Dispatches save event.
190
+ *
191
+ * @since 3.2.0
192
+ * @access private
193
+ *
194
+ * @function
195
+ * @return {undefined}
196
+ */
197
+ function dispatchSavedEvent() {
198
+ saved = false;
199
+ if ( editor.isPostSavingLocked() ) {
200
+ // Retry again.
201
+ queueSaveDone = true;
202
+ debounce( dispatchSavedEvent, 500 );
203
+ } else if ( ! queueSaveDone ) {
204
+ $( document ).trigger( 'tsf-gutenberg-saved-document' );
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Initializes Gutenberg's compatibility and dispatches event hooks.
210
+ *
211
+ * @since 3.2.0
212
+ * @access private
213
+ *
214
+ * @function
215
+ * @return {undefined}
216
+ */
217
+ const _initCompat = () => {
218
+ wp.data.subscribe( debounce( assessData, 300 ) );
219
+ wp.data.subscribe( saveDispatcher );
220
+ // Set all values prior debouncing.
221
+ setTimeout( () => {
222
+ setData();
223
+
224
+ triggerUpdate( 'title' );
225
+ triggerUpdate( 'link' );
226
+ triggerUpdate( 'content' );
227
+ triggerUpdate( 'excerpt' );
228
+ triggerUpdate( 'visibility' );
229
+
230
+ $( document ).trigger( 'tsf-subscribed-to-gutenberg' );
231
+ } );
232
+ }
233
+
234
+ //? IE11 Object.assign() alternative.
235
+ return $.extend( {
236
+ /**
237
+ * Initialises all aspects of the scripts.
238
+ * You shouldn't call this.
239
+ *
240
+ * @since 3.2.0
241
+ * @access protected
242
+ *
243
+ * @function
244
+ * @return {undefined}
245
+ */
246
+ load: function() {
247
+ $( document.body ).on( 'tsf-onload', _initCompat );
248
+ }
249
+ }, {
250
+ triggerUpdate,
251
+ } );
252
+ }( jQuery );
253
+ jQuery( window.tsfGBC.load );
lib/js/tsf-gbc.min.js ADDED
@@ -0,0 +1 @@
 
1
+ 'use strict';window.tsfGBC=function(a){function b(p){return h.getEditedPostAttribute(p)}function c(){k={title:b('title'),link:h.getPermalink(),content:b('content'),excerpt:b('excerpt'),visibility:h.getEditedPostVisibility()}}function d(p){return k[p]||null}function e(){let p=k;c(),p.title!==k.title&&l('title'),p.link!==k.link&&l('link'),p.content!==k.content&&l('content'),p.excerpt!==k.excerpt&&l('excerpt'),p.visibility!==k.visibility&&l('visibility')}function f(){!m&&(h.isSavingPost()||h.isAutosavingPost())?m=!0:m&&(h.didPostSaveRequestSucceed()?g():m=!1)}function g(){m=!1,h.isPostSavingLocked()?(n=!0,i(g,500)):!n&&a(document).trigger('tsf-gutenberg-saved-document')}const h=wp.data.select('core/editor'),{debounce:i}=lodash;let j='undefined'!=typeof tsfGBCL10n&&tsfGBCL10n,k;const l=p=>{a(document).trigger('tsf-updated-gutenberg-'+p,[d(p)])};let m=!1,n=!1;const o=()=>{wp.data.subscribe(i(e,300)),wp.data.subscribe(f),setTimeout(()=>{c(),l('title'),l('link'),l('content'),l('excerpt'),l('visibility'),a(document).trigger('tsf-subscribed-to-gutenberg')})};return a.extend({load:function(){a(document.body).on('tsf-onload',o)}},{triggerUpdate:l})}(jQuery),jQuery(window.tsfGBC.load);
lib/js/tsf.js CHANGED
@@ -8,7 +8,7 @@
8
 
9
  /**
10
  * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
@@ -31,6 +31,9 @@
31
  * "transform-es2015-modules-commonjs"
32
  * IE11 supports everything else implemented, even if it has cost us headaches.
33
  * @see tsf.browseUnhappy
 
 
 
34
  */
35
 
36
  /**
@@ -736,7 +739,7 @@ window.tsf = {
736
  $additionsElement.css( { 'maxWidth' : 'initial' } );
737
 
738
  switch ( hoverAdditionsPlacement ) {
739
- case 'before' :
740
  let additionsWidth = $additionsElement[0].getBoundingClientRect().width;
741
 
742
  additionsWidth = additionsMaxWidth < additionsWidth ? additionsMaxWidth : additionsWidth;
@@ -749,7 +752,7 @@ window.tsf = {
749
  additionsOffset += leftOffset;
750
  break;
751
 
752
- case 'after' :
753
  additionsOffset += leftOffset + textWidth + prefixMaxWidth;
754
  break;
755
  }
@@ -799,22 +802,22 @@ window.tsf = {
799
 
800
  if ( _hasPrefixValue ) {
801
  switch ( hoverPrefixPlacement ) {
802
- case 'before' :
803
  _placeholder = _hoverPrefixValue + _placeholder;
804
  break;
805
 
806
- case 'after' :
807
  _placeholder = _placeholder + _hoverPrefixValue;
808
  break;
809
  }
810
  }
811
  if ( _hasAdditionsValue ) {
812
  switch ( hoverAdditionsPlacement ) {
813
- case 'before' :
814
  _placeholder = _hoverAdditionsValue + _placeholder;
815
  break;
816
 
817
- case 'after' :
818
  _placeholder = _placeholder + _hoverAdditionsValue;
819
  break;
820
  }
@@ -848,22 +851,22 @@ window.tsf = {
848
  } else {
849
  if ( hoverPrefixValue.length ) {
850
  switch ( hoverPrefixPlacement ) {
851
- case 'before' :
852
  text = hoverPrefixValue + text;
853
  break;
854
 
855
- case 'after' :
856
  text = text + hoverPrefixValue;
857
  break;
858
  }
859
  }
860
  if ( hoverAdditionsValue.length ) {
861
  switch ( hoverAdditionsPlacement ) {
862
- case 'before' :
863
  text = hoverAdditionsValue + text;
864
  break;
865
 
866
- case 'after' :
867
  text = text + hoverAdditionsValue;
868
  break;
869
  }
@@ -896,9 +899,9 @@ window.tsf = {
896
  if ( ! pixels || ! reference ) return;
897
 
898
  let test = {
899
- 'e': pixels,
900
- 'text' : tsf.unescapeString( reference.innerHTML ),
901
- 'guidelines' : tsf.params.inputGuidelines.title.search.pixels,
902
  };
903
 
904
  tsf.updatePixelCounter( test );
@@ -984,40 +987,57 @@ window.tsf = {
984
  jQuery( '#tsf-title-tagline-toggle :input' ).on( 'click', changeHomePageAdditionsVisibility );
985
 
986
  /**
987
- * Updates private/protected title prefix upon Post visibility switch.
988
  *
989
  * @function
990
  * @param {!jQuery.Event} event
991
  * @return {undefined}
992
  */
993
- const updateVisibility = function( event ) {
994
- let value = jQuery( '#visibility' ).find( 'input:radio:checked' ).val();
995
 
996
  isPrivate = false;
997
  isPasswordProtected = false;
998
 
999
- switch ( value ) {
1000
- case 'password' :
1001
- let p = jQuery( '#visibility' ).find( '#post_password' ).val();
1002
- // A falsy-password (like '0'), will return true in "SOME OF" WP's front-end PHP, false in WP's JS before submitting...
1003
- // It won't invoke WordPress' password protection. TODO FIXME: file WP Core bug report.
1004
- isPasswordProtected = p ? !! p.length : false;
1005
  break;
1006
 
1007
- case 'private' :
1008
  isPrivate = true;
1009
  break;
1010
 
1011
- default :
1012
- case 'public' :
1013
  break;
1014
  }
1015
-
1016
- //* @TODO move all of the above to a global state handler?
1017
  setHoverPrefixValue();
1018
  enqueueTriggerInput();
1019
  }
1020
- jQuery( '#visibility .save-post-visibility' ).on( 'click', updateVisibility );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1021
 
1022
  /**
1023
  * Updates used separator and all examples thereof.
@@ -1097,7 +1117,7 @@ window.tsf = {
1097
  unregisteredTriggerBuffer = setTimeout( triggerUnregisteredInput, 10 );
1098
  }
1099
  jQuery( window ).on( 'tsf-flex-resize', enqueueUnregisteredInputTrigger );
1100
- jQuery( '#homepage-tab-general' ).on( 'tsf-tab-toggled', enqueueUnregisteredInputTrigger );
1101
  jQuery( '#tsf-flex-inpost-tab-general' ).on( 'tsf-flex-tab-toggled', enqueueUnregisteredInputTrigger );
1102
  enqueueUnregisteredInputTrigger();
1103
 
@@ -1135,12 +1155,11 @@ window.tsf = {
1135
  * Updates default title placeholder.
1136
  *
1137
  * @function
1138
- * @param {!jQuery.Event} event
1139
  * @return {undefined}
1140
  */
1141
- const updateDefaultTitle = function( event ) {
1142
- let val = event.target.value;
1143
- val = val.trim();
1144
 
1145
  if ( val.length ) {
1146
  defaultTitle = tsf.escapeString( stripTitleTags ? tsf.stripTags( val ) : val );
@@ -1152,7 +1171,8 @@ window.tsf = {
1152
  }
1153
  //= The home page listens to a static preset value. Update all others.
1154
  if ( ! tsf.states.isHome ) {
1155
- jQuery( '#edittag #name, #titlewrap #title' ).on( 'input', updateDefaultTitle );
 
1156
  }
1157
 
1158
  /**
@@ -1362,7 +1382,7 @@ window.tsf = {
1362
  $prefix.css( 'display', 'inline' );
1363
  }
1364
  }
1365
- jQuery( '#title-prefixes-toggle :input' ).on( 'click', adjustPrefixExample );
1366
  },
1367
 
1368
  /**
@@ -1378,43 +1398,14 @@ window.tsf = {
1378
 
1379
  if ( ! tsf.hasInput ) return;
1380
 
1381
- let $descriptions = jQuery( "#autodescription_description, #autodescription-meta\\[description\\], #autodescription-site-settings\\[homepage_description\\]" );
 
 
 
 
1382
 
1383
  if ( ! $descriptions.length ) return;
1384
 
1385
- let separator = tsf.params.descriptionSeparator;
1386
-
1387
- /**
1388
- * Updates used separator and all examples thereof.
1389
- *
1390
- * @function
1391
- * @param {!jQuery.Event} event
1392
- * @return {undefined}
1393
- */
1394
- const updateSeparator = function( event ) {
1395
- let val = jQuery( event.target ).val(),
1396
- newSep = '';
1397
-
1398
- switch ( val ) {
1399
- case 'pipe' :
1400
- newSep = '|';
1401
- break;
1402
-
1403
- case 'dash' :
1404
- newSep = '-';
1405
- break;
1406
-
1407
- default :
1408
- newSep = jQuery( '<div/>' ).html( "&" + val + ";" ).text();
1409
- break;
1410
- }
1411
- separator = newSep;
1412
- jQuery( "#autodescription-descsep-js" ).text( ' ' + separator + ' ' );
1413
-
1414
- enqueueTriggerInput();
1415
- }
1416
- jQuery( '#tsf-description-separator input' ).on( 'click', updateSeparator );
1417
-
1418
  // TODO: We need to set a predicted description value, so we can toggle it.
1419
  // const updateAutodescription = function( event ) {
1420
  // let checked = jQuery( event.target ).checked();
@@ -1442,8 +1433,8 @@ window.tsf = {
1442
 
1443
  let test = {
1444
  'e': counter,
1445
- 'text' : tsf.unescapeString( reference.innerHTML ),
1446
- 'guidelines' : tsf.params.inputGuidelines.description.search.chars,
1447
  };
1448
 
1449
  tsf.updateCharacterCounter( test );
@@ -1539,7 +1530,7 @@ window.tsf = {
1539
  clearTimeout( unregisteredTriggerBuffer );
1540
  unregisteredTriggerBuffer = setTimeout( triggerUnregisteredInput, 10 );
1541
  }
1542
- jQuery( '#homepage-tab-general' ).on( 'tsf-tab-toggled', enqueueUnregisteredInputTrigger );
1543
  jQuery( '#tsf-flex-inpost-tab-general' ).on( 'tsf-flex-tab-toggled', enqueueUnregisteredInputTrigger );
1544
  enqueueUnregisteredInputTrigger();
1545
 
@@ -1560,6 +1551,13 @@ window.tsf = {
1560
  }
1561
  }
1562
  jQuery( document ).on( 'postbox-toggled', triggerPostboxSynchronousUnregisteredInput );
 
 
 
 
 
 
 
1563
  },
1564
 
1565
  /**
@@ -1598,21 +1596,21 @@ window.tsf = {
1598
  let val = '';
1599
  switchActive:
1600
  switch ( what ) {
1601
- case 'twitter' :
1602
  val = twTitleValue;
1603
  if ( twLocked || twPHLocked ) {
1604
  val = val.length ? val : $twTitle.prop( 'placeholder' );
1605
  break switchActive;
1606
  }
1607
  // get next if not set.
1608
- case 'og' :
1609
  val = val.length ? val : ogTitleValue;
1610
  if ( ogLocked || ogPHLocked ) {
1611
  val = val.length ? val : $ogTitle.prop( 'placeholder' );
1612
  break switchActive;
1613
  }
1614
  // get next if not set.
1615
- case 'reference' :
1616
  val = val.length ? val : referenceValue;
1617
  break;
1618
  }
@@ -1720,21 +1718,21 @@ window.tsf = {
1720
  let val = '';
1721
  switchActive:
1722
  switch ( what ) {
1723
- case 'twitter' :
1724
  val = twDescValue;
1725
  if ( twLocked || twPHLocked ) {
1726
  val = val.length ? val : $twDesc.prop( 'placeholder' );
1727
  break switchActive;
1728
  }
1729
  // get next if not set.
1730
- case 'og' :
1731
  val = val.length ? val : ogDescValue;
1732
  if ( ogLocked || ogPHLocked ) {
1733
  val = val.length ? val : $ogDesc.prop( 'placeholder' );
1734
  break switchActive;
1735
  }
1736
  // get next if not set.
1737
- case 'reference' :
1738
  if ( ! val.length ) {
1739
  if ( $descriptions.val().length ) {
1740
  val = referenceValue;
@@ -1810,6 +1808,27 @@ window.tsf = {
1810
  $twDesc.on( 'input.tsfUpdateOgDesc', updateTwDesc );
1811
  },
1812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1813
  /**
1814
  * Initializes Webmasters' meta input.
1815
  *
@@ -2222,48 +2241,6 @@ window.tsf = {
2222
  $handles.on( 'click.tsfPostboxes', handleClick );
2223
  },
2224
 
2225
- /**
2226
- * Toggle tagline within the Description Example.
2227
- *
2228
- * @since 2.3.4
2229
- *
2230
- * @function
2231
- * @param {!jQuery.Event} event
2232
- * @return {undefined}
2233
- */
2234
- taglineToggleDesc: function( event ) {
2235
-
2236
- let $this = jQuery( event.target ),
2237
- $tagDesc = jQuery( '#tsf-on-blogname-js' );
2238
-
2239
- if ( $this.is(':checked') ) {
2240
- $tagDesc.css( 'display', 'inline' );
2241
- } else {
2242
- $tagDesc.css( 'display', 'none' );
2243
- }
2244
- },
2245
-
2246
- /**
2247
- * Toggle additions within Description example for the Example Description
2248
- *
2249
- * @since 2.6.0
2250
- *
2251
- * @function
2252
- * @param {!jQuery.Event} event
2253
- * @return {undefined}
2254
- */
2255
- additionsToggleDesc: function( event ) {
2256
-
2257
- let $this = jQuery( event.target ),
2258
- $tagDesc = jQuery( '#tsf-description-additions-js' );
2259
-
2260
- if ( $this.is(':checked') ) {
2261
- $tagDesc.css( 'display', 'inline' );
2262
- } else {
2263
- $tagDesc.css( 'display', 'none' );
2264
- }
2265
- },
2266
-
2267
  /**
2268
  * Toggle tagline end examples within the Left/Right example for the
2269
  * HomePage Title or Description.
@@ -2280,10 +2257,6 @@ window.tsf = {
2280
 
2281
  let $tagTitle = jQuery( '#tsf-title-tagline-toggle :input' ),
2282
  $title = jQuery( '.tsf-custom-blogname-js' ),
2283
- $tagDescAdditions = jQuery( '#tsf-description-additions-toggle :input' ),
2284
- $descAdditions = jQuery( '#tsf-description-additions-js' ),
2285
- $tagDescBlogname = jQuery( '#tsf-description-onblogname-toggle :input' ),
2286
- $descBlogname = jQuery( '#tsf-on-blogname-js' ),
2287
  $tagTitleAdditions = jQuery( '#tsf-title-additions-toggle :input' ),
2288
  $titleAdditions = jQuery( '.tsf-title-additions-js' );
2289
 
@@ -2293,18 +2266,6 @@ window.tsf = {
2293
  $title.css( 'display', 'none' );
2294
  }
2295
 
2296
- if ( $tagDescAdditions.is( ':checked' ) ) {
2297
- $descAdditions.css( 'display', 'inline' );
2298
- } else {
2299
- $descAdditions.css( 'display', 'none' );
2300
- }
2301
-
2302
- if ( $tagDescBlogname.is( ':checked' ) ) {
2303
- $descBlogname.css( 'display', 'inline' );
2304
- } else {
2305
- $descBlogname.css( 'display', 'none' );
2306
- }
2307
-
2308
  // Reverse option.
2309
  if ( $tagTitleAdditions.is( ':checked' ) ) {
2310
  $titleAdditions.css( 'display', 'none' );
@@ -2354,6 +2315,13 @@ window.tsf = {
2354
  .off( 'change.tsfChangeListener' )
2355
  .on( 'change.tsfChangeListener', { _input: input, _except: except }, setUnsetChange );
2356
 
 
 
 
 
 
 
 
2357
  //= Text input
2358
  input = [
2359
  '.tsf-metaboxes input[type=text]',
@@ -2718,6 +2686,8 @@ window.tsf = {
2718
  tsf._initDescInputs();
2719
  tsf._initSocialDescInputs();
2720
 
 
 
2721
  tsf._initWebmastersInput();
2722
 
2723
  // Sets tabs to correct radio button on load.
@@ -2800,10 +2770,6 @@ window.tsf = {
2800
  $( '.tsf-flex-nav-tab-radio' ).on( 'change', tsf.flexTabToggle );
2801
  $( '.tsf-flex-nav-tab' ).on( 'click', '.tsf-flex-nav-tab-label', tsf.addNoFocusClass );
2802
 
2803
- // Toggle Description additions removal.
2804
- $( '#tsf-description-onblogname-toggle :input' ).on( 'click', tsf.taglineToggleDesc );
2805
- $( '#tsf-description-additions-toggle :input' ).on( 'click', tsf.additionsToggleDesc );
2806
-
2807
  // Dismiss notices.
2808
  $( '.tsf-dismiss' ).on( 'click', tsf.dismissNotice );
2809
 
8
 
9
  /**
10
  * The SEO Framework plugin
11
+ * Copyright (C) 2015 - 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
12
  *
13
  * This program is free software: you can redistribute it and/or modify
14
  * it under the terms of the GNU General Public License version 3 as published
31
  * "transform-es2015-modules-commonjs"
32
  * IE11 supports everything else implemented, even if it has cost us headaches.
33
  * @see tsf.browseUnhappy
34
+ *
35
+ * Don't rely on the API: This code is quite anti-pattern. I will rewrite it in the future.
36
+ * It was never meant to become this big: "Serve JavaScript as an addition, not as a means."
37
  */
38
 
39
  /**
739
  $additionsElement.css( { 'maxWidth' : 'initial' } );
740
 
741
  switch ( hoverAdditionsPlacement ) {
742
+ case 'before':
743
  let additionsWidth = $additionsElement[0].getBoundingClientRect().width;
744
 
745
  additionsWidth = additionsMaxWidth < additionsWidth ? additionsMaxWidth : additionsWidth;
752
  additionsOffset += leftOffset;
753
  break;
754
 
755
+ case 'after':
756
  additionsOffset += leftOffset + textWidth + prefixMaxWidth;
757
  break;
758
  }
802
 
803
  if ( _hasPrefixValue ) {
804
  switch ( hoverPrefixPlacement ) {
805
+ case 'before':
806
  _placeholder = _hoverPrefixValue + _placeholder;
807
  break;
808
 
809
+ case 'after':
810
  _placeholder = _placeholder + _hoverPrefixValue;
811
  break;
812
  }
813
  }
814
  if ( _hasAdditionsValue ) {
815
  switch ( hoverAdditionsPlacement ) {
816
+ case 'before':
817
  _placeholder = _hoverAdditionsValue + _placeholder;
818
  break;
819
 
820
+ case 'after':
821
  _placeholder = _placeholder + _hoverAdditionsValue;
822
  break;
823
  }
851
  } else {
852
  if ( hoverPrefixValue.length ) {
853
  switch ( hoverPrefixPlacement ) {
854
+ case 'before':
855
  text = hoverPrefixValue + text;
856
  break;
857
 
858
+ case 'after':
859
  text = text + hoverPrefixValue;
860
  break;
861
  }
862
  }
863
  if ( hoverAdditionsValue.length ) {
864
  switch ( hoverAdditionsPlacement ) {
865
+ case 'before':
866
  text = hoverAdditionsValue + text;
867
  break;
868
 
869
+ case 'after':
870
  text = text + hoverAdditionsValue;
871
  break;
872
  }
899
  if ( ! pixels || ! reference ) return;
900
 
901
  let test = {
902
+ 'e': pixels,
903
+ 'text': tsf.unescapeString( reference.innerHTML ),
904
+ 'guidelines': tsf.params.inputGuidelines.title.search.pixels,
905
  };
906
 
907
  tsf.updatePixelCounter( test );
987
  jQuery( '#tsf-title-tagline-toggle :input' ).on( 'click', changeHomePageAdditionsVisibility );
988
 
989
  /**
990
+ * Updates private/protected title prefix upon Gutenberg's Post visibility switch.
991
  *
992
  * @function
993
  * @param {!jQuery.Event} event
994
  * @return {undefined}
995
  */
996
+ const updateVisibility = ( visibility ) => {
 
997
 
998
  isPrivate = false;
999
  isPasswordProtected = false;
1000
 
1001
+ switch ( visibility ) {
1002
+ case 'password':
1003
+ isPasswordProtected = true;
 
 
 
1004
  break;
1005
 
1006
+ case 'private':
1007
  isPrivate = true;
1008
  break;
1009
 
1010
+ default:
1011
+ case 'public':
1012
  break;
1013
  }
 
 
1014
  setHoverPrefixValue();
1015
  enqueueTriggerInput();
1016
  }
1017
+ jQuery( document ).on( 'tsf-updated-gutenberg-visibility', ( event, visibility ) => updateVisibility( visibility ) );
1018
+
1019
+ /**
1020
+ * Updates private/protected title prefix upon Post visibility switch.
1021
+ *
1022
+ * @function
1023
+ * @param {!jQuery.Event} event
1024
+ * @return {undefined}
1025
+ */
1026
+ const updateClassicVisibility = ( event ) => {
1027
+ let value = jQuery( '#visibility' ).find( 'input:radio:checked' ).val();
1028
+
1029
+ if ( 'password' === value ) {
1030
+ let p = jQuery( '#visibility' ).find( '#post_password' ).val();
1031
+ // A falsy-password (like '0'), will return true in "SOME OF" WP's front-end PHP, false in WP's JS before submitting...
1032
+ // It won't invoke WordPress' password protection. TODO FIXME: file WP Core bug report.
1033
+ let hasProtection = p ? !! p.length : false;
1034
+ if ( ! hasProtection ) {
1035
+ value = 'public';
1036
+ }
1037
+ }
1038
+ updateVisibility( value );
1039
+ }
1040
+ jQuery( '#visibility .save-post-visibility' ).on( 'click', updateClassicVisibility );
1041
 
1042
  /**
1043
  * Updates used separator and all examples thereof.
1117
  unregisteredTriggerBuffer = setTimeout( triggerUnregisteredInput, 10 );
1118
  }
1119
  jQuery( window ).on( 'tsf-flex-resize', enqueueUnregisteredInputTrigger );
1120
+ jQuery( '#tsf-homepage-tab-general' ).on( 'tsf-tab-toggled', enqueueUnregisteredInputTrigger );
1121
  jQuery( '#tsf-flex-inpost-tab-general' ).on( 'tsf-flex-tab-toggled', enqueueUnregisteredInputTrigger );
1122
  enqueueUnregisteredInputTrigger();
1123
 
1155
  * Updates default title placeholder.
1156
  *
1157
  * @function
1158
+ * @param {string} value
1159
  * @return {undefined}
1160
  */
1161
+ const updateDefaultTitle = function( val ) {
1162
+ val = typeof val === 'string' && val.trim() || '';
 
1163
 
1164
  if ( val.length ) {
1165
  defaultTitle = tsf.escapeString( stripTitleTags ? tsf.stripTags( val ) : val );
1171
  }
1172
  //= The home page listens to a static preset value. Update all others.
1173
  if ( ! tsf.states.isHome ) {
1174
+ jQuery( '#edittag #name, #titlewrap #title' ).on( 'input', event => updateDefaultTitle( event.target.value ) );
1175
+ jQuery( document ).on( 'tsf-updated-gutenberg-title', ( event, title ) => updateDefaultTitle( title ) );
1176
  }
1177
 
1178
  /**
1382
  $prefix.css( 'display', 'inline' );
1383
  }
1384
  }
1385
+ jQuery( '#tsf-title-prefixes-toggle :input' ).on( 'click', adjustPrefixExample );
1386
  },
1387
 
1388
  /**
1398
 
1399
  if ( ! tsf.hasInput ) return;
1400
 
1401
+ let $descriptions = jQuery( [
1402
+ "#autodescription_description",
1403
+ "#autodescription-meta\\[description\\]",
1404
+ "#autodescription-site-settings\\[homepage_description\\]"
1405
+ ].join( ', ' ) );
1406
 
1407
  if ( ! $descriptions.length ) return;
1408
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1409
  // TODO: We need to set a predicted description value, so we can toggle it.
1410
  // const updateAutodescription = function( event ) {
1411
  // let checked = jQuery( event.target ).checked();
1433
 
1434
  let test = {
1435
  'e': counter,
1436
+ 'text': tsf.unescapeString( reference.innerHTML ),
1437
+ 'guidelines': tsf.params.inputGuidelines.description.search.chars,
1438
  };
1439
 
1440
  tsf.updateCharacterCounter( test );
1530
  clearTimeout( unregisteredTriggerBuffer );
1531
  unregisteredTriggerBuffer = setTimeout( triggerUnregisteredInput, 10 );
1532
  }
1533
+ jQuery( '#tsf-homepage-tab-general' ).on( 'tsf-tab-toggled', enqueueUnregisteredInputTrigger );
1534
  jQuery( '#tsf-flex-inpost-tab-general' ).on( 'tsf-flex-tab-toggled', enqueueUnregisteredInputTrigger );
1535
  enqueueUnregisteredInputTrigger();
1536
 
1551
  }
1552
  }
1553
  jQuery( document ).on( 'postbox-toggled', triggerPostboxSynchronousUnregisteredInput );
1554
+
1555
+ // const gbUpdated = function() {
1556
+ // jQuery( '#autodescription_description' ).attr( 'placeholder', tsf.gbData.descriptions.search );
1557
+ // enqueueTriggerInput();
1558
+ // }
1559
+ // jQuery( document ).on( 'tsf-updated-gutenberg-content', gbUpdated );
1560
+ // jQuery( document ).on( 'tsf-updated-gutenberg-excerpt', gbUpdated );
1561
  },
1562
 
1563
  /**
1596
  let val = '';
1597
  switchActive:
1598
  switch ( what ) {
1599
+ case 'twitter':
1600
  val = twTitleValue;
1601
  if ( twLocked || twPHLocked ) {
1602
  val = val.length ? val : $twTitle.prop( 'placeholder' );
1603
  break switchActive;
1604
  }
1605
  // get next if not set.
1606
+ case 'og':
1607
  val = val.length ? val : ogTitleValue;
1608
  if ( ogLocked || ogPHLocked ) {
1609
  val = val.length ? val : $ogTitle.prop( 'placeholder' );
1610
  break switchActive;
1611
  }
1612
  // get next if not set.
1613
+ case 'reference':
1614
  val = val.length ? val : referenceValue;
1615
  break;
1616
  }
1718
  let val = '';
1719
  switchActive:
1720
  switch ( what ) {
1721
+ case 'twitter':
1722
  val = twDescValue;
1723
  if ( twLocked || twPHLocked ) {
1724
  val = val.length ? val : $twDesc.prop( 'placeholder' );
1725
  break switchActive;
1726
  }
1727
  // get next if not set.
1728
+ case 'og':
1729
  val = val.length ? val : ogDescValue;
1730
  if ( ogLocked || ogPHLocked ) {
1731
  val = val.length ? val : $ogDesc.prop( 'placeholder' );
1732
  break switchActive;
1733
  }
1734
  // get next if not set.
1735
+ case 'reference':
1736
  if ( ! val.length ) {
1737
  if ( $descriptions.val().length ) {
1738
  val = referenceValue;
1808
  $twDesc.on( 'input.tsfUpdateOgDesc', updateTwDesc );
1809
  },
1810
 
1811
+ /**
1812
+ * Initializes Canonical URL meta input.
1813
+ *
1814
+ * @since 3.2.0
1815
+ *
1816
+ * @function
1817
+ * @return {undefined}
1818
+ */
1819
+ _initCanonicalInput: function() {
1820
+
1821
+ let canonicalInput = jQuery( '#autodescription_canonical' );
1822
+
1823
+ if ( ! canonicalInput ) return;
1824
+
1825
+ const updateCanonical = ( link ) => {
1826
+ canonicalInput.attr( 'placeholder', link );
1827
+ }
1828
+
1829
+ jQuery( document ).on( 'tsf-updated-gutenberg-link', ( event, link ) => updateCanonical( link ) );
1830
+ },
1831
+
1832
  /**
1833
  * Initializes Webmasters' meta input.
1834
  *
2241
  $handles.on( 'click.tsfPostboxes', handleClick );
2242
  },
2243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2244
  /**
2245
  * Toggle tagline end examples within the Left/Right example for the
2246
  * HomePage Title or Description.
2257
 
2258
  let $tagTitle = jQuery( '#tsf-title-tagline-toggle :input' ),
2259
  $title = jQuery( '.tsf-custom-blogname-js' ),
 
 
 
 
2260
  $tagTitleAdditions = jQuery( '#tsf-title-additions-toggle :input' ),
2261
  $titleAdditions = jQuery( '.tsf-title-additions-js' );
2262
 
2266
  $title.css( 'display', 'none' );
2267
  }
2268
 
 
 
 
 
 
 
 
 
 
 
 
 
2269
  // Reverse option.
2270
  if ( $tagTitleAdditions.is( ':checked' ) ) {
2271
  $titleAdditions.css( 'display', 'none' );
2315
  .off( 'change.tsfChangeListener' )
2316
  .on( 'change.tsfChangeListener', { _input: input, _except: except }, setUnsetChange );
2317
 
2318
+ //= Gutenberg save.
2319
+ jQuery( document )
2320
+ .off( 'tsf-gutenberg-saved-document.tsfChangeListener' )
2321
+ .on( 'tsf-gutenberg-saved-document.tsfChangeListener', () => {
2322
+ tsf.settingsChanged = false;
2323
+ } );
2324
+
2325
  //= Text input
2326
  input = [
2327
  '.tsf-metaboxes input[type=text]',
2686
  tsf._initDescInputs();
2687
  tsf._initSocialDescInputs();
2688
 
2689
+ tsf._initCanonicalInput();
2690
+
2691
  tsf._initWebmastersInput();
2692
 
2693
  // Sets tabs to correct radio button on load.
2770
  $( '.tsf-flex-nav-tab-radio' ).on( 'change', tsf.flexTabToggle );
2771
  $( '.tsf-flex-nav-tab' ).on( 'click', '.tsf-flex-nav-tab-label', tsf.addNoFocusClass );
2772
 
 
 
 
 
2773
  // Dismiss notices.
2774
  $( '.tsf-dismiss' ).on( 'click', tsf.dismissNotice );
2775
 
lib/js/tsf.min.js CHANGED
@@ -1 +1 @@
1
- 'use strict';window.tsf={nonces:tsfL10n.nonces,i18n:tsfL10n.i18n,states:tsfL10n.states,params:tsfL10n.params,settingsChanged:!1,counterType:0,hasInput:!1,browseUnhappy:!!navigator.userAgent.match(/Trident\/7\./),counterClasses:{0:'tsf-counter-zero',1:'tsf-counter-one',2:'tsf-counter-two',3:'tsf-counter-three'},confirm:function(t){return confirm(t)},stripTags:function(t){return t.replace(/(<([^>]+)?>?)/ig,'')},escapeString:function(t){if(!t.length)return'';let s={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&#039;','\\\\':'&#92;','\\':''};return t.replace(/[&<>"']|\\\\|\\/g,function(n){return s[n]})},unescapeString:function(t){if(!t.length)return'';let s={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&#039;','\\':'&#92;'},n={};n=tsf.browseUnhappy?Object.keys(s).map(function(o){return s[o]}):Object.values(s);let a=new RegExp(n.map(function(o){return o.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,'\\$&')}).join('|'),'g');return tsf.browseUnhappy?t.replace(a,function(o){for(let r in s)if(s[r]===o)return r;return o}):t.replace(a,function(o){return Object.keys(s).find(function(r){return s[r]===o})})},sDoubleSpace:function(t){return t.replace(/\s\s+/g,' ')},getStringLength:function(t){let s,n=0;return t.length&&(s=document.createElement('span'),s.innerHTML=tsf.escapeString(t).trim(),'undefined'!=typeof s.childNodes[0]&&(n=s.childNodes[0].nodeValue.length)),+n},convertJSONResponse:function(t){let s=t&&t.json||void 0,n=1===s;if(!n){let a=t;try{t=JSON.parse(t),n=!0}catch(o){n=!1}n||(t=a)}return t},updateCharacterCounter:function(t){let s=t.e,n=t.text,a=t.guidelines,o=tsf.getStringLength(n),r='',l='',c={bad:'tsf-count-bad',okay:'tsf-count-okay',good:'tsf-count-good',unknown:'tsf-count-unknown'};switch(o?o<a.lower?(r=c.bad,l=tsf.i18n.inputGuidelines.short.farTooShort):o<a.goodLower?(r=c.okay,l=tsf.i18n.inputGuidelines.short.tooShort):o>a.upper?(r=c.bad,l=tsf.i18n.inputGuidelines.short.farTooLong):o>a.goodUpper?(r=c.okay,l=tsf.i18n.inputGuidelines.short.tooLong):(r=c.good,l=tsf.i18n.inputGuidelines.short.good):(r=c.unknown,l=tsf.i18n.inputGuidelines.short.empty),tsf.counterType){case 3:l=o.toString()+' - '+l;break;case 2:break;case 1:default:l=o.toString();}for(let g in s.innerHTML=l,c)s.classList.remove(c[g]);for(let g in tsf.counterClasses)s.classList.remove(tsf.counterClasses[g]);s.classList.add(r),s.classList.add(tsf.counterClasses[tsf.counterType])},updatePixelCounter:function(t){let s=t.e,n=t.text,a=t.guidelines,o=s.parentElement;if(o){let r=o.querySelector('.tsf-pixel-counter-bar'),l=o.querySelector('.tsf-pixel-counter-shadow');if(r&&l){l.innerHTML=tsf.escapeString(n);let c=l.offsetWidth,g='',d='',u='',f={bad:'tsf-pixel-counter-bad',okay:'tsf-pixel-counter-okay',good:'tsf-pixel-counter-good',unknown:'tsf-pixel-counter-unknown'};d=100*(c/a.goodUpper)+'%',c?c<a.lower?(g=f.bad,u=tsf.i18n.inputGuidelines.long.farTooShort):c<a.goodLower?(g=f.okay,u=tsf.i18n.inputGuidelines.long.tooShort):c>a.upper?(d=100*(a.upper/(c+2*(c-a.upper)/3))+'%',g=f.bad,u=tsf.i18n.inputGuidelines.long.farTooLong):c>a.goodUpper?(g=f.okay,u=tsf.i18n.inputGuidelines.long.tooLong,d='100%'):(g=f.good,u=tsf.i18n.inputGuidelines.long.good):(g=f.unknown,d='100%',u=tsf.i18n.inputGuidelines.long.empty);let b,h=r.querySelector('.tsf-pixel-counter-fluid');for(let x in b=tsf.i18n.pixelsUsed.replace(/%1\$d/g,c),b=b.replace(/%2\$d/g,a.goodUpper),b=b+'<br>'+u,f)r.classList.remove(f[x]);r.classList.add(g),h.style.width=d,r.dataset.desc=b,r.setAttribute('aria-label',b),tsfTT.triggerUpdate(r)}}},_initTitleInputs:function(){if(tsf.hasInput){let t=jQuery(['#autodescription_title','#autodescription-meta\\[doctitle\\]','#autodescription-site-settings\\[homepage_title\\]'].join(', '));if(t.length){let n,a,o,l,s=!1,r='',c='',g=tsf.params.titleSeparator,d=tsf.params.defaultTitle,u=tsf.states.useTagline,f=tsf.states.isRTL,h=tsf.states.isPrivate,b=tsf.states.isPasswordProtected,x=tsf.states.stripTitleTags;n=f?'after':'before';const y=function(){let Q='before';tsf.states.isSettingsPage?f?'right'===jQuery('#tsf-home-title-location input:checked').val()&&(Q='after'):'left'===jQuery('#tsf-home-title-location input:checked').val()&&(Q='after'):tsf.states.isHome?f?'right'===tsf.params.titleLocation&&(Q='after'):'left'===tsf.params.titleLocation&&(Q='after'):f?'left'===tsf.params.titleLocation&&(Q='after'):'right'===tsf.params.titleLocation&&(Q='after'),a=Q};y();const _=function(){let Q='';if(!tsf.states.isSettingsPage)tsf.states.isHome?u&&(Q=tsf.params.titleAdditions):u&&(Q=tsf.params.titleAdditions);else if(u){let K=document.getElementById('autodescription-site-settings[homepage_title_tagline]'),X=K&&K.value||'';X=tsf.sDoubleSpace(X.trim()),Q=X.length?X:tsf.params.blogDescription}Q.length&&(Q=tsf.escapeString(tsf.sDoubleSpace(Q.trim())),'before'===a?Q=Q+' '+g+' ':'after'===a?Q=' '+g+' '+Q:void 0),c=Q.length?Q:'',l=document.getElementById('tsf-title-placeholder'),c.length&&l&&(l.innerHTML=c)};_();const L=function(){let Q='';h?Q=tsf.i18n.privateTitle:b&&(Q=tsf.i18n.protectedTitle),Q.length&&(Q=tsf.escapeString(Q),'before'===n?Q+=' ':'after'===n?Q=' '+Q:void 0),r=Q.length?Q:'',r.length&&o&&(o.innerHTML=r),o=document.getElementById('tsf-title-placeholder-prefix'),r.length&&o&&(o.innerHTML=r)};L();const T=function(Q){if(l||o){let K=jQuery(Q.target),X=K.val(),Y=!!c.length,Z=!!r.length;if(!Y&&l&&(l.style.display='none'),!Z&&o&&(o.style.display='none'),!Y&&!Z)return void K.css('text-indent','initial');if(!X.length)return K.css('text-indent','initial'),l&&(l.style.display='none'),void(o&&(o.style.display='none'));let ee=K.outerWidth(!0),te=(K.outerHeight(!0)-K.height())/2,se=(ee-K.innerWidth())/2,ie=f?'right':'left',ne=(K.outerWidth(!0)-K.width())/2,ae={display:K.css('display'),lineHeight:K.css('lineHeight'),fontFamily:K.css('fontFamily'),fontWeight:K.css('fontWeight'),fontSize:K.css('fontSize'),letterSpacing:K.css('letterSpacing'),paddingTop:te+'px',paddingBottom:te+'px'},oe=jQuery(o),re=jQuery(l),le=0,pe=0,ce=0,ge=0,de=0,ue=0;if(Z&&(oe.css(ae),oe.css({maxWidth:'initial'}),de=oe[0].getBoundingClientRect().width,de<ue&&(de=0)),Y){let he=0;switch(function(){let me=jQuery('#tsf-title-offset');me.text(X),me.css({fontFamily:ae.fontFamily,fontWeight:ae.fontWeight,letterSpacing:ae.letterSpacing,fontSize:ae.fontSize}),he=me[0].getBoundingClientRect().width}(),le=K[0].getBoundingClientRect().width-se-ne-he-de,le<ue&&(de+=le,le=0),re.css(ae),re.css({maxWidth:'initial'}),a){case'before':let me=re[0].getBoundingClientRect().width;me=le<me?le:me,me<ue&&(me=0),le=me,ge+=le,ce+=le,pe+=ne;break;case'after':pe+=ne+he+de;}}ce+=ne,de=0>de?0:de,ge+=de;let fe;Z&&(fe={},fe[ie]=ce+'px',fe.maxWidth=de+'px',oe.css(fe)),Y&&(fe={},fe[ie]=pe+'px',fe.maxWidth=le+'px',re.css(fe)),fe={},fe['text-indent']=ge+'px',K.css(fe)}},C=function(){let K='',X=!!c.length,Y=!!r.length,Z=c,ee=r;tsf.states.isTermEdit&&tsf.params.termName&&(ee=f?' :'+tsf.params.termName:tsf.params.termName+': ',Y=tsf.states.useTermPrefix),K=d,Y&&('before'===n?K=ee+K:'after'===n?K+=ee:void 0),X&&('before'===a?K=Z+K:'after'===a?K+=Z:void 0),tsf.browseUnhappy&&(s=!0);let te=document.createElement('span');te.innerHTML=tsf.escapeString(tsf.sDoubleSpace(K)),t.prop('placeholder',tsf.unescapeString(te.textContent)),tsf.browseUnhappy&&setTimeout(function(){s=!1},0)},w=function(Q){let K=document.getElementById('tsf-title-reference'),X=Q.target.value;K&&(X=X.trim(),1>X.length||tsf.states.homeLocks.refTitleLock?X=Q.target.placeholder:(r.length&&('before'===n?X=r+X:'after'===n?X+=r:void 0),c.length&&('before'===a?X=c+X:'after'===a?X+=c:void 0)),K.innerHTML=tsf.escapeString(tsf.sDoubleSpace(X)),setTimeout(function(){jQuery(K).change()},0))},S=function(Q){let K=document.getElementById(Q.target.id+'_chars'),X=document.getElementById('tsf-title-reference');if(K&&X){let Y={e:K,text:tsf.unescapeString(X.innerHTML),guidelines:tsf.params.inputGuidelines.title.search.chars};tsf.updateCharacterCounter(Y)}},I=function(Q){let K=document.getElementById(Q.target.id+'_pixels'),X=document.getElementById('tsf-title-reference');if(K&&X){let Y={e:K,text:tsf.unescapeString(X.innerHTML),guidelines:tsf.params.inputGuidelines.title.search.pixels};tsf.updatePixelCounter(Y)}};t.on('input.tsfUpdateTitles',function(Q){return!s&&void(T(Q),C(),w(Q),S(Q),I(Q))});t.on('tsf-update-title-counter',function(Q){w(Q),S(Q),I(Q)});const U=function(){t.trigger('tsf-update-title-counter')},P=function(){_(),E()};jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').on('input',P),jQuery('#autodescription-site-settings\\[homepage_tagline\\]').on('change',P);jQuery('#tsf-title-tagline-toggle :input').on('click',function(Q){let K=u;jQuery(Q.target).is(':checked')?(jQuery('.tsf-custom-blogname-js').css('display','inline'),u=!0):(jQuery('.tsf-custom-blogname-js').css('display','none'),u=!1),K^u&&(_(),B())});jQuery('#visibility .save-post-visibility').on('click',function(){let K=jQuery('#visibility').find('input:radio:checked').val();switch(h=!1,b=!1,K){case'password':let X=jQuery('#visibility').find('#post_password').val();b=!!X&&!!X.length;break;case'private':h=!0;break;default:case'public':}L(),B()});jQuery('#tsf-title-separator :input').on('click',function(Q){let K=jQuery(Q.target).val(),X='';X='pipe'===K?'|':'dash'===K?'-':jQuery('<div/>').html('&'+K+';').text(),g=X,jQuery('.tsf-sep-js').text(' '+g+' '),_(),B()});const E=function(){t.trigger('input.tsfUpdateTitles')};let z=0;const B=function(){clearTimeout(z),z=setTimeout(E,10)};jQuery(window).on('tsf-counter-updated',B);const O=function(){let Q=tsf.settingsChanged;E(),tsf.settingsChanged=Q};let G=0;const A=function(){clearTimeout(G),G=setTimeout(O,10)};jQuery(window).on('tsf-flex-resize',A),jQuery('#homepage-tab-general').on('tsf-tab-toggled',A),jQuery('#tsf-flex-inpost-tab-general').on('tsf-flex-tab-toggled',A),A();let M=['autodescription-homepage-settings','tsf-inpost-box'];jQuery(document).on('postbox-toggled',function(Q,K){if(0<=M.indexOf(K.id)){let X=K.querySelector('.inside');0<X.offsetHeight&&0<X.offsetWidth&&O()}});jQuery('#tsf-home-title-location :input').on('click',function(){y(),_(),B()});tsf.states.isHome||jQuery('#edittag #name, #titlewrap #title').on('input',function(Q){let K=Q.target.value;K=K.trim(),d=K.length?tsf.escapeString(x?tsf.stripTags(K):K):tsf.params.untitledTitle,C(),U()});tsf.states.isHome||(jQuery('#autodescription_title_no_blogname').on('change',function(Q){if(!tsf.states.taglineLocked){let K=u;u=!jQuery(Q.target).is(':checked'),K^u&&(_(),B())}}),jQuery('#autodescription_title_no_blogname').trigger('change'));(function(){let Q=0,K=window.innerWidth;window.addEventListener('resize',function(){clearTimeout(Q),Q=setTimeout(function(){let X=window.innerWidth;K<X?782>=K&&782<=X&&O():782<=K&&782>=X&&O(),K=X},50)})})()}}},_initUnboundTitleSettings:function(){if(tsf.hasInput){let t=jQuery(['#autodescription_title','#autodescription-meta\\[doctitle\\]','#autodescription-site-settings\\[homepage_title\\]'].join(', '));jQuery('#tsf-title-placeholder, #tsf-title-placeholder-prefix').on('click',function(c){let g=jQuery(c.target).siblings(t)[0];if('function'==typeof g.setSelectionRange){g.focus();let d=2*g.value.length;g.setSelectionRange(d,d)}else{let d=g.value;g.value='',g.focus(),g.value=d}});jQuery('#autodescription-site-settings\\[title_rem_additions\\]').on('click',function(c){jQuery(c.target).is(':checked')?jQuery('.tsf-title-additions-js').css('display','none'):jQuery('.tsf-title-additions-js').css('display','inline')});jQuery('#tsf-title-location input').on('click',function(c){let g=jQuery('.tsf-title-additions-example-left'),d=jQuery('.tsf-title-additions-example-right');'right'===jQuery(c.target).val()?(g.css('display','none'),d.css('display','inline')):(g.css('display','inline'),d.css('display','none'))});jQuery('#autodescription-site-settings\\[homepage_title\\]').on('input',function(c){let g=c.target.value||'',d=jQuery('.tsf-custom-title-js');0===g.length?d.text(tsf.params.defaultTitle):d.text(g)});jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').on('input.tsfInputTagline',function(c){let g=c.target.value||'',d=jQuery('.tsf-custom-tagline-js');g=tsf.escapeString(tsf.sDoubleSpace(g.trim())),g.length?(d.html(g),jQuery('#tsf-home-title-location .tsf-sep-js').show()):(d.text(tsf.params.blogDescription),0===tsf.params.blogDescription.length?jQuery('#tsf-home-title-location .tsf-sep-js').hide():jQuery('#tsf-home-title-location .tsf-sep-js').show())}),jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').trigger('input.tsfInputTagline');jQuery('#title-prefixes-toggle :input').on('click',function(c){let g=jQuery(c.target),d=jQuery('.tsf-title-prefix-example');g.is(':checked')?d.css('display','none'):d.css('display','inline')})}},_initDescInputs:function(){if(tsf.hasInput){let t=jQuery('#autodescription_description, #autodescription-meta\\[description\\], #autodescription-site-settings\\[homepage_description\\]');if(t.length){let s=tsf.params.descriptionSeparator;jQuery('#tsf-description-separator input').on('click',function(y){let _=jQuery(y.target).val(),L='';L='pipe'===_?'|':'dash'===_?'-':jQuery('<div/>').html('&'+_+';').text(),s=L,jQuery('#autodescription-descsep-js').text(' '+s+' '),d()});const a=function(y){let _=document.getElementById(y.target.id+'_chars'),L=document.getElementById('tsf-description-reference');if(_&&L){let T={e:_,text:tsf.unescapeString(L.innerHTML),guidelines:tsf.params.inputGuidelines.description.search.chars};tsf.updateCharacterCounter(T)}},o=function(y){let _=document.getElementById('tsf-description-reference'),L=y.target.value;_&&(L=L.trim(),(1>L.length||tsf.states.homeLocks.refDescriptionLock)&&(L=y.target.placeholder),_.innerHTML=tsf.escapeString(tsf.sDoubleSpace(L)),setTimeout(function(){jQuery(_).change()},0))},r=function(y){let _=document.getElementById(y.target.id+'_pixels'),L=document.getElementById('tsf-description-reference');if(_&&L){let T={e:_,text:tsf.unescapeString(L.innerHTML),guidelines:tsf.params.inputGuidelines.description.search.pixels};tsf.updatePixelCounter(T)}};t.on('input.tsfUpdateDescriptions',function(y){o(y),a(y),r(y)});const c=function(){t.trigger('input.tsfUpdateDescriptions')};let g=0;const d=function(){clearTimeout(g),g=setTimeout(c,10)};jQuery(window).on('tsf-counter-updated',d);const u=function(){let y=tsf.settingsChanged;c(),tsf.settingsChanged=y};let f=0;const h=function(){clearTimeout(f),f=setTimeout(u,10)};jQuery('#homepage-tab-general').on('tsf-tab-toggled',h),jQuery('#tsf-flex-inpost-tab-general').on('tsf-flex-tab-toggled',h),h();let b=['autodescription-homepage-settings','tsf-inpost-box'];jQuery(document).on('postbox-toggled',function(y,_){if(0<=b.indexOf(_.id)){let L=_.querySelector('.inside');0<L.offsetHeight&&0<L.offsetWidth&&d()}})}}},_initSocialTitleInputs:function(){if(tsf.hasInput){let t=jQuery('#autodescription_og_title, #autodescription-site-settings\\[homepage_og_title\\]'),s=jQuery('#autodescription_twitter_title, #autodescription-site-settings\\[homepage_twitter_title\\]'),n=jQuery('#tsf-title-reference');if(t.length&&s.length&&n.length){let a=!1,o=tsf.states.homeLocks.ogTitleLock,r=tsf.states.homeLocks.ogTitlePHLock,l=tsf.states.homeLocks.twTitleLock,c=tsf.states.homeLocks.twTitlePHLock,g=o?t.prop('placeholder'):t.val(),d=l?s.prop('placeholder'):s.val(),u=n.text();const f=function(T){let C='';switchActive:switch(T){case'twitter':if(C=d,l||c){C=C.length?C:s.prop('placeholder');break switchActive}case'og':if(C=C.length?C:g,o||r){C=C.length?C:t.prop('placeholder');break switchActive}case'reference':C=C.length?C:u;}return C},h=function(){tsf.browseUnhappy&&(a=!0),o||r||t.prop('placeholder',f('reference')),l||c||s.prop('placeholder',f('og')),tsf.browseUnhappy&&setTimeout(function(){a=!1},0)},b=function(T,C,w){let S=document.getElementById(T.id+'_chars');if(S){let I={e:S,text:tsf.unescapeString(C),guidelines:tsf.params.inputGuidelines.title[w].chars};tsf.updateCharacterCounter(I)}};let x=0;const y=function(){clearTimeout(x),x=setTimeout(function(){t.each(function(T,C){return b(C,f('og'),'opengraph')}),s.each(function(T,C){return b(C,f('twitter'),'twitter')})},10)};n.on('change',function(){u=n.text(),h(),y()});t.on('input.tsfUpdateOgTitle',function(T){if(!a){if(!o){let C=T.target.value.trim();g=C.length?tsf.sDoubleSpace(C):''}h(),y()}}),s.on('input.tsfUpdateTwTitle',function(T){if(!a){if(!l){let C=T.target.value.trim();d=C.length?tsf.sDoubleSpace(C):''}h(),y()}})}}},_initSocialDescInputs:function(){if(tsf.hasInput){let t=jQuery('#autodescription_og_description, #autodescription-site-settings\\[homepage_og_description\\]'),s=jQuery('#autodescription_twitter_description, #autodescription-site-settings\\[homepage_twitter_description\\]'),n=jQuery('#tsf-description-reference');if(t.length&&s.length&&n.length){let a=!1,o=tsf.states.homeLocks.ogDescriptionLock,r=tsf.states.homeLocks.ogDescriptionPHLock,l=tsf.states.homeLocks.twDescriptionLock,c=tsf.states.homeLocks.twDescriptionPHLock,g=o?t.prop('placeholder'):t.val(),d=l?s.prop('placeholder'):s.val(),u=n.text(),f=jQuery(['#autodescription_description','#autodescription-meta\\[description\\]','#autodescription-site-settings\\[homepage_description\\]'].join(', '));const h=function(C,w){let S='';switchActive:switch(C){case'twitter':if(S=d,l||c){S=S.length?S:s.prop('placeholder');break switchActive}case'og':if(S=S.length?S:g,o||r){S=S.length?S:t.prop('placeholder');break switchActive}case'reference':S.length||(f.val().length?S=u:'twitter'===w?S=tsf.params.socialPlaceholders.twDesc:'og'==w&&(S=tsf.params.socialPlaceholders.ogDesc));}return S},b=function(){tsf.browseUnhappy&&(a=!0),o||r||t.attr('placeholder',h('reference','og')),l||c||s.attr('placeholder',h('og','twitter')),tsf.browseUnhappy&&setTimeout(function(){a=!1},0)},x=function(C,w,S){let I=document.getElementById(C.id+'_chars');if(I){let j={e:I,text:tsf.unescapeString(w),guidelines:tsf.params.inputGuidelines.description[S].chars};tsf.updateCharacterCounter(j)}};let y=0;const _=function(){clearTimeout(y),y=setTimeout(function(){t.each(function(C,w){return x(w,h('og','og'),'opengraph')}),s.each(function(C,w){return x(w,h('twitter','twitter'),'twitter')})},10)};n.on('change',function(){u=n.text(),b(),_()});t.on('input.tsfUpdateOgDesc',function(C){if(!a){if(!o){let w=C.target.value.trim();g=w.length?tsf.sDoubleSpace(w):''}b(),_()}}),s.on('input.tsfUpdateOgDesc',function(C){if(!a){if(!l){let w=C.target.value.trim();d=w.length?tsf.sDoubleSpace(w):''}b(),_()}})}}},_initWebmastersInput:function(){if(tsf.states.isSettingsPage){let t=jQuery(['#autodescription-site-settings\\[google_verification\\]','#autodescription-site-settings\\[bing_verification\\]','#autodescription-site-settings\\[yandex_verification\\]','#autodescription-site-settings\\[pint_verification\\]'].join(', '));t.length&&t.on('paste',function(s){let n=s.originalEvent.clipboardData&&s.originalEvent.clipboardData.getData('text')||void 0;if(n){let a=/<meta[^>]+content=(\"|\')?([^\"\'>\s]+)\1?.*?>/i.exec(n);a&&2 in a&&'string'==typeof a[2]&&a[2].length&&(s.stopPropagation(),s.preventDefault(),s.target.value=a[2])}})}},_initCounters:function(){if(tsf.hasInput){jQuery('.tsf-counter').on('click',function(){++tsf.counterType,3<tsf.counterType&&(tsf.counterType=0),s();let r='.tsf-counter-wrap .tsf-ajax',l=0;tsf.resetAjaxLoader(r),tsf.setAjaxLoader(r);let c={method:'POST',url:ajaxurl,datatype:'json',data:{action:'the_seo_framework_update_counter',nonce:tsf.nonces.edit_posts,val:tsf.counterType},async:!0,success:function(g){switch(g=tsf.convertJSONResponse(g),'success'===g.type&&(l=1),l){case 0:tsf.unsetAjaxLoader(r,!1);break;case 1:tsf.unsetAjaxLoader(r,!0);break;default:tsf.resetAjaxLoader(r);}}};jQuery.ajax(c)});const s=function(){tsf.counterType=+tsf.counterType,3<tsf.counterType&&(tsf.counterType=0),tsf._triggerCounterUpdate()};jQuery('#autodescription-site-settings\\[display_character_counter\\]').on('click',function(o){jQuery(o.target).is(':checked')?jQuery('.tsf-counter-wrap').show():jQuery('.tsf-counter-wrap').hide()});jQuery('#autodescription-site-settings\\[display_pixel_counter\\]').on('click',function(o){jQuery(o.target).is(':checked')?(jQuery('.tsf-pixel-counter-wrap').show(),tsf._triggerCounterUpdate()):jQuery('.tsf-pixel-counter-wrap').hide()})}},tabToggle:function(t,s){let n=jQuery(t.target);if(n.is(':checked')){s='boolean'==typeof s&&s;let a=t.target.id,o=t.target.name,r='tsf-active-tab-content',l='tsf-tab-active',c=jQuery('.'+r),g=n.closest('.tsf-nav-tab-wrapper').find('.'+l),d=c.find('input:invalid, select:invalid, textarea:invalid');if(d.length){try{d[0].reportValidity()}catch(f){let h=jQuery(t.target.form).find('input[type=submit]').not('.autodescription-site-settings\\[tsf-settings-reset\\]');h.length&&h[0].click()}return g.prop('checked',!0),n.prop('checked',!1),t.stopPropagation(),t.preventDefault(),!1}let u=jQuery('#'+a+'-content');if(g.removeClass(l),g.siblings('label').removeClass('tsf-no-focus-ring'),n.addClass(l),s){let f=jQuery('.'+o+'-content');f.removeClass(r).hide(),u.addClass(r).show(),jQuery('#'+a).trigger('tsf-tab-toggled')}else if(u.length&&!u.is(c)){let f=jQuery('.'+o+'-content');f.fadeOut(150,function(){jQuery(this).removeClass(r)}),setTimeout(function(){u.addClass(r).fadeIn(250)},150),setTimeout(function(){jQuery('#'+a).trigger('tsf-tab-toggled')},175)}}},flexTabToggle:function(t,s){let n=jQuery(t.target);if(n.is(':checked')){s='boolean'==typeof s&&s;let a=t.target.id,o=t.target.name,r='tsf-flex-tab-content-active',l='tsf-flex-tab-active',c=jQuery('.'+r),g=n.closest('.tsf-flex-nav-tab-wrapper').find('.'+l),d=c.find('input:invalid, select:invalid, textarea:invalid');if(d.length){try{d[0].reportValidity()}catch(f){let h=jQuery(t.target.form).find('#publishing-action input[type="submit"], #save-action input[type="submit"]');h.length&&h[0].click()}return g.prop('checked',!0),n.prop('checked',!1),t.stopPropagation(),t.preventDefault(),!1}let u=jQuery('#'+a+'-content');if(g.removeClass(l),g.siblings('label').removeClass('tsf-no-focus-ring'),n.addClass(l),s){let f=jQuery('.'+o+'-content');f.removeClass(r).hide(),u.addClass(r).show(),jQuery('#'+a).trigger('tsf-flex-tab-toggled')}else if(u.length&&!u.is(c)){let f=jQuery('.'+o+'-content');f.fadeOut(150,function(){jQuery(this).removeClass(r)}),setTimeout(function(){u.addClass(r).fadeIn(250)},150),setTimeout(function(){jQuery('#'+a).trigger('tsf-flex-tab-toggled')},175)}}},addNoFocusClass:function(){this.classList.add('tsf-no-focus-ring')},setTabsOnload:function(){tsf.hasInput&&(tsf.states.isPostEdit&&jQuery('.tsf-flex-nav-tab-radio:checked').trigger('change',[!0]),tsf.states.isSettingsPage&&jQuery('.tsf-tabs-radio:checked').each(function(t,s){jQuery(s).trigger('change',[!0])}))},_initPostboxToggle:function(){let t;if(tsf.states.isSettingsPage?t=jQuery('.postbox[id^="autodescription-"]').find('.hndle, .handlediv'):tsf.states.isPostEdit&&(t=jQuery('.postbox#tsf-inpost-box').find('.hndle, .handlediv')),t&&t.length){let s;const n=function(){try{s[0].reportValidity()}catch(o){let r=jQuery(s[0].form).find('input[type=submit]').not('.autodescription-site-settings\\[tsf-settings-reset\\]');r.length&&r[0].click()}};t.on('click.tsfPostboxes',function(o){let r=jQuery(o.target).closest('.postbox');r[0].classList.contains('closed')&&(s=r.find('input:invalid, select:invalid, textarea:invalid'),s.length&&(jQuery(document).one('postbox-toggled',n),jQuery(o.target).trigger('click')))})}},taglineToggleDesc:function(t){let s=jQuery(t.target),n=jQuery('#tsf-on-blogname-js');s.is(':checked')?n.css('display','inline'):n.css('display','none')},additionsToggleDesc:function(t){let s=jQuery(t.target),n=jQuery('#tsf-description-additions-js');s.is(':checked')?n.css('display','inline'):n.css('display','none')},taglineToggleOnload:function(){if(tsf.hasInput){let t=jQuery('#tsf-title-tagline-toggle :input'),s=jQuery('.tsf-custom-blogname-js'),n=jQuery('#tsf-description-additions-toggle :input'),a=jQuery('#tsf-description-additions-js'),o=jQuery('#tsf-description-onblogname-toggle :input'),r=jQuery('#tsf-on-blogname-js'),l=jQuery('#tsf-title-additions-toggle :input'),c=jQuery('.tsf-title-additions-js');t.is(':checked')?s.css('display','inline'):s.css('display','none'),n.is(':checked')?a.css('display','inline'):a.css('display','none'),o.is(':checked')?r.css('display','inline'):r.css('display','none'),l.is(':checked')?c.css('display','none'):c.css('display','inline')}},attachUnsavedChangesListener:function(){if(tsf.hasInput){const t=function(o){jQuery(o.data._input).not(o.data._except).off(o.type,s)},s=function(o){tsf.registerChange(),t(o)};let n,a='.tsf-input-not-saved';n=['.tsf-metaboxes :input','#tsf-inpost-box .inside :input'].join(', '),jQuery(n).not(a).off('change.tsfChangeListener').on('change.tsfChangeListener',{_input:n,_except:a},s),n=['.tsf-metaboxes input[type=text]','.tsf-metaboxes textarea','#tsf-inpost-box .inside input[type=text]','#tsf-inpost-box .inside textarea'].join(', '),jQuery(n).not(a).off('input.tsfChangeListener').on('input.tsfChangeListener',{_input:n,_except:a},s),jQuery(window).off('beforeunload.tsfChangeListener').on('beforeunload.tsfChangeListener',function(){if(tsf.settingsChanged)return tsf.i18n.saveAlert}),jQuery(['.tsf-metaboxes input[type="submit"]','#publishing-action input[type="submit"]','#save-action input[type="submit"]','a.submitdelete'].join(', ')).off('click.tsfChangeListener').on('click.tsfChangeListener',function(){tsf.settingsChanged=!1})}},registerChange:function(){tsf.settingsChanged=!0},confirmedReset:function(){return confirm(tsf.i18n.confirmReset)},onLoadUnregisterChange:function(){tsf.settingsChanged=!1},dismissNotice:function(t){jQuery(t.target).parents('.tsf-notice').slideUp(200,function(){this.remove()})},setAjaxLoader:function(t){jQuery(t).toggleClass('tsf-loading')},unsetAjaxLoader:function(t,s){let n='tsf-success',a=2500;s||(n='tsf-error',a=5e3),jQuery(t).removeClass('tsf-loading').addClass(n).fadeOut(a)},resetAjaxLoader:function(t){jQuery(t).stop().empty().prop('class','tsf-ajax').css('opacity','1').removeProp('style')},setColorOnload:function(){let t=jQuery('.tsf-color-picker');t.length&&jQuery.each(t,function(s,n){let a=jQuery(n),o='',r=a.data('tsf-default-color');a.wpColorPicker({defaultColor:r,width:238,change:function(){o=a.wpColorPicker('color'),''==o&&(o=r),a.val(o),tsf.registerChange()},clear:function(){a.parent().siblings('.wp-color-result').css('backgroundColor',r),tsf.registerChange()},palettes:!1})})},_doFlexResizeListener:function(){if(jQuery('.tsf-flex').length){tsf._setResizeListeners();let t=0,s={},n=0,a=jQuery('.tsf-flex-nav-tab-wrapper'),o=jQuery(window);o.on('tsf-flex-resize',function(){clearTimeout(t);let r=0;t=setTimeout(function(){if(a.length){let l=jQuery('.tsf-flex-nav-tab-inner'),c=a.width(),g=l.width(),d=jQuery('.tsf-flex-nav-name');s.tabWrapper||(s.tabWrapper={},s.tabWrapper.outer=0,s.tabWrapper.inner=0,s.tabWrapper.shown=1),!s.tabWrapper.shown&&s.tabWrapper.outer<c&&(d.fadeIn(250),setTimeout(function(){g=l.width()},r)),setTimeout(function(){g>c?(d.hide(),s.tabWrapper.shown=0):s.tabWrapper.outer<c&&(d.fadeIn(250),s.tabWrapper.shown=1)},2*r),setTimeout(function(){s.tabWrapper.outer=c,s.tabWrapper.inner=g},3*r)}},n),r=10,n=75}),o.trigger('tsf-flex-resize')}},_setResizeListeners:function(){jQuery(window).on('resize orientationchange',tsf._triggerResize),jQuery('#collapse-menu').click(tsf._triggerResize),jQuery('.columns-prefs :input[type=radio]').change(tsf._triggerResize),jQuery('.meta-box-sortables').on('sortupdate',tsf._triggerResize)},_triggerResize:function(){jQuery(window).trigger('tsf-flex-resize')},_triggerCounterUpdate:function(){jQuery(window).trigger('tsf-counter-updated')},_triggerReady:function(){jQuery(document.body).trigger('tsf-ready')},_triggerOnLoad:function(){jQuery(document.body).trigger('tsf-onload')},_doReady:function(){tsf._triggerOnLoad(),tsf._initCounters(),tsf._initTitleInputs(),tsf._initUnboundTitleSettings(),tsf._initSocialTitleInputs(),tsf._initDescInputs(),tsf._initSocialDescInputs(),tsf._initWebmastersInput(),tsf.setTabsOnload(),tsf._initPostboxToggle(),tsf.taglineToggleOnload(),tsf.setColorOnload(),tsf.attachUnsavedChangesListener(),tsf.onLoadUnregisterChange(),tsf._doFlexResizeListener(),tsf._triggerReady()},setupVars:function(){tsf.counterType=parseInt(tsf.states.counterType),tsf.hasInput=tsf.states.hasInput},ready:function(t){t('.updated, .error, .notice-error, .notice-warning').insertAfter('.tsf-top-wrap'),tsf.setupVars(),t('.tsf-js-confirm-reset').on('click',tsf.confirmedReset),t('.tsf-tabs-radio').on('change',tsf.tabToggle),t('.tsf-tab').on('click','.tsf-nav-tab',tsf.addNoFocusClass),t('.tsf-flex-nav-tab-radio').on('change',tsf.flexTabToggle),t('.tsf-flex-nav-tab').on('click','.tsf-flex-nav-tab-label',tsf.addNoFocusClass),t('#tsf-description-onblogname-toggle :input').on('click',tsf.taglineToggleDesc),t('#tsf-description-additions-toggle :input').on('click',tsf.additionsToggleDesc),t('.tsf-dismiss').on('click',tsf.dismissNotice),t(document.body).ready(tsf._doReady)}},jQuery(tsf.ready);
1
+ 'use strict';window.tsf={nonces:tsfL10n.nonces,i18n:tsfL10n.i18n,states:tsfL10n.states,params:tsfL10n.params,settingsChanged:!1,counterType:0,hasInput:!1,browseUnhappy:!!navigator.userAgent.match(/Trident\/7\./),counterClasses:{0:'tsf-counter-zero',1:'tsf-counter-one',2:'tsf-counter-two',3:'tsf-counter-three'},confirm:function(t){return confirm(t)},stripTags:function(t){return t.replace(/(<([^>]+)?>?)/ig,'')},escapeString:function(t){if(!t.length)return'';let s={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&#039;','\\\\':'&#92;','\\':''};return t.replace(/[&<>"']|\\\\|\\/g,function(n){return s[n]})},unescapeString:function(t){if(!t.length)return'';let s={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&#039;','\\':'&#92;'},n={};n=tsf.browseUnhappy?Object.keys(s).map(function(o){return s[o]}):Object.values(s);let a=new RegExp(n.map(function(o){return o.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,'\\$&')}).join('|'),'g');return tsf.browseUnhappy?t.replace(a,function(o){for(let r in s)if(s[r]===o)return r;return o}):t.replace(a,function(o){return Object.keys(s).find(function(r){return s[r]===o})})},sDoubleSpace:function(t){return t.replace(/\s\s+/g,' ')},getStringLength:function(t){let s,n=0;return t.length&&(s=document.createElement('span'),s.innerHTML=tsf.escapeString(t).trim(),'undefined'!=typeof s.childNodes[0]&&(n=s.childNodes[0].nodeValue.length)),+n},convertJSONResponse:function(t){let s=t&&t.json||void 0,n=1===s;if(!n){let a=t;try{t=JSON.parse(t),n=!0}catch(o){n=!1}n||(t=a)}return t},updateCharacterCounter:function(t){let s=t.e,n=t.text,a=t.guidelines,o=tsf.getStringLength(n),r='',l='',c={bad:'tsf-count-bad',okay:'tsf-count-okay',good:'tsf-count-good',unknown:'tsf-count-unknown'};switch(o?o<a.lower?(r=c.bad,l=tsf.i18n.inputGuidelines.short.farTooShort):o<a.goodLower?(r=c.okay,l=tsf.i18n.inputGuidelines.short.tooShort):o>a.upper?(r=c.bad,l=tsf.i18n.inputGuidelines.short.farTooLong):o>a.goodUpper?(r=c.okay,l=tsf.i18n.inputGuidelines.short.tooLong):(r=c.good,l=tsf.i18n.inputGuidelines.short.good):(r=c.unknown,l=tsf.i18n.inputGuidelines.short.empty),tsf.counterType){case 3:l=o.toString()+' - '+l;break;case 2:break;case 1:default:l=o.toString();}for(let g in s.innerHTML=l,c)s.classList.remove(c[g]);for(let g in tsf.counterClasses)s.classList.remove(tsf.counterClasses[g]);s.classList.add(r),s.classList.add(tsf.counterClasses[tsf.counterType])},updatePixelCounter:function(t){let s=t.e,n=t.text,a=t.guidelines,o=s.parentElement;if(o){let r=o.querySelector('.tsf-pixel-counter-bar'),l=o.querySelector('.tsf-pixel-counter-shadow');if(r&&l){l.innerHTML=tsf.escapeString(n);let c=l.offsetWidth,g='',d='',u='',f={bad:'tsf-pixel-counter-bad',okay:'tsf-pixel-counter-okay',good:'tsf-pixel-counter-good',unknown:'tsf-pixel-counter-unknown'};d=100*(c/a.goodUpper)+'%',c?c<a.lower?(g=f.bad,u=tsf.i18n.inputGuidelines.long.farTooShort):c<a.goodLower?(g=f.okay,u=tsf.i18n.inputGuidelines.long.tooShort):c>a.upper?(d=100*(a.upper/(c+2*(c-a.upper)/3))+'%',g=f.bad,u=tsf.i18n.inputGuidelines.long.farTooLong):c>a.goodUpper?(g=f.okay,u=tsf.i18n.inputGuidelines.long.tooLong,d='100%'):(g=f.good,u=tsf.i18n.inputGuidelines.long.good):(g=f.unknown,d='100%',u=tsf.i18n.inputGuidelines.long.empty);let b,h=r.querySelector('.tsf-pixel-counter-fluid');for(let x in b=tsf.i18n.pixelsUsed.replace(/%1\$d/g,c),b=b.replace(/%2\$d/g,a.goodUpper),b=b+'<br>'+u,f)r.classList.remove(f[x]);r.classList.add(g),h.style.width=d,r.dataset.desc=b,r.setAttribute('aria-label',b),tsfTT.triggerUpdate(r)}}},_initTitleInputs:function(){if(tsf.hasInput){let t=jQuery(['#autodescription_title','#autodescription-meta\\[doctitle\\]','#autodescription-site-settings\\[homepage_title\\]'].join(', '));if(t.length){let n,a,o,l,s=!1,r='',c='',g=tsf.params.titleSeparator,d=tsf.params.defaultTitle,u=tsf.states.useTagline,f=tsf.states.isRTL,h=tsf.states.isPrivate,b=tsf.states.isPasswordProtected,x=tsf.states.stripTitleTags;n=f?'after':'before';const y=function(){let Q='before';tsf.states.isSettingsPage?f?'right'===jQuery('#tsf-home-title-location input:checked').val()&&(Q='after'):'left'===jQuery('#tsf-home-title-location input:checked').val()&&(Q='after'):tsf.states.isHome?f?'right'===tsf.params.titleLocation&&(Q='after'):'left'===tsf.params.titleLocation&&(Q='after'):f?'left'===tsf.params.titleLocation&&(Q='after'):'right'===tsf.params.titleLocation&&(Q='after'),a=Q};y();const _=function(){let Q='';if(!tsf.states.isSettingsPage)tsf.states.isHome?u&&(Q=tsf.params.titleAdditions):u&&(Q=tsf.params.titleAdditions);else if(u){let X=document.getElementById('autodescription-site-settings[homepage_title_tagline]'),Y=X&&X.value||'';Y=tsf.sDoubleSpace(Y.trim()),Q=Y.length?Y:tsf.params.blogDescription}Q.length&&(Q=tsf.escapeString(tsf.sDoubleSpace(Q.trim())),'before'===a?Q=Q+' '+g+' ':'after'===a?Q=' '+g+' '+Q:void 0),c=Q.length?Q:'',l=document.getElementById('tsf-title-placeholder'),c.length&&l&&(l.innerHTML=c)};_();const L=function(){let Q='';h?Q=tsf.i18n.privateTitle:b&&(Q=tsf.i18n.protectedTitle),Q.length&&(Q=tsf.escapeString(Q),'before'===n?Q+=' ':'after'===n?Q=' '+Q:void 0),r=Q.length?Q:'',r.length&&o&&(o.innerHTML=r),o=document.getElementById('tsf-title-placeholder-prefix'),r.length&&o&&(o.innerHTML=r)};L();const C=function(Q){if(l||o){let X=jQuery(Q.target),Y=X.val(),Z=!!c.length,ee=!!r.length;if(!Z&&l&&(l.style.display='none'),!ee&&o&&(o.style.display='none'),!Z&&!ee)return void X.css('text-indent','initial');if(!Y.length)return X.css('text-indent','initial'),l&&(l.style.display='none'),void(o&&(o.style.display='none'));let te=X.outerWidth(!0),se=(X.outerHeight(!0)-X.height())/2,ie=(te-X.innerWidth())/2,ne=f?'right':'left',ae=(X.outerWidth(!0)-X.width())/2,oe={display:X.css('display'),lineHeight:X.css('lineHeight'),fontFamily:X.css('fontFamily'),fontWeight:X.css('fontWeight'),fontSize:X.css('fontSize'),letterSpacing:X.css('letterSpacing'),paddingTop:se+'px',paddingBottom:se+'px'},re=jQuery(o),le=jQuery(l),pe=0,ce=0,ge=0,de=0,ue=0,fe=0;if(ee&&(re.css(oe),re.css({maxWidth:'initial'}),ue=re[0].getBoundingClientRect().width,ue<fe&&(ue=0)),Z){let me=0;switch(function(){let be=jQuery('#tsf-title-offset');be.text(Y),be.css({fontFamily:oe.fontFamily,fontWeight:oe.fontWeight,letterSpacing:oe.letterSpacing,fontSize:oe.fontSize}),me=be[0].getBoundingClientRect().width}(),pe=X[0].getBoundingClientRect().width-ie-ae-me-ue,pe<fe&&(ue+=pe,pe=0),le.css(oe),le.css({maxWidth:'initial'}),a){case'before':let be=le[0].getBoundingClientRect().width;be=pe<be?pe:be,be<fe&&(be=0),pe=be,de+=pe,ge+=pe,ce+=ae;break;case'after':ce+=ae+me+ue;}}ge+=ae,ue=0>ue?0:ue,de+=ue;let he;ee&&(he={},he[ne]=ge+'px',he.maxWidth=ue+'px',re.css(he)),Z&&(he={},he[ne]=ce+'px',he.maxWidth=pe+'px',le.css(he)),he={},he['text-indent']=de+'px',X.css(he)}},w=function(){let X='',Y=!!c.length,Z=!!r.length,ee=c,te=r;tsf.states.isTermEdit&&tsf.params.termName&&(te=f?' :'+tsf.params.termName:tsf.params.termName+': ',Z=tsf.states.useTermPrefix),X=d,Z&&('before'===n?X=te+X:'after'===n?X+=te:void 0),Y&&('before'===a?X=ee+X:'after'===a?X+=ee:void 0),tsf.browseUnhappy&&(s=!0);let se=document.createElement('span');se.innerHTML=tsf.escapeString(tsf.sDoubleSpace(X)),t.prop('placeholder',tsf.unescapeString(se.textContent)),tsf.browseUnhappy&&setTimeout(function(){s=!1},0)},T=function(Q){let X=document.getElementById('tsf-title-reference'),Y=Q.target.value;X&&(Y=Y.trim(),1>Y.length||tsf.states.homeLocks.refTitleLock?Y=Q.target.placeholder:(r.length&&('before'===n?Y=r+Y:'after'===n?Y+=r:void 0),c.length&&('before'===a?Y=c+Y:'after'===a?Y+=c:void 0)),X.innerHTML=tsf.escapeString(tsf.sDoubleSpace(Y)),setTimeout(function(){jQuery(X).change()},0))},S=function(Q){let X=document.getElementById(Q.target.id+'_chars'),Y=document.getElementById('tsf-title-reference');if(X&&Y){let Z={e:X,text:tsf.unescapeString(Y.innerHTML),guidelines:tsf.params.inputGuidelines.title.search.chars};tsf.updateCharacterCounter(Z)}},I=function(Q){let X=document.getElementById(Q.target.id+'_pixels'),Y=document.getElementById('tsf-title-reference');if(X&&Y){let Z={e:X,text:tsf.unescapeString(Y.innerHTML),guidelines:tsf.params.inputGuidelines.title.search.pixels};tsf.updatePixelCounter(Z)}};t.on('input.tsfUpdateTitles',function(Q){return!s&&void(C(Q),w(),T(Q),S(Q),I(Q))});t.on('tsf-update-title-counter',function(Q){T(Q),S(Q),I(Q)});const U=function(){t.trigger('tsf-update-title-counter')},P=function(){_(),z()};jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').on('input',P),jQuery('#autodescription-site-settings\\[homepage_tagline\\]').on('change',P);jQuery('#tsf-title-tagline-toggle :input').on('click',function(Q){let X=u;jQuery(Q.target).is(':checked')?(jQuery('.tsf-custom-blogname-js').css('display','inline'),u=!0):(jQuery('.tsf-custom-blogname-js').css('display','none'),u=!1),X^u&&(_(),O())});const H=function(Q){switch(h=!1,b=!1,Q){case'password':b=!0;break;case'private':h=!0;break;default:case'public':}L(),O()};jQuery(document).on('tsf-updated-gutenberg-visibility',function(Q,X){return H(X)});jQuery('#visibility .save-post-visibility').on('click',function(){let X=jQuery('#visibility').find('input:radio:checked').val();if('password'===X){let Y=jQuery('#visibility').find('#post_password').val(),Z=!!Y&&!!Y.length;Z||(X='public')}H(X)});jQuery('#tsf-title-separator :input').on('click',function(Q){let X=jQuery(Q.target).val(),Y='';Y='pipe'===X?'|':'dash'===X?'-':jQuery('<div/>').html('&'+X+';').text(),g=Y,jQuery('.tsf-sep-js').text(' '+g+' '),_(),O()});const z=function(){t.trigger('input.tsfUpdateTitles')};let B=0;const O=function(){clearTimeout(B),B=setTimeout(z,10)};jQuery(window).on('tsf-counter-updated',O);const G=function(){let Q=tsf.settingsChanged;z(),tsf.settingsChanged=Q};let A=0;const M=function(){clearTimeout(A),A=setTimeout(G,10)};jQuery(window).on('tsf-flex-resize',M),jQuery('#tsf-homepage-tab-general').on('tsf-tab-toggled',M),jQuery('#tsf-flex-inpost-tab-general').on('tsf-flex-tab-toggled',M),M();let N=['autodescription-homepage-settings','tsf-inpost-box'];jQuery(document).on('postbox-toggled',function(Q,X){if(0<=N.indexOf(X.id)){let Y=X.querySelector('.inside');0<Y.offsetHeight&&0<Y.offsetWidth&&G()}});jQuery('#tsf-home-title-location :input').on('click',function(){y(),_(),O()});const V=function(Q){Q='string'==typeof Q&&Q.trim()||'',d=Q.length?tsf.escapeString(x?tsf.stripTags(Q):Q):tsf.params.untitledTitle,w(),U()};tsf.states.isHome||(jQuery('#edittag #name, #titlewrap #title').on('input',function(Q){return V(Q.target.value)}),jQuery(document).on('tsf-updated-gutenberg-title',function(Q,X){return V(X)}));tsf.states.isHome||(jQuery('#autodescription_title_no_blogname').on('change',function(Q){if(!tsf.states.taglineLocked){let X=u;u=!jQuery(Q.target).is(':checked'),X^u&&(_(),O())}}),jQuery('#autodescription_title_no_blogname').trigger('change'));(function(){let Q=0,X=window.innerWidth;window.addEventListener('resize',function(){clearTimeout(Q),Q=setTimeout(function(){let Y=window.innerWidth;X<Y?782>=X&&782<=Y&&G():782<=X&&782>=Y&&G(),X=Y},50)})})()}}},_initUnboundTitleSettings:function(){if(tsf.hasInput){let t=jQuery(['#autodescription_title','#autodescription-meta\\[doctitle\\]','#autodescription-site-settings\\[homepage_title\\]'].join(', '));jQuery('#tsf-title-placeholder, #tsf-title-placeholder-prefix').on('click',function(c){let g=jQuery(c.target).siblings(t)[0];if('function'==typeof g.setSelectionRange){g.focus();let d=2*g.value.length;g.setSelectionRange(d,d)}else{let d=g.value;g.value='',g.focus(),g.value=d}});jQuery('#autodescription-site-settings\\[title_rem_additions\\]').on('click',function(c){jQuery(c.target).is(':checked')?jQuery('.tsf-title-additions-js').css('display','none'):jQuery('.tsf-title-additions-js').css('display','inline')});jQuery('#tsf-title-location input').on('click',function(c){let g=jQuery('.tsf-title-additions-example-left'),d=jQuery('.tsf-title-additions-example-right');'right'===jQuery(c.target).val()?(g.css('display','none'),d.css('display','inline')):(g.css('display','inline'),d.css('display','none'))});jQuery('#autodescription-site-settings\\[homepage_title\\]').on('input',function(c){let g=c.target.value||'',d=jQuery('.tsf-custom-title-js');0===g.length?d.text(tsf.params.defaultTitle):d.text(g)});jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').on('input.tsfInputTagline',function(c){let g=c.target.value||'',d=jQuery('.tsf-custom-tagline-js');g=tsf.escapeString(tsf.sDoubleSpace(g.trim())),g.length?(d.html(g),jQuery('#tsf-home-title-location .tsf-sep-js').show()):(d.text(tsf.params.blogDescription),0===tsf.params.blogDescription.length?jQuery('#tsf-home-title-location .tsf-sep-js').hide():jQuery('#tsf-home-title-location .tsf-sep-js').show())}),jQuery('#autodescription-site-settings\\[homepage_title_tagline\\]').trigger('input.tsfInputTagline');jQuery('#tsf-title-prefixes-toggle :input').on('click',function(c){let g=jQuery(c.target),d=jQuery('.tsf-title-prefix-example');g.is(':checked')?d.css('display','none'):d.css('display','inline')})}},_initDescInputs:function(){if(tsf.hasInput){let t=jQuery(['#autodescription_description','#autodescription-meta\\[description\\]','#autodescription-site-settings\\[homepage_description\\]'].join(', '));if(t.length){const s=function(b){let x=document.getElementById(b.target.id+'_chars'),y=document.getElementById('tsf-description-reference');if(x&&y){let _={e:x,text:tsf.unescapeString(y.innerHTML),guidelines:tsf.params.inputGuidelines.description.search.chars};tsf.updateCharacterCounter(_)}},n=function(b){let x=document.getElementById('tsf-description-reference'),y=b.target.value;x&&(y=y.trim(),(1>y.length||tsf.states.homeLocks.refDescriptionLock)&&(y=b.target.placeholder),x.innerHTML=tsf.escapeString(tsf.sDoubleSpace(y)),setTimeout(function(){jQuery(x).change()},0))},a=function(b){let x=document.getElementById(b.target.id+'_pixels'),y=document.getElementById('tsf-description-reference');if(x&&y){let _={e:x,text:tsf.unescapeString(y.innerHTML),guidelines:tsf.params.inputGuidelines.description.search.pixels};tsf.updatePixelCounter(_)}};t.on('input.tsfUpdateDescriptions',function(b){n(b),s(b),a(b)});const r=function(){t.trigger('input.tsfUpdateDescriptions')};let l=0;const c=function(){clearTimeout(l),l=setTimeout(r,10)};jQuery(window).on('tsf-counter-updated',c);const g=function(){let b=tsf.settingsChanged;r(),tsf.settingsChanged=b};let d=0;const u=function(){clearTimeout(d),d=setTimeout(g,10)};jQuery('#tsf-homepage-tab-general').on('tsf-tab-toggled',u),jQuery('#tsf-flex-inpost-tab-general').on('tsf-flex-tab-toggled',u),u();let f=['autodescription-homepage-settings','tsf-inpost-box'];jQuery(document).on('postbox-toggled',function(b,x){if(0<=f.indexOf(x.id)){let y=x.querySelector('.inside');0<y.offsetHeight&&0<y.offsetWidth&&c()}})}}},_initSocialTitleInputs:function(){if(tsf.hasInput){let t=jQuery('#autodescription_og_title, #autodescription-site-settings\\[homepage_og_title\\]'),s=jQuery('#autodescription_twitter_title, #autodescription-site-settings\\[homepage_twitter_title\\]'),n=jQuery('#tsf-title-reference');if(t.length&&s.length&&n.length){let a=!1,o=tsf.states.homeLocks.ogTitleLock,r=tsf.states.homeLocks.ogTitlePHLock,l=tsf.states.homeLocks.twTitleLock,c=tsf.states.homeLocks.twTitlePHLock,g=o?t.prop('placeholder'):t.val(),d=l?s.prop('placeholder'):s.val(),u=n.text();const f=function(C){let w='';switchActive:switch(C){case'twitter':if(w=d,l||c){w=w.length?w:s.prop('placeholder');break switchActive}case'og':if(w=w.length?w:g,o||r){w=w.length?w:t.prop('placeholder');break switchActive}case'reference':w=w.length?w:u;}return w},h=function(){tsf.browseUnhappy&&(a=!0),o||r||t.prop('placeholder',f('reference')),l||c||s.prop('placeholder',f('og')),tsf.browseUnhappy&&setTimeout(function(){a=!1},0)},b=function(C,w,T){let S=document.getElementById(C.id+'_chars');if(S){let I={e:S,text:tsf.unescapeString(w),guidelines:tsf.params.inputGuidelines.title[T].chars};tsf.updateCharacterCounter(I)}};let x=0;const y=function(){clearTimeout(x),x=setTimeout(function(){t.each(function(C,w){return b(w,f('og'),'opengraph')}),s.each(function(C,w){return b(w,f('twitter'),'twitter')})},10)};n.on('change',function(){u=n.text(),h(),y()});t.on('input.tsfUpdateOgTitle',function(C){if(!a){if(!o){let w=C.target.value.trim();g=w.length?tsf.sDoubleSpace(w):''}h(),y()}}),s.on('input.tsfUpdateTwTitle',function(C){if(!a){if(!l){let w=C.target.value.trim();d=w.length?tsf.sDoubleSpace(w):''}h(),y()}})}}},_initSocialDescInputs:function(){if(tsf.hasInput){let t=jQuery('#autodescription_og_description, #autodescription-site-settings\\[homepage_og_description\\]'),s=jQuery('#autodescription_twitter_description, #autodescription-site-settings\\[homepage_twitter_description\\]'),n=jQuery('#tsf-description-reference');if(t.length&&s.length&&n.length){let a=!1,o=tsf.states.homeLocks.ogDescriptionLock,r=tsf.states.homeLocks.ogDescriptionPHLock,l=tsf.states.homeLocks.twDescriptionLock,c=tsf.states.homeLocks.twDescriptionPHLock,g=o?t.prop('placeholder'):t.val(),d=l?s.prop('placeholder'):s.val(),u=n.text(),f=jQuery(['#autodescription_description','#autodescription-meta\\[description\\]','#autodescription-site-settings\\[homepage_description\\]'].join(', '));const h=function(w,T){let S='';switchActive:switch(w){case'twitter':if(S=d,l||c){S=S.length?S:s.prop('placeholder');break switchActive}case'og':if(S=S.length?S:g,o||r){S=S.length?S:t.prop('placeholder');break switchActive}case'reference':S.length||(f.val().length?S=u:'twitter'===T?S=tsf.params.socialPlaceholders.twDesc:'og'==T&&(S=tsf.params.socialPlaceholders.ogDesc));}return S},b=function(){tsf.browseUnhappy&&(a=!0),o||r||t.attr('placeholder',h('reference','og')),l||c||s.attr('placeholder',h('og','twitter')),tsf.browseUnhappy&&setTimeout(function(){a=!1},0)},x=function(w,T,S){let I=document.getElementById(w.id+'_chars');if(I){let j={e:I,text:tsf.unescapeString(T),guidelines:tsf.params.inputGuidelines.description[S].chars};tsf.updateCharacterCounter(j)}};let y=0;const _=function(){clearTimeout(y),y=setTimeout(function(){t.each(function(w,T){return x(T,h('og','og'),'opengraph')}),s.each(function(w,T){return x(T,h('twitter','twitter'),'twitter')})},10)};n.on('change',function(){u=n.text(),b(),_()});t.on('input.tsfUpdateOgDesc',function(w){if(!a){if(!o){let T=w.target.value.trim();g=T.length?tsf.sDoubleSpace(T):''}b(),_()}}),s.on('input.tsfUpdateOgDesc',function(w){if(!a){if(!l){let T=w.target.value.trim();d=T.length?tsf.sDoubleSpace(T):''}b(),_()}})}}},_initCanonicalInput:function(){let t=jQuery('#autodescription_canonical');if(t){const s=function(n){t.attr('placeholder',n)};jQuery(document).on('tsf-updated-gutenberg-link',function(n,a){return s(a)})}},_initWebmastersInput:function(){if(tsf.states.isSettingsPage){let t=jQuery(['#autodescription-site-settings\\[google_verification\\]','#autodescription-site-settings\\[bing_verification\\]','#autodescription-site-settings\\[yandex_verification\\]','#autodescription-site-settings\\[pint_verification\\]'].join(', '));t.length&&t.on('paste',function(s){let n=s.originalEvent.clipboardData&&s.originalEvent.clipboardData.getData('text')||void 0;if(n){let a=/<meta[^>]+content=(\"|\')?([^\"\'>\s]+)\1?.*?>/i.exec(n);a&&2 in a&&'string'==typeof a[2]&&a[2].length&&(s.stopPropagation(),s.preventDefault(),s.target.value=a[2])}})}},_initCounters:function(){if(tsf.hasInput){jQuery('.tsf-counter').on('click',function(){++tsf.counterType,3<tsf.counterType&&(tsf.counterType=0),s();let r='.tsf-counter-wrap .tsf-ajax',l=0;tsf.resetAjaxLoader(r),tsf.setAjaxLoader(r);let c={method:'POST',url:ajaxurl,datatype:'json',data:{action:'the_seo_framework_update_counter',nonce:tsf.nonces.edit_posts,val:tsf.counterType},async:!0,success:function(g){switch(g=tsf.convertJSONResponse(g),'success'===g.type&&(l=1),l){case 0:tsf.unsetAjaxLoader(r,!1);break;case 1:tsf.unsetAjaxLoader(r,!0);break;default:tsf.resetAjaxLoader(r);}}};jQuery.ajax(c)});const s=function(){tsf.counterType=+tsf.counterType,3<tsf.counterType&&(tsf.counterType=0),tsf._triggerCounterUpdate()};jQuery('#autodescription-site-settings\\[display_character_counter\\]').on('click',function(o){jQuery(o.target).is(':checked')?jQuery('.tsf-counter-wrap').show():jQuery('.tsf-counter-wrap').hide()});jQuery('#autodescription-site-settings\\[display_pixel_counter\\]').on('click',function(o){jQuery(o.target).is(':checked')?(jQuery('.tsf-pixel-counter-wrap').show(),tsf._triggerCounterUpdate()):jQuery('.tsf-pixel-counter-wrap').hide()})}},tabToggle:function(t,s){let n=jQuery(t.target);if(n.is(':checked')){s='boolean'==typeof s&&s;let a=t.target.id,o=t.target.name,r='tsf-active-tab-content',l='tsf-tab-active',c=jQuery('.'+r),g=n.closest('.tsf-nav-tab-wrapper').find('.'+l),d=c.find('input:invalid, select:invalid, textarea:invalid');if(d.length){try{d[0].reportValidity()}catch(f){let h=jQuery(t.target.form).find('input[type=submit]').not('.autodescription-site-settings\\[tsf-settings-reset\\]');h.length&&h[0].click()}return g.prop('checked',!0),n.prop('checked',!1),t.stopPropagation(),t.preventDefault(),!1}let u=jQuery('#'+a+'-content');if(g.removeClass(l),g.siblings('label').removeClass('tsf-no-focus-ring'),n.addClass(l),s){let f=jQuery('.'+o+'-content');f.removeClass(r).hide(),u.addClass(r).show(),jQuery('#'+a).trigger('tsf-tab-toggled')}else if(u.length&&!u.is(c)){let f=jQuery('.'+o+'-content');f.fadeOut(150,function(){jQuery(this).removeClass(r)}),setTimeout(function(){u.addClass(r).fadeIn(250)},150),setTimeout(function(){jQuery('#'+a).trigger('tsf-tab-toggled')},175)}}},flexTabToggle:function(t,s){let n=jQuery(t.target);if(n.is(':checked')){s='boolean'==typeof s&&s;let a=t.target.id,o=t.target.name,r='tsf-flex-tab-content-active',l='tsf-flex-tab-active',c=jQuery('.'+r),g=n.closest('.tsf-flex-nav-tab-wrapper').find('.'+l),d=c.find('input:invalid, select:invalid, textarea:invalid');if(d.length){try{d[0].reportValidity()}catch(f){let h=jQuery(t.target.form).find('#publishing-action input[type="submit"], #save-action input[type="submit"]');h.length&&h[0].click()}return g.prop('checked',!0),n.prop('checked',!1),t.stopPropagation(),t.preventDefault(),!1}let u=jQuery('#'+a+'-content');if(g.removeClass(l),g.siblings('label').removeClass('tsf-no-focus-ring'),n.addClass(l),s){let f=jQuery('.'+o+'-content');f.removeClass(r).hide(),u.addClass(r).show(),jQuery('#'+a).trigger('tsf-flex-tab-toggled')}else if(u.length&&!u.is(c)){let f=jQuery('.'+o+'-content');f.fadeOut(150,function(){jQuery(this).removeClass(r)}),setTimeout(function(){u.addClass(r).fadeIn(250)},150),setTimeout(function(){jQuery('#'+a).trigger('tsf-flex-tab-toggled')},175)}}},addNoFocusClass:function(){this.classList.add('tsf-no-focus-ring')},setTabsOnload:function(){tsf.hasInput&&(tsf.states.isPostEdit&&jQuery('.tsf-flex-nav-tab-radio:checked').trigger('change',[!0]),tsf.states.isSettingsPage&&jQuery('.tsf-tabs-radio:checked').each(function(t,s){jQuery(s).trigger('change',[!0])}))},_initPostboxToggle:function(){let t;if(tsf.states.isSettingsPage?t=jQuery('.postbox[id^="autodescription-"]').find('.hndle, .handlediv'):tsf.states.isPostEdit&&(t=jQuery('.postbox#tsf-inpost-box').find('.hndle, .handlediv')),t&&t.length){let s;const n=function(){try{s[0].reportValidity()}catch(o){let r=jQuery(s[0].form).find('input[type=submit]').not('.autodescription-site-settings\\[tsf-settings-reset\\]');r.length&&r[0].click()}};t.on('click.tsfPostboxes',function(o){let r=jQuery(o.target).closest('.postbox');r[0].classList.contains('closed')&&(s=r.find('input:invalid, select:invalid, textarea:invalid'),s.length&&(jQuery(document).one('postbox-toggled',n),jQuery(o.target).trigger('click')))})}},taglineToggleOnload:function(){if(tsf.hasInput){let t=jQuery('#tsf-title-tagline-toggle :input'),s=jQuery('.tsf-custom-blogname-js'),n=jQuery('#tsf-title-additions-toggle :input'),a=jQuery('.tsf-title-additions-js');t.is(':checked')?s.css('display','inline'):s.css('display','none'),n.is(':checked')?a.css('display','none'):a.css('display','inline')}},attachUnsavedChangesListener:function(){if(tsf.hasInput){const t=function(o){jQuery(o.data._input).not(o.data._except).off(o.type,s)},s=function(o){tsf.registerChange(),t(o)};let n,a='.tsf-input-not-saved';n=['.tsf-metaboxes :input','#tsf-inpost-box .inside :input'].join(', '),jQuery(n).not(a).off('change.tsfChangeListener').on('change.tsfChangeListener',{_input:n,_except:a},s),jQuery(document).off('tsf-gutenberg-saved-document.tsfChangeListener').on('tsf-gutenberg-saved-document.tsfChangeListener',function(){tsf.settingsChanged=!1}),n=['.tsf-metaboxes input[type=text]','.tsf-metaboxes textarea','#tsf-inpost-box .inside input[type=text]','#tsf-inpost-box .inside textarea'].join(', '),jQuery(n).not(a).off('input.tsfChangeListener').on('input.tsfChangeListener',{_input:n,_except:a},s),jQuery(window).off('beforeunload.tsfChangeListener').on('beforeunload.tsfChangeListener',function(){if(tsf.settingsChanged)return tsf.i18n.saveAlert}),jQuery(['.tsf-metaboxes input[type="submit"]','#publishing-action input[type="submit"]','#save-action input[type="submit"]','a.submitdelete'].join(', ')).off('click.tsfChangeListener').on('click.tsfChangeListener',function(){tsf.settingsChanged=!1})}},registerChange:function(){tsf.settingsChanged=!0},confirmedReset:function(){return confirm(tsf.i18n.confirmReset)},onLoadUnregisterChange:function(){tsf.settingsChanged=!1},dismissNotice:function(t){jQuery(t.target).parents('.tsf-notice').slideUp(200,function(){this.remove()})},setAjaxLoader:function(t){jQuery(t).toggleClass('tsf-loading')},unsetAjaxLoader:function(t,s){let n='tsf-success',a=2500;s||(n='tsf-error',a=5e3),jQuery(t).removeClass('tsf-loading').addClass(n).fadeOut(a)},resetAjaxLoader:function(t){jQuery(t).stop().empty().prop('class','tsf-ajax').css('opacity','1').removeProp('style')},setColorOnload:function(){let t=jQuery('.tsf-color-picker');t.length&&jQuery.each(t,function(s,n){let a=jQuery(n),o='',r=a.data('tsf-default-color');a.wpColorPicker({defaultColor:r,width:238,change:function(){o=a.wpColorPicker('color'),''==o&&(o=r),a.val(o),tsf.registerChange()},clear:function(){a.parent().siblings('.wp-color-result').css('backgroundColor',r),tsf.registerChange()},palettes:!1})})},_doFlexResizeListener:function(){if(jQuery('.tsf-flex').length){tsf._setResizeListeners();let t=0,s={},n=0,a=jQuery('.tsf-flex-nav-tab-wrapper'),o=jQuery(window);o.on('tsf-flex-resize',function(){clearTimeout(t);let r=0;t=setTimeout(function(){if(a.length){let l=jQuery('.tsf-flex-nav-tab-inner'),c=a.width(),g=l.width(),d=jQuery('.tsf-flex-nav-name');s.tabWrapper||(s.tabWrapper={},s.tabWrapper.outer=0,s.tabWrapper.inner=0,s.tabWrapper.shown=1),!s.tabWrapper.shown&&s.tabWrapper.outer<c&&(d.fadeIn(250),setTimeout(function(){g=l.width()},r)),setTimeout(function(){g>c?(d.hide(),s.tabWrapper.shown=0):s.tabWrapper.outer<c&&(d.fadeIn(250),s.tabWrapper.shown=1)},2*r),setTimeout(function(){s.tabWrapper.outer=c,s.tabWrapper.inner=g},3*r)}},n),r=10,n=75}),o.trigger('tsf-flex-resize')}},_setResizeListeners:function(){jQuery(window).on('resize orientationchange',tsf._triggerResize),jQuery('#collapse-menu').click(tsf._triggerResize),jQuery('.columns-prefs :input[type=radio]').change(tsf._triggerResize),jQuery('.meta-box-sortables').on('sortupdate',tsf._triggerResize)},_triggerResize:function(){jQuery(window).trigger('tsf-flex-resize')},_triggerCounterUpdate:function(){jQuery(window).trigger('tsf-counter-updated')},_triggerReady:function(){jQuery(document.body).trigger('tsf-ready')},_triggerOnLoad:function(){jQuery(document.body).trigger('tsf-onload')},_doReady:function(){tsf._triggerOnLoad(),tsf._initCounters(),tsf._initTitleInputs(),tsf._initUnboundTitleSettings(),tsf._initSocialTitleInputs(),tsf._initDescInputs(),tsf._initSocialDescInputs(),tsf._initCanonicalInput(),tsf._initWebmastersInput(),tsf.setTabsOnload(),tsf._initPostboxToggle(),tsf.taglineToggleOnload(),tsf.setColorOnload(),tsf.attachUnsavedChangesListener(),tsf.onLoadUnregisterChange(),tsf._doFlexResizeListener(),tsf._triggerReady()},setupVars:function(){tsf.counterType=parseInt(tsf.states.counterType),tsf.hasInput=tsf.states.hasInput},ready:function(t){t('.updated, .error, .notice-error, .notice-warning').insertAfter('.tsf-top-wrap'),tsf.setupVars(),t('.tsf-js-confirm-reset').on('click',tsf.confirmedReset),t('.tsf-tabs-radio').on('change',tsf.tabToggle),t('.tsf-tab').on('click','.tsf-nav-tab',tsf.addNoFocusClass),t('.tsf-flex-nav-tab-radio').on('change',tsf.flexTabToggle),t('.tsf-flex-nav-tab').on('click','.tsf-flex-nav-tab-label',tsf.addNoFocusClass),t('.tsf-dismiss').on('click',tsf.dismissNotice),t(document.body).ready(tsf._doReady)}},jQuery(tsf.ready);
lib/js/tt.js CHANGED
@@ -9,7 +9,7 @@
9
 
10
  /**
11
  * The SEO Framework plugin
12
- * Copyright (C) 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
13
  *
14
  * This program is free software: you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License version 3 as published
@@ -290,6 +290,9 @@ window.tsfTT = function( $ ) {
290
 
291
  addBoundary( '#wpcontent' ); //! All pages, but Gutenberg destroys the boundaries..
292
  addBoundary( '#editor' ); //! Gutenberg
 
 
 
293
  }
294
 
295
  /**
@@ -345,7 +348,7 @@ window.tsfTT = function( $ ) {
345
  borderLeft = $textWrap.offset().left,
346
  borderRight = borderLeft + textWrapWidth,
347
  boundaryLeft = $boundary.offset().left - ( $boundary.prop( 'scrollLeft' ) || 0 ),
348
- boundaryRight = boundaryLeft + $boundary.outerWidth();
349
 
350
  let direction = 'left',
351
  horIndent = NaN;
@@ -482,7 +485,7 @@ window.tsfTT = function( $ ) {
482
  * @return {undefined}
483
  */
484
  load: function() {
485
- $( document.body ).on( 'tsf-onload', _initToolTips );
486
  }
487
  }, {
488
  /**
9
 
10
  /**
11
  * The SEO Framework plugin
12
+ * Copyright (C) 2019 Sybre Waaijer, CyberWire (https://cyberwire.nl/)
13
  *
14
  * This program is free software: you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License version 3 as published
290
 
291
  addBoundary( '#wpcontent' ); //! All pages, but Gutenberg destroys the boundaries..
292
  addBoundary( '#editor' ); //! Gutenberg
293
+ // if ( tsfL10n && tsf.states && tsf.states.isGutenbergPage ) {
294
+ // addBoundary( '.edit-post-layout__metaboxes' ); //! TSF's postbox container... ideally.
295
+ // }
296
  }
297
 
298
  /**
348
  borderLeft = $textWrap.offset().left,
349
  borderRight = borderLeft + textWrapWidth,
350
  boundaryLeft = $boundary.offset().left - ( $boundary.prop( 'scrollLeft' ) || 0 ),
351
+ boundaryRight = boundaryLeft + $boundary.width();
352
 
353
  let direction = 'left',
354
  horIndent = NaN;
485
  * @return {undefined}
486
  */
487
  load: function() {
488
+ $( document.body ).ready( _initToolTips );
489
  }
490
  }, {
491
  /**
lib/js/tt.min.js CHANGED
@@ -1 +1 @@
1
- 'use strict';window.tsfTT=function(a){const b=function(){let k=0,l=!1,m=!1;try{let z=Object.defineProperty({},'passive',{get:function(){m=!0}});window.addEventListener('tsf-tt-test-passive',z,z).removeEventListener('tsf-tt-test-passive',z,z)}catch(z){}const n=function(){l=!0,clearTimeout(k),k=setTimeout(function(){l=!1},250)},o=function(z,A){A=A||!1;let B='pointerdown.tsfTT touchstart.tsfTT click.tsfTT',C=a(z);A?(C.off('mousemove.tsfTT mouseleave.tsfTT mouseout.tsfTT'),a(document.body).off(B)):(C.on({'mousemove.tsfTT':t,'mouseleave.tsfTT':u,'mouseout.tsfTT':u}),a(document.body).off(B).on(B,v)),C.off('tsf-tooltip-update').on('tsf-tooltip-update',q)},p=function(z){o(z,!0)},q=function(z){if(z.target.classList.contains('tsf-tooltip-item')){let A=z.target.querySelector('.tsf-tooltip-text');A instanceof Element&&(A.innerHTML=z.target.dataset.desc,a(z.target).trigger('mousemove.tsfTT'))}},r=function(z){let A=z.target.dataset.desc||z.target.title||'';A&&0===z.target.getElementsByClassName('tsf-tooltip').length&&(z.target.dataset.desc=A,z.target.title='',c(z,z.target,A))};let s=NaN;const t=function(z){let A=a(z.target),B=A.find('.tsf-tooltip'),C=B.find('.tsf-tooltip-arrow'),D=z.originalEvent&&z.originalEvent.pageX||z.pageX,E=7,F=16;D=isNaN(D)?s:D,s=D;let G=A.closest('.tsf-tooltip-wrap');G.length||(G=$hoverItem.parent());let H=D-G.offset().left-F/2,I=B.find('.tsf-tooltip-text-wrap'),J=I.outerWidth(!0),K=B.data('adjust'),L=J-F-E;if(K=parseInt(K,10),K=isNaN(K)?0:Math.round(K),K&&(H-=K,L+K>G.outerWidth(!0))){let M=I.find('.tsf-tooltip-text'),N=M.outerWidth(!0);L=N-F-E}H<=E?C.css('left',E+'px'):H>=L?C.css('left',L+'px'):C.css('left',H+'px')},u=function(z){l||(f(z.target),p(z.target))},v=function(z){n();let D,B='.tsf-tooltip',C=a(z.target);if(C.hasClass('tsf-tooltip-item')&&(D=C.find(B)),!D){let E=C.children('.tsf-tooltip-item');E.length&&(D=E.find(B))}D&&D.length?a(B).not(D).remove():a(B).remove()},w=function(z){if(!l){let A=!1;switch(z.type){case'mouseenter':break;case'pointerdown':case'touchstart':A=!0;break;default:}A&&v(z),r(z),t(z),o(z.target)}},x=function(z){z.target.classList.contains('tsf-tooltip-item')&&w(z),z.stopPropagation()},y=function(){let z=document.querySelectorAll('.tsf-tooltip-wrap'),A=!m||{capture:!0,passive:!0};for(let B=0;B<z.length;B++)'mouseenter pointerdown touchstart'.split(' ').forEach(function(C){z[B].removeEventListener(C,x,A),z[B].addEventListener(C,x,A)})};y(),a(window).on('tsf-tooltip-reset',y),d('#wpcontent'),d('#editor')},c=function(k,l,m){let n=a(l);if(n.find('.tsf-tooltip').length&&f(l),!!m.length){let o=a('<div class="tsf-tooltip"><span class="tsf-tooltip-text-wrap"><span class="tsf-tooltip-text">'+m+'</span></span><div class="tsf-tooltip-arrow"></div></div>');n.append(o);let p=n.closest('.tsf-tooltip-boundary');p=p.length&&p||a(document.body);let q=n.outerHeight()+8,r=o.offset().top-q,s=p.offset().top-(p.prop('scrolltop')||0);s>r?(o.addClass('tsf-tooltip-down'),o.css('top',q+'px')):o.css('bottom',q+'px');let t=n.closest('.tsf-tooltip-wrap');t.length||(t=n.parent());let u=o.find('.tsf-tooltip-text-wrap'),v=u.find('.tsf-tooltip-text'),w=t.width(),x=u.outerWidth(!0),y=v.outerWidth(!0),z=u.offset().left,B=p.offset().left-(p.prop('scrollLeft')||0),C=B+p.outerWidth(),D='left',E=NaN;if(z<B)E=B-z+12;else if(z+x>C)E=C-z-x-12;else if(42>w)E=2*-w+w/2,-E>x&&(E=-15);else if(k&&1>a(k.target).find(o).length)E=0;else if(k&&w>x){let F=k.originalEvent&&k.originalEvent.pageX||k.pageX,G=t.offset().left,I=F-G-x/2;E=I,0>I?E=0:I+x>w&&(E=w-y)}if(!isNaN(E)){let F=parseInt(u.css('flex-basis'),10);E<-F&&(E=-F),o.css(D,E+'px'),o.data('adjust',E),o.data('adjustDir',D)}}},d=function(k){a(k).addClass('tsf-tooltip-boundary')},f=function(k){g(k).remove()},g=function(k){return a(k).find('.tsf-tooltip').first()};return a.extend({load:function(){a(document.body).on('tsf-onload',b)}},{doTooltip:c,removeTooltip:f,getTooltip:g,addBoundary:d,triggerReset:function(){a(window).trigger('tsf-tooltip-reset')},triggerUpdate:function(k){a(k||'.tsf-tooltip-item').trigger('tsf-tooltip-update')}})}(jQuery),jQuery(window.tsfTT.load);
1
+ 'use strict';window.tsfTT=function(a){const b=()=>{let k=0,l=!1,m=!1;try{let z=Object.defineProperty({},'passive',{get:()=>{m=!0}});window.addEventListener('tsf-tt-test-passive',z,z).removeEventListener('tsf-tt-test-passive',z,z)}catch(z){}const n=()=>{l=!0,clearTimeout(k),k=setTimeout(()=>{l=!1},250)},o=(z,A)=>{A=A||!1;let B='pointerdown.tsfTT touchstart.tsfTT click.tsfTT',C=a(z);A?(C.off('mousemove.tsfTT mouseleave.tsfTT mouseout.tsfTT'),a(document.body).off(B)):(C.on({'mousemove.tsfTT':t,'mouseleave.tsfTT':u,'mouseout.tsfTT':u}),a(document.body).off(B).on(B,v)),C.off('tsf-tooltip-update').on('tsf-tooltip-update',q)},p=z=>{o(z,!0)},q=z=>{if(z.target.classList.contains('tsf-tooltip-item')){let A=z.target.querySelector('.tsf-tooltip-text');A instanceof Element&&(A.innerHTML=z.target.dataset.desc,a(z.target).trigger('mousemove.tsfTT'))}},r=z=>{let A=z.target.dataset.desc||z.target.title||'';A&&0===z.target.getElementsByClassName('tsf-tooltip').length&&(z.target.dataset.desc=A,z.target.title='',c(z,z.target,A))};let s=NaN;const t=z=>{let A=a(z.target),B=A.find('.tsf-tooltip'),C=B.find('.tsf-tooltip-arrow'),D=z.originalEvent&&z.originalEvent.pageX||z.pageX,E=7,F=16;D=isNaN(D)?s:D,s=D;let G=A.closest('.tsf-tooltip-wrap');G.length||(G=$hoverItem.parent());let H=D-G.offset().left-F/2,I=B.find('.tsf-tooltip-text-wrap'),J=I.outerWidth(!0),K=B.data('adjust'),L=J-F-E;if(K=parseInt(K,10),K=isNaN(K)?0:Math.round(K),K&&(H-=K,L+K>G.outerWidth(!0))){let M=I.find('.tsf-tooltip-text'),N=M.outerWidth(!0);L=N-F-E}H<=E?C.css('left',E+'px'):H>=L?C.css('left',L+'px'):C.css('left',H+'px')},u=z=>{l||(f(z.target),p(z.target))},v=z=>{n();let D,B='.tsf-tooltip',C=a(z.target);if(C.hasClass('tsf-tooltip-item')&&(D=C.find(B)),!D){let E=C.children('.tsf-tooltip-item');E.length&&(D=E.find(B))}D&&D.length?a(B).not(D).remove():a(B).remove()},w=z=>{if(!l){let A=!1;switch(z.type){case'mouseenter':break;case'pointerdown':case'touchstart':A=!0;break;default:}A&&v(z),r(z),t(z),o(z.target)}},x=z=>{z.target.classList.contains('tsf-tooltip-item')&&w(z),z.stopPropagation()},y=()=>{let z=document.querySelectorAll('.tsf-tooltip-wrap'),A=!m||{capture:!0,passive:!0};for(let B=0;B<z.length;B++)'mouseenter pointerdown touchstart'.split(' ').forEach(C=>{z[B].removeEventListener(C,x,A),z[B].addEventListener(C,x,A)})};y(),a(window).on('tsf-tooltip-reset',y),d('#wpcontent'),d('#editor')},c=(k,l,m)=>{let n=a(l);if(n.find('.tsf-tooltip').length&&f(l),!!m.length){let o=a('<div class="tsf-tooltip"><span class="tsf-tooltip-text-wrap"><span class="tsf-tooltip-text">'+m+'</span></span><div class="tsf-tooltip-arrow"></div></div>');n.append(o);let p=n.closest('.tsf-tooltip-boundary');p=p.length&&p||a(document.body);let q=n.outerHeight()+8,r=o.offset().top-q,s=p.offset().top-(p.prop('scrolltop')||0);s>r?(o.addClass('tsf-tooltip-down'),o.css('top',q+'px')):o.css('bottom',q+'px');let t=n.closest('.tsf-tooltip-wrap');t.length||(t=n.parent());let u=o.find('.tsf-tooltip-text-wrap'),v=u.find('.tsf-tooltip-text'),w=t.width(),x=u.outerWidth(!0),y=v.outerWidth(!0),z=u.offset().left,B=p.offset().left-(p.prop('scrollLeft')||0),C=B+p.width(),D='left',E=NaN;if(z<B)E=B-z+12;else if(z+x>C)E=C-z-x-12;else if(42>w)E=2*-w+w/2,-E>x&&(E=-15);else if(k&&1>a(k.target).find(o).length)E=0;else if(k&&w>x){let F=k.originalEvent&&k.originalEvent.pageX||k.pageX,G=t.offset().left,I=F-G-x/2;E=I,0>I?E=0:I+x>w&&(E=w-y)}if(!isNaN(E)){let F=parseInt(u.css('flex-basis'),10);E<-F&&(E=-F),o.css(D,E+'px'),o.data('adjust',E),o.data('adjustDir',D)}}},d=k=>{a(k).addClass('tsf-tooltip-boundary')},f=k=>{g(k).remove()},g=k=>{return a(k).find('.tsf-tooltip').first()};return a.extend({load:function(){a(document.body).ready(b)}},{doTooltip:c,removeTooltip:f,getTooltip:g,addBoundary:d,triggerReset:()=>{a(window).trigger('tsf-tooltip-reset')},triggerUpdate:k=>{a(k||'.tsf-tooltip-item').trigger('tsf-tooltip-update')}})}(jQuery),jQuery(window.tsfTT.load);
readme.txt CHANGED
@@ -3,74 +3,89 @@ Contributors: Cybr
3
  Donate link: https://theseoframework.com/donate/
4
  Tags: SEO, XML Sitemap, Google, Open Graph, Schema.org, Twitter
5
  Requires at least: 4.6.0
6
- Tested up to: 4.9.6
7
  Requires PHP: 5.4.0
8
- Stable tag: 3.1.4
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11
 
12
  The SEO Framework plugin provides an automated and advanced SEO solution for your WordPress website.
13
 
14
  == Description ==
15
- **Easy SEO for beginners, an awesome API for experts. WordPress SEO for everyone.**
16
 
17
- The SEO Framework provides an automated, accessible, unbranded, and a lightning-fast SEO solution for your WordPress website.
18
 
19
- Rediscover how SEO plugins should work: *No ads. No distractions. No nonsense.*
 
 
 
 
20
 
21
  = This plugin: =
22
 
23
- * Improves search presence by ranking your website distinctively.
24
- * Is preconfigured, providing a suitable starting point for most websites.
25
- * Provides an AI that listens to all WordPress gives to automatically optimize your pages.
26
- * Outputs Structured Data that helps search engines learn more about your pages.
27
- * Helps you optimize your metadata.
28
- * Points search engine crawlers in the right direction, preventing duplicated content issues.
29
- * Allows you to adjust SEO through global options.
30
- * Allows you to optimize every public page, post, and term.
31
- * Shows you how to improve SEO with a beautiful SEO bar and pixel counters.
32
- * Helps your pages get shared more beautiful through Facebook, Twitter, and other social sites.
33
- * Supports all custom post types, like from WooCommerce and bbPress.
34
- * [Respects your privacy](https://theseoframework.com/privacy-policy/#pluginprivacyinformation), truly, unlike others.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  = Getting started =
37
 
38
- * Used another plugin? Easily [migrate your SEO Data](https://theseoframework.com/docs/seo-data-migration/).
39
- * Lost in the sea of settings? Don't worry! Read our [quick setup guide](https://theseoframework.com/docs/seo-plugin-setup/).
 
40
 
41
  = Do more with extensions =
42
- For more advanced SEO tools and output, check out our free companion plugin [Extension Manager](https://wordpress.org/plugins/the-seo-framework-extension-manager/).
43
- Many extensions are included, among others are:
44
 
45
- * **[Focus](https://theseoframework.com/extensions/focus/)** helps you write targeted content with **focus keywords**, their inflections, and their synonyms. A great addition for bloggers and businesses alike.
46
- * **[Local](https://theseoframework.com/extensions/local/)** helps you set up local SEO business information. This could expand your business' "Knowledge Graph" card for local search listings.
47
- * **[Title Fix](https://theseoframework.com/extensions/title-fix/)** fixes incorrect titles that are rendered by outdated themes.
48
 
49
  Visit our [Extensions overview page](https://theseoframework.com/extensions/) for more information.
50
 
51
  = Unbranded, Free and for the Professional =
52
- This plugin is unbranded! This means that we don't even put the name "The SEO Framework" anywhere within the WordPress interface, aside from the plugin activation page. This plugin makes great use of the default WordPress interface elements, like as if this plugin is part of WordPress. No ads, no nags. The small and hidden HTML comments can easily be disabled with the use of a filter or extension.
53
 
54
  Nobody has to know about the tools you've used to create your or someone else's website. A clean interface, for everyone.
55
 
56
- = Completely automated =
57
- **By default, this plugin automatically generates:**
58
-
59
- * Titles according to Google's best practices.
60
- * Descriptions with anti-spam techniques and detection that informs you when it can be improved.
61
- * A canonical URL to prevent duplicated content; with full "domain mapping", subdomain, and HTTPS support.
62
- * Various Open Graph, Facebook and Twitter tags.
63
- * Special Open Graph descriptions, which organically integrates within the Facebook and Twitter snippets.
64
- * Open Graph images, they are automatically resized and optimized when needed.
65
- * Structured Data for Google Search and supported browsers that add extended on-site search support.
66
- * Structured Data for Google's Knowledge Graph; like Personal/Business site relations, names, and logos.
67
- * Structured Data for Breadcrumbs that extend pages and categories relationship support in Google Search.
68
- * Publishing and editing dates for social sites and search engines alike.
69
- * Paginated content relationship links, to help visitors going to the right page.
70
- * A sitemap with all your pages, posts and CPT, which listens to their page settings.
71
- * Feed excerpts and backlinks within, to reduce automated content theft.
72
-
73
- **This plugin goes further, behind the screens it:**
74
 
75
  * Prevents canonical errors with categories, pages, subdomains, and Multisite domain mapping.
76
  * Stops SEO attacks that are caused by pagination exploits in WordPress.
@@ -78,9 +93,9 @@ Nobody has to know about the tools you've used to create your or someone else's
78
  * Automatically notifies Google, Bing, and Yandex on website updates when sitemaps are enabled.
79
 
80
  = Generously personal =
81
- **This plugin allows you to manually set various values for each post, page, public CPT, and term.**
82
 
83
- **This plugin allows you to adjust over 100 site settings, including:**
84
 
85
  * Automated title output options; they encourage you to follow the guidelines.
86
  * Automated description output options.
@@ -96,24 +111,24 @@ Nobody has to know about the tools you've used to create your or someone else's
96
 
97
  = Openly pluggable =
98
  The SEO Framework has been built to go further than just itself.
99
- Take a look at the API documentation located at [The SEO Framework API Docs](http://theseoframework.com/docs/api/).
100
 
101
  = The SEO Bar =
102
- **This plugin helps you to create better content, at a glance. By showing you:**
103
 
104
  * If the title is too long, too short, duplicated, and/or automatically generated.
105
- * If the description is too long, too short, duplicated, has too many repeated words and/or automatically generated.
106
  * If the page is indexed, redirected, followed and/or archived, while looking at other WordPress settings.
107
 
108
  We call this the SEO Bar. Check out the screenshots below to see how it helps you!
109
 
110
  = Hardcore caching =
111
- This plugin's code is highly optimized on PHP-level and uses variable, object and transient caching. This means that there's little extra page load time from this plugin, even with more meta tags used.
112
 
113
  A caching plugin isn't even needed for this plugin as you won't notice a difference; however, it's supported wherever best suited.
114
 
115
  = Compatibility =
116
- **This plugin supports:**
117
 
118
  * PHP 5.4 and greater.
119
  * WordPress 4.6 and greater.
@@ -124,15 +139,15 @@ A caching plugin isn't even needed for this plugin as you won't notice a differe
124
  * Screen reader accessibility and keyboard navigation.
125
  * Multisite setups, this plugin is in fact built upon one.
126
  * Detection of robots.txt and sitemap.xml files.
127
- * Both up-to-date and outdated themes.
128
- * Detection of various other popular SEO tools to help you prevent duplicated output.
129
  * Translation plugins like WPML, Polylang, WPGlobus, and MultilingualPress.
130
  * WooCommerce, for free, in all its glory.
131
 
132
  = An additional sitemap =
133
- The sitemap generated with The SEO Framework is more than sufficient for search engines to find posts, pages and supported custom post types throughout your website. It also listens to the "noindex" settings on each of the items and works great with various translation plugins.
134
 
135
- Via Structured Data, like what's brought with the [Articles extension](https://theseoframework.com/extensions/articles/), advanced sitemaps are no longer needed.
136
 
137
  However, if you require a more expanded sitemap, feel free to activate a dedicated Sitemap plugin. The SEO Framework will automatically deactivate its Sitemap functionality when another (known) sitemap plugin is found.
138
 
@@ -148,7 +163,7 @@ The Breadcrumb script generated by this plugin on Posts will also make sure Goog
148
 
149
  = Installation instructions: =
150
 
151
- 1. Install "The SEO Framework" either via the WordPress.org plugin directory or by uploading the files to your server.
152
  1. Either Network Activate this plugin or activate it on a single site.
153
  1. That's it!
154
 
@@ -162,11 +177,11 @@ You should read up on our [plugin setup guide](https://theseoframework.com/docs/
162
 
163
  = Get more SEO power =
164
 
165
- * Optionally, also install the [Extension Manager](https://wordpress.org/plugins/the-seo-framework-extension-manager/) for additional SEO solutions.
166
 
167
  == Screenshots ==
168
 
169
- 1. This plugin shows you what you can improve, at a glance. With complete color vision deficiency support.
170
  2. Hover over any of the SEO Bar's items to see how you can improve the page's SEO. Red requires attention, orange is okay, green is good. Blue is informational.
171
  3. The dynamic Post/Page SEO settings meta box. Another version of this box is also implemented for terms, like categories and tags.
172
  4. The dynamic Post/Page SEO settings meta box also fits neatly in the sidebar. For when you want to work faster.
@@ -181,7 +196,7 @@ This plugin is all-inclusive without upsells.
181
 
182
  = Is there more? =
183
 
184
- For more advanced SEO options and output, we offer the free plugin [Extension Manager](https://wordpress.org/plugins/the-seo-framework-extension-manager/).
185
 
186
  = I have a feature request, I've found a bug, a plugin is incompatible... =
187
 
@@ -190,10 +205,10 @@ We'll try to get back to you within 72 hours. :)
190
 
191
  = I am a developer; how can I help? =
192
 
193
- Any input is greatly appreciated, and everything will be considered.
194
  Please visit the [GitHub project page](https://github.com/sybrew/the-seo-framework) to submit issues or even pull requests.
195
 
196
- = I want to modify how this plugin works. =
197
 
198
  The SEO Framework is extensible. Please refer to the [API documentation](https://theseoframework.com/docs/api/).
199
 
@@ -202,7 +217,7 @@ The SEO Framework is extensible. Please refer to the [API documentation](https:/
202
  This is not an issue. Search engines love crawling WordPress because its structure is consistent and well known.
203
  If a visitor can't find a page, then why would a search engine? Don't rely on your sitemap, but on your content and website's usability.
204
 
205
- Check out our [Extension Manager](https://wordpress.org/plugins/the-seo-framework-extension-manager/).
206
  It brings extensions, like Articles, that fill in the gaps with newer and better techniques.
207
 
208
  = The sitemap contains unwanted links. =
@@ -212,85 +227,53 @@ The SEO Framework takes all publicly queryable posts, pages, and CPT and puts th
212
  If you don't want a page in the sitemap, consider enabling the `noindex` option. This will also remove the page from search engine result pages.
213
 
214
  If the link shouldn't be in the sitemap because it's meant for structural reasons, then inform the plugin or theme author that created them.
215
- You should tell the author to check out the "`public` and `rewrite` post type arguments". The plugin or theme author should know what that means.
216
 
217
- = What's do the application/ld+json scripts do? =
218
 
219
  The JSON-LD scripts are search engine helpers which tell search engines how to connect and index the site.
220
  They can tell the search engine if your site contains an internal search engine, what sites you're socially connected to and what page structure you're using.
221
- This is also referred to as "Structured Data".
222
 
223
  = The metadata is not being updated, and I'm using a caching plugin. =
224
 
225
- All The SEO Framework's metadata is put into Object cache when a caching plugin is available.
226
  Please be sure to clear your cache or adjust the plugin's caching settings if deemed necessary.
227
 
228
  == Changelog ==
229
 
230
- = 3.1.4 =
231
-
232
- This update brings improved compatibility with WooCommerce, adds a few filters, and fixes [various logic issues](https://theseoframework.com/?p=2709).
233
 
234
- = 3.1.3 =
235
 
236
- This update fixes incorrect logic in the homepage title additions brought in v3.1.2. Your site may be affected and we urge you to update.
237
 
238
- Follow our guide on [how to resolve this without affecting ranking](https://theseoframework.com/?p=2654) directly after updating. Our apologies for the inconvenience!
239
 
240
- = 3.1.2 =
241
 
242
- This minor update adds more robust term ID collision checks, adds a few missing API features, and introduces [other improvements](https://theseoframework.com/?p=2641).
243
-
244
- = 3.1.1 =
245
 
246
- This tiny update fixes [two issues with v3.1](https://theseoframework.com/?p=2598), our apologies for the inconvenience.
247
 
248
- = 3.1.0 - Pure =
249
-
250
- *"The difference between something good and something great is attention to detail." - Charles R. Swindoll[†](http://dannybeckettjr.com/2009/10/220079492/)*
251
 
252
  **Release date**
253
 
254
- * September 15th, 2018
255
-
256
- **Foreword**
257
-
258
- We've written a [foreword on v3.1](https://theseoframework.com/?p=2490), it tells the story behind of what we've done. You should read it, so you'll know what to expect from this update.
259
 
260
- **Feature highlights:**
261
 
262
- * We completely redesigned the meta-titles generation, they support 114+ languages out of the box, and we’ve added new title adjustment features.
263
- * We've vastly improved the meta-description generation code, it now supports all languages, it leaves out junk, and it’s faster than ever before.
264
- * The SEO Bar is now more intelligent. It’s now aware of its WordPress, linguistic, and graphical environment, and it tells you more details.
265
- * The pixel counter is now the most accurate guideline in its field. Hover over it, and you’ll find it gives you more information.
266
- * Custom Post Type support is improved, and you can now easily manage various settings for them individually.
267
- * The plugin's interface is now fully accessible with added keyboard navigation.
268
- * ...and more than 700 other noteworthy changes, found in our [detailed log](https://theseoframework.com/?p=2562#detailed).
269
 
270
- **Upgrade notes:**
271
 
272
- * PHP 5.3 support has been dropped. Here's why:
273
- * PHP 5.3 hasn't received updates for [over 4 years](http://php.net/eol.php) and using it yields a major security risk.
274
- * Using PHP 5.4 lowers our time spent on maintenance, and it increases our productivity; so, we can focus on faster, better, and more useful solutions.
275
- * Learn more about [Upgrading PHP](https://wordpress.org/support/upgrade-php/).
276
- * WordPress 4.4 and 4.5 support has been dropped. Here's why:
277
- * Although WordPress still brings security updates for versions as low as 3.7, [most users](https://wordpress.org/about/stats/) have upgraded to a newer version.
278
- * WordPress brings a slightly different yet vastly better developer environment with each major release. Supporting these will not only lower our maintenance and support time, but it also brings you a better experience.
279
- * Learn more about [Upgrading WordPress](https://codex.wordpress.org/Upgrading_WordPress).
280
 
281
- *If, for whatever reason, you still wish to use PHP 5.3 and/or WordPress 4.4/4.5, [The SEO Framework 3.0.6](https://downloads.wordpress.org/plugin/autodescription.3.0.6.zip) still supports them.*
282
 
283
- **New and simplified API documentation**
284
-
285
- After two years, we've finally updated our [API docs](https://theseoframework.com/docs/api/), go check it out.
286
-
287
- **Like what you see?**
288
-
289
- Consider giving us [an awesome review](https://wordpress.org/support/plugin/autodescription/reviews/#new-topic-0)!
290
-
291
- **Detailed log:**
292
-
293
- Fred Brooks' law: "What [one developer](https://theseoframework.com/?p=2562#detailed) can do in one month, two developers can do in two months."
294
 
295
  = Full changelog =
296
 
@@ -298,20 +281,14 @@ Fred Brooks' law: "What [one developer](https://theseoframework.com/?p=2562#deta
298
 
299
  == Upgrade Notice ==
300
 
301
- = 3.1.3 =
302
- This update fixes incorrect logic in the homepage title additions brought in 3.1.2. We urge you to update and [ask Google to recrawl your homepage](https://support.google.com/webmasters/answer/6065812?hl=en) URL directly after doing so. See https://theseoframework.com/?p=2654 for details.
303
-
304
  = 3.1.1 =
305
  This is a major upgrade. Make a backup of your database before upgrading. WordPress v4.6 (or greater) and PHP v5.4 (or greater) are now required. If you use the Extension Manager, update it to v1.5.2 (or greater) before upgrading this plugin. Downgrading to v3.0.6 possible.
306
 
307
  = 3.0.0 =
308
  A major update. Make a backup of your database before upgrading.
309
 
310
- = 2.9.3 =
311
- A highly recommended update that fixes "Home Page as Blog" query issues.
312
-
313
  = 2.8.0 =
314
- In the 2.8.0 update WordPress 4.3 and PHP 5.2 support have been dropped for better code quality.
315
 
316
  = 2.7.0 =
317
  The 2.7.0 update is required for the upcoming Extension Manager plugin and includes many improvements.
3
  Donate link: https://theseoframework.com/donate/
4
  Tags: SEO, XML Sitemap, Google, Open Graph, Schema.org, Twitter
5
  Requires at least: 4.6.0
6
+ Tested up to: 5.0.4
7
  Requires PHP: 5.4.0
8
+ Stable tag: 3.2.2
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11
 
12
  The SEO Framework plugin provides an automated and advanced SEO solution for your WordPress website.
13
 
14
  == Description ==
 
15
 
16
+ **The complete SEO solution for your WordPress website.**
17
 
18
+ The SEO Framework is a reliable, accessible, unbranded, fully automated, and rigorously optimized SEO plugin for your website.
19
+
20
+ Without ads, distractions, and nonsensical functionality, this plugin delivers a time-saving SEO solution that truly helps your website rank.
21
+
22
+ [Migrate](https://theseoframework.com/?p=511) | [Setup](https://theseoframework.com/?p=2428) | [Improve](https://theseoframework.com/?p=2663) | [Extensions](https://theseoframework.com/extensions/) | [API](https://theseoframework.com/?p=82) | [Privacy](https://theseoframework.com/privacy-policy/#pluginprivacyinformation)
23
 
24
  = This plugin: =
25
 
26
+ * **Comes preconfigured**
27
+ The SEO Framework provides a suitable starting point for most websites via its AI. It also comes with over a hundred settings for you to tweak; learn how to manage this in our [Setup guide](https://theseoframework.com/?p=2428).
28
+
29
+ * **Is smarter than all others**
30
+ The SEO Framework has an AI built in that listens to all that WordPress gives to automatically optimize your pages. This saves you a lot of time and makes it very easy to use.
31
+
32
+ * **Has exceptional support**
33
+ We don't outsource our support. Instead, the developer of this plugin, with extensive knowledge of hosting, SEO, WordPress, theming, and plugin development is here for you. Over a thousand inquiries have been answered personally within 72 hours in the past four years.
34
+
35
+ * **Leaves no room for errors**
36
+ We focus on quality rather than selling you useless features. This means that this plugin performs faster, is more accurate, has fewer bugs, and is more sustainable than others. The added benefit is that your site is unlikely to get penalized by search engines.
37
+
38
+ * **Is cleaner than all others**
39
+ The SEO Framework is built for the small to large corporations and enterprises. The interface seamlessly integrates within WordPress, and interacting with it feels natural.
40
+
41
+ * **Improves search presence**
42
+ The SEO Framework ranks your website distinctively by enabling breadcrumbs for Google Search, and by automatically generating titles and descriptions according to Google's guidelines. It also notifies Google, Bing, Yandex, and all connected search networks automatically of your website's changes with its built-in sitemap.
43
+
44
+ * **Improves social sharing**
45
+ The SEO Framework automatically supports the Open Graph and Twitter Cards protocols, this helps your posts stand out when shared on various social networks.
46
+
47
+ * **Helps you optimize your metadata**
48
+ The SEO Framework is the only plugin that literally has pixel-perfect guidelines for Google Search. It took years of research to get this right, and this means you can manually optimize your pages without making critical mistakes.
49
+
50
+ * **Creates a beautiful overview**
51
+ On your post overview pages, you'll find color-coded guidelines. They tell you how to improve when hovering over it with your mouse.
52
+
53
+ * **Is completely accessible**
54
+ We handpicked our color scheme so that people with any type of color-vision deficiency can distinguish these. Full keyboard-navigation support is also implemented.
55
+
56
+ * **Is always doing it right**
57
+ The SEO Framework steers you from making significant and common SEO mistakes. It also leaves little room for you to mess up because the plugin already does everything for you. It also automatically prevents duplicated content mistakes by enforcing strict canonical URL rules, which is something many other plugins don't do.
58
+
59
+ * **Follows best-practices and beyond**
60
+ We built the plugin according to all WordPress coding guidelines. This means it neatly integrates with everything else made according to it, like bbPress and WooCommerce. This also means that the plugin is secure (there's no record of exploits) and extensible.
61
+
62
+ * **Is built with developers in mind**
63
+ We encourage other developers to add functionality to this plugin. We've done so ourselves, already, with our [extensions](https://theseoframework.com/extensions/). Feel free to join in on our efforts!
64
+
65
+ * **Respects your privacy**
66
+ Unlike others, this plugin has no links that cloak your information, and it doesn't automatically share your email address with third parties. Learn more from our strictly adhered-to [privacy policy](https://theseoframework.com/privacy-policy/#pluginprivacyinformation).
67
 
68
  = Getting started =
69
 
70
+ * Used another plugin? Easily [migrate your SEO Data](https://theseoframework.com/?p=511).
71
+ * Lost in the sea of settings? Don't worry! Read our [quick setup guide](https://theseoframework.com/?p=2428).
72
+ * Want to improve your pages? Learn how to [optimize your metadata](https://theseoframework.com/?p=2663).
73
 
74
  = Do more with extensions =
75
+ For more advanced SEO tools and output, check out our free companion plugin [Extension Manager](https://theseoframework.com/?p=2760). Many Premium, Essentials, and Free extensions are included, among others are:
 
76
 
77
+ * **[Focus](https://theseoframework.com/?p=2305)** helps you write targeted content with **focus keywords**, their inflections, and their synonyms. It is an indispensable addition for bloggers and businesses alike.
78
+ * **[Local](https://theseoframework.com/?p=2306)** helps you set up local SEO business information. This could expand your business' "Knowledge Graph" card for local search listings.
79
+ * **[Title Fix](https://theseoframework.com/?p=2298)** fixes incorrect titles that are rendered by old themes.
80
 
81
  Visit our [Extensions overview page](https://theseoframework.com/extensions/) for more information.
82
 
83
  = Unbranded, Free and for the Professional =
84
+ The SEO Framework is unbranded! This means that we don't even put the name "The SEO Framework" anywhere within the WordPress interface, aside from the plugin activation page. This plugin makes excellent use of the default WordPress interface elements, like as if this plugin is part of WordPress. No ads, no nags. The small and hidden HTML comments can easily be disabled with the use of a filter or extension.
85
 
86
  Nobody has to know about the tools you've used to create your or someone else's website. A clean interface, for everyone.
87
 
88
+ **The SEO Framework goes further, behind the screens it:**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  * Prevents canonical errors with categories, pages, subdomains, and Multisite domain mapping.
91
  * Stops SEO attacks that are caused by pagination exploits in WordPress.
93
  * Automatically notifies Google, Bing, and Yandex on website updates when sitemaps are enabled.
94
 
95
  = Generously personal =
96
+ **The SEO Framework allows you to manually set various values for each post, page, public CPT, and term.**
97
 
98
+ **And, this plugin allows you to adjust over 100 site settings, including:**
99
 
100
  * Automated title output options; they encourage you to follow the guidelines.
101
  * Automated description output options.
111
 
112
  = Openly pluggable =
113
  The SEO Framework has been built to go further than just itself.
114
+ Take a look at the API documentation located at [The SEO Framework API Docs](https://theseoframework.com/?p=82).
115
 
116
  = The SEO Bar =
117
+ **The SEO Framework helps you to create better content, at a glance. By showing you:**
118
 
119
  * If the title is too long, too short, duplicated, and/or automatically generated.
120
+ * If the description is too long, too short, has too many repeated words and/or automatically generated.
121
  * If the page is indexed, redirected, followed and/or archived, while looking at other WordPress settings.
122
 
123
  We call this the SEO Bar. Check out the screenshots below to see how it helps you!
124
 
125
  = Hardcore caching =
126
+ The code in The SEO Framework is highly optimized on PHP-level and uses variable, object and transient caching. This means that there's little extra page load time from this plugin, even with more meta tags used.
127
 
128
  A caching plugin isn't even needed for this plugin as you won't notice a difference; however, it's supported wherever best suited.
129
 
130
  = Compatibility =
131
+ **The SEO Framework supports:**
132
 
133
  * PHP 5.4 and greater.
134
  * WordPress 4.6 and greater.
139
  * Screen reader accessibility and keyboard navigation.
140
  * Multisite setups, this plugin is in fact built upon one.
141
  * Detection of robots.txt and sitemap.xml files.
142
+ * Both current and old themes.
143
+ * Detection of various other SEO tools to help you switch graciously.
144
  * Translation plugins like WPML, Polylang, WPGlobus, and MultilingualPress.
145
  * WooCommerce, for free, in all its glory.
146
 
147
  = An additional sitemap =
148
+ The sitemap generated with The SEO Framework is more than sufficient for search engines to find posts, pages and supported custom post types throughout your website. It also listens to the `noindex` settings on each of the items and works great with various translation plugins.
149
 
150
+ Via structured data, like what's brought with the [Articles extension](https://theseoframework.com/extensions/articles/), advanced sitemaps are no longer needed.
151
 
152
  However, if you require a more expanded sitemap, feel free to activate a dedicated Sitemap plugin. The SEO Framework will automatically deactivate its Sitemap functionality when another (known) sitemap plugin is found.
153
 
163
 
164
  = Installation instructions: =
165
 
166
+ 1. Install **The SEO Framework** either via the WordPress.org plugin directory or by uploading the files to your server.
167
  1. Either Network Activate this plugin or activate it on a single site.
168
  1. That's it!
169
 
177
 
178
  = Get more SEO power =
179
 
180
+ * Optionally, also install the [Extension Manager](https://theseoframework.com/?p=2760) for additional SEO solutions.
181
 
182
  == Screenshots ==
183
 
184
+ 1. The SEO Framework shows you what you can improve, at a glance. With complete color vision deficiency support.
185
  2. Hover over any of the SEO Bar's items to see how you can improve the page's SEO. Red requires attention, orange is okay, green is good. Blue is informational.
186
  3. The dynamic Post/Page SEO settings meta box. Another version of this box is also implemented for terms, like categories and tags.
187
  4. The dynamic Post/Page SEO settings meta box also fits neatly in the sidebar. For when you want to work faster.
196
 
197
  = Is there more? =
198
 
199
+ For more advanced SEO options and output, we offer the free plugin [Extension Manager](https://theseoframework.com/?p=2760).
200
 
201
  = I have a feature request, I've found a bug, a plugin is incompatible... =
202
 
205
 
206
  = I am a developer; how can I help? =
207
 
208
+ Any input is much appreciated, and everything will be considered.
209
  Please visit the [GitHub project page](https://github.com/sybrew/the-seo-framework) to submit issues or even pull requests.
210
 
211
+ = I want to modify how The SEO Framework works. =
212
 
213
  The SEO Framework is extensible. Please refer to the [API documentation](https://theseoframework.com/docs/api/).
214
 
217
  This is not an issue. Search engines love crawling WordPress because its structure is consistent and well known.
218
  If a visitor can't find a page, then why would a search engine? Don't rely on your sitemap, but on your content and website's usability.
219
 
220
+ Check out our [Extension Manager](https://theseoframework.com/?p=2760).
221
  It brings extensions, like Articles, that fill in the gaps with newer and better techniques.
222
 
223
  = The sitemap contains unwanted links. =
227
  If you don't want a page in the sitemap, consider enabling the `noindex` option. This will also remove the page from search engine result pages.
228
 
229
  If the link shouldn't be in the sitemap because it's meant for structural reasons, then inform the plugin or theme author that created them.
230
+ You should tell the author to check out the "`public` and `rewrite` post type arguments." The plugin or theme author should know what that means.
231
 
232
+ = What do the application/ld+json scripts do? =
233
 
234
  The JSON-LD scripts are search engine helpers which tell search engines how to connect and index the site.
235
  They can tell the search engine if your site contains an internal search engine, what sites you're socially connected to and what page structure you're using.
236
+ This is also referred to as **structured data**.
237
 
238
  = The metadata is not being updated, and I'm using a caching plugin. =
239
 
240
+ The SEO Framework's metadata is put into WordPress' object cache when a caching plugin is available.
241
  Please be sure to clear your cache or adjust the plugin's caching settings if deemed necessary.
242
 
243
  == Changelog ==
244
 
245
+ = 3.2.2 =
 
 
246
 
247
+ This minor update brings [major bug fixes](https://theseoframework.com/?p=3022). Most notoriously, the home page settings now predict the metadata perfectly in the admin screens. Bloggers will love this update, too, because Facebook and Twitter metadata for the home blog page is now always correct.
248
 
249
+ For developers, please note that the upcoming major release (3.3.0) will introduce new taxonomical settings. Because the image-rendering integration isn't suited for this, it'll be overhauled. For more information, see [this issue](https://github.com/sybrew/the-seo-framework/issues/403).
250
 
251
+ Also, for developers, note that some API changes better suited for a major release were also brought into this minor release; these were required to fix some bugs.
252
 
253
+ = 3.2.1 =
254
 
255
+ This minor update [fixes script load-order issues](https://theseoframework.com/?p=2982) which can occur when other plugins try to interact with the new WordPress editor.
 
 
256
 
257
+ = 3.2.0 - Horizon =
258
 
259
+ *What is right to be done cannot be done too soon. - Jane Austen*
 
 
260
 
261
  **Release date**
262
 
263
+ * December 4th, 2018
 
 
 
 
264
 
265
+ **Release highlights**
266
 
267
+ * A new editor (codename Gutenberg) will launch [in just two days](https://make.wordpress.org/core/2018/12/04/new-5-0-target-date/) with WordPress 5.0. This release makes the plugin fully compatible with it.
268
+ * Description prefixes have been removed. Descriptions aren't used a ranking factor anymore, and gaming the system by repeating the title isn't beneficial.
 
 
 
 
 
269
 
270
+ **Did you know?**
271
 
272
+ * We recently relaunched a plugin for The SEO Framework. [Learn more](https://theseoframework.com/?p=2760).
 
 
 
 
 
 
 
273
 
274
+ **Detailed log**
275
 
276
+ Happy Holidays! [(╯°□°)╯︵ ┻┻](https://theseoframework.com/?p=2957)
 
 
 
 
 
 
 
 
 
 
277
 
278
  = Full changelog =
279
 
281
 
282
  == Upgrade Notice ==
283
 
 
 
 
284
  = 3.1.1 =
285
  This is a major upgrade. Make a backup of your database before upgrading. WordPress v4.6 (or greater) and PHP v5.4 (or greater) are now required. If you use the Extension Manager, update it to v1.5.2 (or greater) before upgrading this plugin. Downgrading to v3.0.6 possible.
286
 
287
  = 3.0.0 =
288
  A major update. Make a backup of your database before upgrading.
289
 
 
 
 
290
  = 2.8.0 =
291
+ In the 2.8.0 update, WordPress 4.3 and PHP 5.2 support have been dropped for better code quality.
292
 
293
  = 2.7.0 =
294
  The 2.7.0 update is required for the upcoming Extension Manager plugin and includes many improvements.