The SEO Framework - Version 3.0.2

Version Description

  • Esteem =

Release date:

  • November 23rd, 2017

Fixed:

  • A fatal error no longer occurs on the wpForo Forum plugin pages.
Download this release

Release Info

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

Code changes from version 2.9.4 to 3.0.2

Files changed (80) hide show
  1. autodescription.php +8 -8
  2. inc/classes/admin-init.class.php +174 -74
  3. inc/classes/admin-pages.class.php +166 -103
  4. inc/classes/cache.class.php +104 -18
  5. inc/classes/compat.class.php +15 -22
  6. inc/classes/core.class.php +54 -17
  7. inc/classes/debug.class.php +22 -29
  8. inc/classes/deprecated.class.php +2012 -1290
  9. inc/classes/detect.class.php +8 -3
  10. inc/classes/doing-it-right.class.php +73 -61
  11. inc/classes/feed.class.php +184 -187
  12. inc/classes/generate-description.class.php +23 -13
  13. inc/classes/generate-image.class.php +17 -1
  14. inc/classes/generate-ldjson.class.php +214 -226
  15. inc/classes/generate-title.class.php +18 -12
  16. inc/classes/generate-url.class.php +467 -548
  17. inc/classes/generate.class.php +38 -35
  18. inc/classes/index.php +48 -0
  19. inc/classes/init.class.php +70 -66
  20. inc/classes/inpost.class.php +51 -108
  21. inc/classes/load.class.php +10 -18
  22. inc/classes/metaboxes.class.php +12 -0
  23. inc/classes/post-data.class.php +217 -25
  24. inc/classes/profile.class.php +138 -0
  25. inc/classes/query.class.php +49 -16
  26. inc/classes/render.class.php +151 -128
  27. inc/classes/sanitize.class.php +76 -34
  28. inc/classes/site-options.class.php +16 -129
  29. inc/classes/sitemaps.class.php +54 -50
  30. inc/classes/term-data.class.php +92 -33
  31. inc/classes/user-data.class.php +235 -0
  32. inc/compat/php-mbstring.php +11 -11
  33. inc/compat/plugin-bbpress.php +3 -12
  34. inc/compat/plugin-buddypress.php +22 -0
  35. inc/compat/plugin-donncha-dm.php +0 -69
  36. inc/compat/plugin-polylang.php +0 -187
  37. inc/compat/plugin-qtranslatex.php +0 -100
  38. inc/compat/plugin-wpforo.php +3 -23
  39. inc/compat/plugin-wpml.php +1 -183
  40. inc/compat/plugin-wpmudev-dm.php +0 -134
  41. inc/compat/theme-genesis.php +10 -25
  42. inc/compat/wp-460.php +58 -0
  43. inc/functions/optionsapi.php +1 -2
  44. inc/functions/plugin-activation.php +73 -0
  45. inc/functions/plugin-deactivation.php +71 -0
  46. inc/functions/plugin-test-server.php +1 -1
  47. inc/functions/upgrade.php +72 -8
  48. inc/views/admin/index.php +6 -0
  49. inc/views/admin/seo-settings-columns.php +35 -0
  50. inc/views/admin/seo-settings-wrap.php +48 -0
  51. inc/views/inpost/seo-settings-singular.php +34 -47
  52. inc/views/inpost/seo-settings-tt.php +69 -23
  53. inc/views/inpost/wrap.php +100 -0
  54. inc/views/metaboxes/description-metabox.php +15 -7
  55. inc/views/metaboxes/feed-metabox.php +2 -2
  56. inc/views/metaboxes/general-metabox.php +119 -14
  57. inc/views/metaboxes/homepage-metabox.php +40 -31
  58. inc/views/metaboxes/robots-metabox.php +56 -54
  59. inc/views/metaboxes/schema-metabox.php +90 -94
  60. inc/views/metaboxes/sitemaps-metabox.php +27 -67
  61. inc/views/metaboxes/social-metabox.php +66 -67
  62. inc/views/metaboxes/title-metabox.php +10 -8
  63. inc/views/metaboxes/webmaster-metabox.php +29 -9
  64. inc/views/profile/author.php +26 -0
  65. inc/views/profile/index.php +6 -0
  66. inc/views/templates/index.php +6 -0
  67. inc/views/templates/inpost/index.php +6 -0
  68. inc/views/templates/inpost/primary-term-selector.php +29 -0
  69. language/autodescription.pot +675 -607
  70. lib/css/tsf-rtl.css +360 -106
  71. lib/css/tsf-rtl.min.css +1 -1
  72. lib/css/tsf.css +358 -109
  73. lib/css/tsf.min.css +1 -1
  74. lib/js/{tsf.externs.js → externs/tsf.externs.js} +0 -0
  75. lib/js/{tsf.externs.protected.js → externs/tsf.externs.protected.js} +1 -1
  76. lib/js/tsf.js +2145 -1272
  77. lib/js/tsf.min.js +1 -38
  78. load.php +4 -96
  79. patch/index.php +0 -10
  80. readme.txt +101 -146
autodescription.php CHANGED
@@ -3,7 +3,7 @@
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: 2.9.4
7
  * Author: Sybre Waaijer
8
  * Author URI: https://theseoframework.com/
9
  * License: GPLv3
@@ -33,7 +33,7 @@ defined( 'ABSPATH' ) or die;
33
  //* Debug. Not to be used on production websites as it dumps and/or disables all kinds of stuff everywhere.
34
  // add_action( 'plugins_loaded', function() { if ( is_super_admin() ) {
35
  // if ( is_admin() ) {
36
- // define( 'THE_SEO_FRAMEWORK_DEBUG', true );
37
  // define( 'THE_SEO_FRAMEWORK_DEBUG_HIDDEN', true );
38
  // define( 'THE_SEO_FRAMEWORK_DISABLE_TRANSIENTS', true );
39
  // update_option( 'the_seo_framework_upgraded_db_version', '0' );
@@ -51,7 +51,7 @@ defined( 'ABSPATH' ) or die;
51
  *
52
  * @since 1.0.0
53
  */
54
- define( 'THE_SEO_FRAMEWORK_VERSION', '2.9.4' );
55
 
56
  /**
57
  * The plugin Database version.
@@ -60,7 +60,7 @@ define( 'THE_SEO_FRAMEWORK_VERSION', '2.9.4' );
60
  *
61
  * @since 2.7.0
62
  */
63
- define( 'THE_SEO_FRAMEWORK_DB_VERSION', '2941' );
64
 
65
  /**
66
  * The plugin options database option_name.
@@ -182,7 +182,7 @@ function the_seo_framework_pre_load() {
182
  function the_seo_framework_test_server() {
183
 
184
  //* Load on init action (manual FTP upload) or after plugin has been upgraded.
185
- require_once( THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'plugin-test-server.php' );
186
 
187
  if ( get_option( 'the_seo_framework_tested_upgrade_version' ) >= THE_SEO_FRAMEWORK_DB_VERSION )
188
  the_seo_framework_load_base_files();
@@ -200,7 +200,7 @@ function the_seo_framework_load_base_files() {
200
  * @since 1.0.0
201
  * @uses THE_SEO_FRAMEWORK_DIR_PATH
202
  */
203
- require_once( THE_SEO_FRAMEWORK_DIR_PATH . 'load.php' );
204
 
205
  /**
206
  * Load deprecated functions.
@@ -209,12 +209,12 @@ function the_seo_framework_load_base_files() {
209
  * @since 2.9.2 No longer called to improve performance.
210
  * @uses THE_SEO_FRAMEWORK_DIR_PATH_FUNCT
211
  */
212
- // require_once( THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'deprecated.php' );
213
 
214
  /**
215
  * Load API files.
216
  * @since 2.1.6
217
  * @uses THE_SEO_FRAMEWORK_DIR_PATH_FUNCT
218
  */
219
- require_once( THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'optionsapi.php' );
220
  }
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.0.2
7
  * Author: Sybre Waaijer
8
  * Author URI: https://theseoframework.com/
9
  * License: GPLv3
33
  //* Debug. Not to be used on production websites as it dumps and/or disables all kinds of stuff everywhere.
34
  // add_action( 'plugins_loaded', function() { if ( is_super_admin() ) {
35
  // if ( is_admin() ) {
36
+ // define( 'THE_SEO_FRAMEWORK_DEBUG', true );
37
  // define( 'THE_SEO_FRAMEWORK_DEBUG_HIDDEN', true );
38
  // define( 'THE_SEO_FRAMEWORK_DISABLE_TRANSIENTS', true );
39
  // update_option( 'the_seo_framework_upgraded_db_version', '0' );
51
  *
52
  * @since 1.0.0
53
  */
54
+ define( 'THE_SEO_FRAMEWORK_VERSION', '3.0.2' );
55
 
56
  /**
57
  * The plugin Database version.
60
  *
61
  * @since 2.7.0
62
  */
63
+ define( 'THE_SEO_FRAMEWORK_DB_VERSION', '3001' );
64
 
65
  /**
66
  * The plugin options database option_name.
182
  function the_seo_framework_test_server() {
183
 
184
  //* Load on init action (manual FTP upload) or after plugin has been upgraded.
185
+ require THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'plugin-test-server.php';
186
 
187
  if ( get_option( 'the_seo_framework_tested_upgrade_version' ) >= THE_SEO_FRAMEWORK_DB_VERSION )
188
  the_seo_framework_load_base_files();
200
  * @since 1.0.0
201
  * @uses THE_SEO_FRAMEWORK_DIR_PATH
202
  */
203
+ require THE_SEO_FRAMEWORK_DIR_PATH . 'load.php';
204
 
205
  /**
206
  * Load deprecated functions.
209
  * @since 2.9.2 No longer called to improve performance.
210
  * @uses THE_SEO_FRAMEWORK_DIR_PATH_FUNCT
211
  */
212
+ // require THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'deprecated.php';
213
 
214
  /**
215
  * Load API files.
216
  * @since 2.1.6
217
  * @uses THE_SEO_FRAMEWORK_DIR_PATH_FUNCT
218
  */
219
+ require THE_SEO_FRAMEWORK_DIR_PATH_FUNCT . 'optionsapi.php';
220
  }
inc/classes/admin-init.class.php CHANGED
@@ -153,7 +153,6 @@ class Admin_Init extends Init {
153
  * @since 2.5.2.2
154
  */
155
  \add_action( 'admin_footer', array( $this, '_localize_admin_javascript' ) );
156
-
157
  }
158
 
159
  /**
@@ -177,7 +176,6 @@ class Admin_Init extends Init {
177
  \wp_register_script( $this->js_name, THE_SEO_FRAMEWORK_DIR_URL . "lib/js/{$this->js_name}{$suffix}.js", array( 'jquery' ), THE_SEO_FRAMEWORK_VERSION, true );
178
 
179
  $registered = true;
180
-
181
  }
182
 
183
  /**
@@ -199,12 +197,13 @@ class Admin_Init extends Init {
199
  \wp_localize_script( $this->js_name, "{$this->js_name}L10n", $strings );
200
 
201
  $localized = true;
202
-
203
  }
204
 
205
  /**
206
  * Generate Javascript Localization.
207
  *
 
 
208
  * @since 2.6.0
209
  * @staticvar array $strings : The l10n strings.
210
  * @since 2.7.0 Added AJAX nonce: 'autodescription-ajax-nonce'
@@ -218,137 +217,178 @@ class Admin_Init extends Init {
218
  */
219
  protected function get_javascript_l10n() {
220
 
 
221
  $blog_name = $this->get_blogname();
222
  $description = $this->get_blogdescription();
223
- $title = '';
224
  $additions = '';
225
 
226
- $tagline = (bool) $this->get_option( 'homepage_tagline' );
227
  $home_tagline = $this->get_option( 'homepage_title_tagline' );
228
  $title_location = $this->get_option( 'title_location' );
229
  $title_add_additions = $this->add_title_additions();
230
  $counter_type = (int) $this->get_user_option( 0, 'counter_type', 3 );
231
 
232
- //* Enunciate the lenghts of Titles and Descriptions.
233
- $good = \__( 'Good', 'autodescription' );
234
- $okay = \__( 'Okay', 'autodescription' );
235
- $bad = \__( 'Bad', 'autodescription' );
236
- $unknown = \__( 'Unknown', 'autodescription' );
237
-
238
  $title_separator = $this->get_separator( 'title' );
239
  $description_separator = $this->get_separator( 'description' );
240
 
241
  $ishome = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  if ( isset( $this->page_base_file ) && $this->page_base_file ) {
244
  // We're somewhere within default WordPress pages.
245
- $post_id = $this->get_the_real_ID();
246
-
247
- if ( $this->is_static_frontpage( $post_id ) ) {
248
- $title = $blog_name;
249
  $title_location = $this->get_option( 'home_title_location' );
250
  $ishome = true;
251
 
252
- if ( $tagline ) {
253
  $additions = $home_tagline ? $home_tagline : $description;
254
  } else {
255
  $additions = '';
256
  }
257
- } elseif ( $post_id ) {
258
  //* We're on post.php
259
  $generated_doctitle_args = array(
260
- 'term_id' => $post_id,
261
  'notagline' => true,
262
  'get_custom_field' => false,
263
  );
264
 
265
- $title = $this->title( '', '', '', $generated_doctitle_args );
266
 
267
  if ( $title_add_additions ) {
268
  $additions = $blog_name;
269
- $tagline = true;
270
  } else {
271
  $additions = '';
272
- $tagline = false;
273
  }
274
- } elseif ( $this->is_archive() ) {
275
  //* Category or Tag.
276
- if ( isset( $GLOBALS['current_screen']->taxonomy ) ) {
277
-
278
- $term_id = $this->get_admin_term_id();
279
-
280
- if ( $term_id ) {
281
- $generated_doctitle_args = array(
282
- 'term_id' => $term_id,
283
- 'taxonomy' => $GLOBALS['current_screen']->taxonomy,
284
- 'notagline' => true,
285
- 'get_custom_field' => false,
286
- );
287
-
288
- $title = $this->title( '', '', '', $generated_doctitle_args );
289
- $additions = $title_add_additions ? $blog_name : '';
290
- }
291
  }
292
  } else {
293
  //* We're in a special place.
294
  // Can't fetch title.
295
- $title = '';
296
  $additions = $title_add_additions ? $blog_name : '';
297
  }
298
- } else {
299
  // We're on our SEO settings pages.
300
  if ( $this->has_page_on_front() ) {
301
  // Home is a page.
302
- $inpost_title = $this->get_custom_field( '_genesis_title', \get_option( 'page_on_front' ) );
 
303
  } else {
304
  // Home is a blog.
305
  $inpost_title = '';
306
  }
307
- $title = $inpost_title ?: $blog_name;
308
  $additions = $home_tagline ?: $description;
309
  }
310
 
311
- //* @TODO deprecate
312
- $nonce = \wp_create_nonce( 'autodescription-ajax-nonce' );
313
-
314
  $this->set_js_nonces( array(
315
  /**
316
- * Use $this->settings_capability() ?... might conflict with other nonces.
317
  */
318
  // 'manage_options' => \current_user_can( 'manage_options' ) ? \wp_create_nonce( 'tsf-ajax-manage_options' ) : false,
319
  'upload_files' => \current_user_can( 'upload_files' ) ? \wp_create_nonce( 'tsf-ajax-upload_files' ) : false,
320
  'edit_posts' => \current_user_can( 'edit_posts' ) ? \wp_create_nonce( 'tsf-ajax-edit_posts' ) : false,
321
  ) );
322
 
323
- return array(
324
- 'nonce' => $nonce,
 
 
 
 
 
 
 
325
  'nonces' => $this->get_js_nonces(),
326
- 'i18n' => array(
327
- 'saveAlert' => \esc_html__( 'The changes you made will be lost if you navigate away from this page.', 'autodescription' ),
328
- 'confirmReset' => \esc_html__( 'Are you sure you want to reset all SEO settings to their defaults?', 'autodescription' ),
329
- 'good' => \esc_html( $good ),
330
- 'okay' => \esc_html( $okay ),
331
- 'bad' => \esc_html( $bad ),
332
- 'unknown' => \esc_html( $unknown ),
333
- ),
334
  'states' => array(
335
  'isRTL' => (bool) \is_rtl(),
336
  'isHome' => $ishome,
337
- 'hasInput' => $this->is_term_edit() || $this->is_post_edit() || $this->is_seo_settings_page(),
338
  'counterType' => \absint( $counter_type ),
339
- 'titleTagline' => $tagline,
340
- 'isSettingsPage' => $this->is_seo_settings_page(),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  ),
342
  'params' => array(
343
- 'siteTitle' => \esc_html( \wp_kses_decode_entities( $title ) ),
344
- 'titleAdditions' => \esc_html( \wp_kses_decode_entities( $additions ) ),
345
- 'blogDescription' => \esc_html( \wp_kses_decode_entities( $description ) ),
346
- 'titleSeparator' => \esc_html( $title_separator ),
347
- 'descriptionSeparator' => \esc_html( $description_separator ),
348
- 'titleLocation' => \esc_html( $title_location ),
 
 
 
 
349
  ),
350
  'other' => $this->additional_js_l10n( null, array(), true ),
351
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  }
353
 
354
  /**
@@ -448,13 +488,14 @@ class Admin_Init extends Init {
448
  * valid and generated between 12-24 hours ago.
449
  */
450
  public function check_tsf_ajax_referer( $capability ) {
451
- return \check_ajax_referer( 'tsf-ajax-' . $capability, 'nonce' );
452
  }
453
 
454
  /**
455
  * CSS for the AutoDescription Bar
456
  *
457
  * @since 2.1.9
 
458
  *
459
  * @param $hook the current page
460
  */
@@ -475,6 +516,8 @@ class Admin_Init extends Init {
475
 
476
  \wp_enqueue_style( $this->css_name );
477
 
 
 
478
  }
479
 
480
  /**
@@ -496,7 +539,65 @@ class Admin_Init extends Init {
496
  $registered = true;
497
 
498
  \wp_register_style( $this->css_name, THE_SEO_FRAMEWORK_DIR_URL . "lib/css/{$this->css_name}{$rtl}{$suffix}.css", array(), THE_SEO_FRAMEWORK_VERSION, 'all' );
 
499
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
  }
501
 
502
  /**
@@ -505,7 +606,7 @@ class Admin_Init extends Init {
505
  * @since 2.8.0
506
  *
507
  * @param array $removable_query_args
508
- * @return array $removable_query_args The adjusted removable query args.
509
  */
510
  public function add_removable_query_args( $removable_query_args = array() ) {
511
 
@@ -569,7 +670,7 @@ class Admin_Init extends Init {
569
  * Provides an accessible error for when redirecting fails.
570
  *
571
  * @since 2.9.2
572
- * @link https://developer.wordpress.org/reference/functions/wp_redirect/
573
  *
574
  * @param string $target The redirect target location. Should be escaped.
575
  * @return void
@@ -607,6 +708,7 @@ class Admin_Init extends Init {
607
  * @since 2.6.0
608
  * @since 2.9.0 : 1. Changed capability from 'publish_posts' to 'edit_posts'.
609
  * 2. Added json header.
 
610
  * @access private
611
  */
612
  public function wp_ajax_update_counter_type() {
@@ -614,11 +716,12 @@ class Admin_Init extends Init {
614
  if ( $this->is_admin() && $this->doing_ajax() ) :
615
 
616
  $this->check_tsf_ajax_referer( 'edit_posts' );
 
 
 
 
617
  //* If current user isn't allowed to edit posts, don't do anything and kill PHP.
618
  if ( ! \current_user_can( 'edit_posts' ) ) {
619
- //* Remove output buffer.
620
- $this->clean_response_header();
621
-
622
  //* Encode and echo results. Requires JSON decode within JS.
623
  echo json_encode( array( 'type' => 'failure', 'value' => '' ) );
624
  exit;
@@ -642,9 +745,6 @@ class Admin_Init extends Init {
642
  'value' => $value,
643
  );
644
 
645
- //* Remove output buffer.
646
- $this->clean_response_header();
647
-
648
  //* Encode and echo results. Requires JSON decode within JS.
649
  echo json_encode( $results );
650
 
@@ -663,6 +763,7 @@ class Admin_Init extends Init {
663
  * 4. It no longer accepts a default context.
664
  *
665
  * @since 2.9.0
 
666
  * @access private
667
  */
668
  public function wp_ajax_crop_image() {
@@ -720,7 +821,6 @@ class Admin_Init extends Init {
720
  * Filters the cropped image attachment metadata.
721
  *
722
  * @since 4.3.0 WordPress Core
723
- *
724
  * @see wp_generate_attachment_metadata()
725
  *
726
  * @param array $metadata Attachment metadata.
153
  * @since 2.5.2.2
154
  */
155
  \add_action( 'admin_footer', array( $this, '_localize_admin_javascript' ) );
 
156
  }
157
 
158
  /**
176
  \wp_register_script( $this->js_name, THE_SEO_FRAMEWORK_DIR_URL . "lib/js/{$this->js_name}{$suffix}.js", array( 'jquery' ), THE_SEO_FRAMEWORK_VERSION, true );
177
 
178
  $registered = true;
 
179
  }
180
 
181
  /**
197
  \wp_localize_script( $this->js_name, "{$this->js_name}L10n", $strings );
198
 
199
  $localized = true;
 
200
  }
201
 
202
  /**
203
  * Generate Javascript Localization.
204
  *
205
+ * @TODO rewrite, it's slow and a mess.
206
+ *
207
  * @since 2.6.0
208
  * @staticvar array $strings : The l10n strings.
209
  * @since 2.7.0 Added AJAX nonce: 'autodescription-ajax-nonce'
217
  */
218
  protected function get_javascript_l10n() {
219
 
220
+ $id = $this->get_the_real_ID();
221
  $blog_name = $this->get_blogname();
222
  $description = $this->get_blogdescription();
223
+ $object_title = '';
224
  $additions = '';
225
 
226
+ $use_additions = (bool) $this->get_option( 'homepage_tagline' );
227
  $home_tagline = $this->get_option( 'homepage_title_tagline' );
228
  $title_location = $this->get_option( 'title_location' );
229
  $title_add_additions = $this->add_title_additions();
230
  $counter_type = (int) $this->get_user_option( 0, 'counter_type', 3 );
231
 
 
 
 
 
 
 
232
  $title_separator = $this->get_separator( 'title' );
233
  $description_separator = $this->get_separator( 'description' );
234
 
235
  $ishome = false;
236
+ $is_settings_page = $this->is_seo_settings_page();
237
+ $is_post_edit = $this->is_post_edit();
238
+ $is_term_edit = $this->is_term_edit();
239
+ $has_input = $is_settings_page || $is_post_edit || $is_term_edit;
240
+
241
+ $post_type = $is_post_edit ? \get_post_type( $id ) : false;
242
+ $_taxonomies = $post_type ? $this->get_hierarchical_taxonomies_as( 'objects', $post_type ) : array();
243
+
244
+ $taxonomies = array();
245
+
246
+ foreach ( $_taxonomies as $_t ) {
247
+ $_i18n_name = strtolower( $_t->labels->singular_name );
248
+ $taxonomies[ $_t->name ] = array(
249
+ 'name' => $_t->name,
250
+ 'i18n' => array(
251
+ /* translators: %s = term name */
252
+ 'makePrimary' => sprintf( \esc_html__( 'Make primary %s', 'autodescription' ), $_i18n_name ),
253
+ /* translators: %s = term name */
254
+ 'primary' => sprintf( \esc_html__( 'Primary %s', 'autodescription' ), $_i18n_name ),
255
+ ),
256
+ 'primary' => $this->get_primary_term_id( $id, $_t->name ) ?: 0,
257
+ );
258
+ }
259
 
260
  if ( isset( $this->page_base_file ) && $this->page_base_file ) {
261
  // We're somewhere within default WordPress pages.
262
+ if ( $this->is_static_frontpage( $id ) ) {
263
+ $object_title = $this->get_option( 'homepage_title' ) ?: $blog_name;
 
 
264
  $title_location = $this->get_option( 'home_title_location' );
265
  $ishome = true;
266
 
267
+ if ( $use_additions ) {
268
  $additions = $home_tagline ? $home_tagline : $description;
269
  } else {
270
  $additions = '';
271
  }
272
+ } elseif ( $is_post_edit ) {
273
  //* We're on post.php
274
  $generated_doctitle_args = array(
275
+ 'term_id' => $id,
276
  'notagline' => true,
277
  'get_custom_field' => false,
278
  );
279
 
280
+ $object_title = $this->title( '', '', '', $generated_doctitle_args );
281
 
282
  if ( $title_add_additions ) {
283
  $additions = $blog_name;
284
+ $use_additions = true;
285
  } else {
286
  $additions = '';
287
+ $use_additions = false;
288
  }
289
+ } elseif ( $is_term_edit ) {
290
  //* Category or Tag.
291
+ if ( isset( $GLOBALS['current_screen']->taxonomy ) && $id ) {
292
+ $object_title = $this->single_term_title( '', false, $this->fetch_the_term( $id ) );
293
+ $additions = $title_add_additions ? $blog_name : '';
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
  } else {
296
  //* We're in a special place.
297
  // Can't fetch title.
298
+ $object_title = '';
299
  $additions = $title_add_additions ? $blog_name : '';
300
  }
301
+ } elseif ( $is_settings_page ) {
302
  // We're on our SEO settings pages.
303
  if ( $this->has_page_on_front() ) {
304
  // Home is a page.
305
+ $id = \get_option( 'page_on_front' );
306
+ $inpost_title = $this->get_custom_field( '_genesis_title', $id );
307
  } else {
308
  // Home is a blog.
309
  $inpost_title = '';
310
  }
311
+ $object_title = $inpost_title ?: $blog_name;
312
  $additions = $home_tagline ?: $description;
313
  }
314
 
 
 
 
315
  $this->set_js_nonces( array(
316
  /**
317
+ * Use $this->get_settings_capability() ?... might conflict with other nonces.
318
  */
319
  // 'manage_options' => \current_user_can( 'manage_options' ) ? \wp_create_nonce( 'tsf-ajax-manage_options' ) : false,
320
  'upload_files' => \current_user_can( 'upload_files' ) ? \wp_create_nonce( 'tsf-ajax-upload_files' ) : false,
321
  'edit_posts' => \current_user_can( 'edit_posts' ) ? \wp_create_nonce( 'tsf-ajax-edit_posts' ) : false,
322
  ) );
323
 
324
+ $term_name = '';
325
+ $use_term_prefix = false;
326
+ if ( $is_term_edit ) {
327
+ $_term = $this->fetch_the_term( $id );
328
+ $term_name = $this->get_the_term_name( $_term, true, false );
329
+ $use_term_prefix = $this->use_archive_prefix( $_term );
330
+ }
331
+
332
+ $l10n = array(
333
  'nonces' => $this->get_js_nonces(),
 
 
 
 
 
 
 
 
334
  'states' => array(
335
  'isRTL' => (bool) \is_rtl(),
336
  'isHome' => $ishome,
337
+ 'hasInput' => $has_input,
338
  'counterType' => \absint( $counter_type ),
339
+ 'useTagline' => $use_additions,
340
+ 'useTermPrefix' => $use_term_prefix,
341
+ 'isSettingsPage' => $is_settings_page,
342
+ 'isPostEdit' => $is_post_edit,
343
+ 'isTermEdit' => $is_term_edit,
344
+ 'postType' => $post_type,
345
+ 'taxonomies' => $taxonomies,
346
+ 'isPrivate' => $has_input && $id && $this->is_private( $id ),
347
+ 'isPasswordProtected' => $has_input && $id && $this->is_password_protected( $id ),
348
+ 'debug' => $this->script_debug,
349
+ ),
350
+ 'i18n' => array(
351
+ 'saveAlert' => \__( 'The changes you made will be lost if you navigate away from this page.', 'autodescription' ),
352
+ 'confirmReset' => \__( 'Are you sure you want to reset all SEO settings to their defaults?', 'autodescription' ),
353
+ 'good' => \__( 'Good', 'autodescription' ),
354
+ 'okay' => \__( 'Okay', 'autodescription' ),
355
+ 'bad' => \__( 'Bad', 'autodescription' ),
356
+ 'unknown' => \__( 'Unknown', 'autodescription' ),
357
+ 'privateTitle' => $has_input && $id ? \__( 'Private:', 'autodescription' ) : '',
358
+ 'protectedTitle' => $has_input && $id ? \__( 'Protected:', 'autodescription' ) : '',
359
+ /* translators: Pixel counter. 1: width, 2: guideline */
360
+ 'pixelsUsed' => $has_input ? \__( '%1$d out of %2$d pixels are used.', 'autodescription' ) : '',
361
  ),
362
  'params' => array(
363
+ 'objectTitle' => $object_title,
364
+ 'titleAdditions' => $additions,
365
+ 'blogDescription' => $description,
366
+ 'termName' => $term_name,
367
+ 'untitledTitle' => $this->untitled(),
368
+ 'titleSeparator' => $title_separator,
369
+ 'descriptionSeparator' => $description_separator,
370
+ 'titleLocation' => $title_location,
371
+ 'titlePixelGuideline' => 600,
372
+ 'descPixelGuideline' => $is_post_edit ? ( $this->is_page() ? 920 : 820 ) : 920,
373
  ),
374
  'other' => $this->additional_js_l10n( null, array(), true ),
375
  );
376
+
377
+ $decode = array( 'i18n', 'params' );
378
+ $flags = ENT_COMPAT;
379
+ foreach ( $decode as $key ) {
380
+ foreach ( $l10n[ $key ] as $k => $v ) {
381
+ $l10n[ $key ][ $k ] = \esc_js( \html_entity_decode( $v, $flags, 'UTF-8' ) );
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Applies filters 'the_seo_framework_js_l10n'
387
+ *
388
+ * @since 3.0.0
389
+ * @param array $l10n
390
+ */
391
+ return (array) \apply_filters( 'the_seo_framework_js_l10n', $l10n );
392
  }
393
 
394
  /**
488
  * valid and generated between 12-24 hours ago.
489
  */
490
  public function check_tsf_ajax_referer( $capability ) {
491
+ return \check_ajax_referer( 'tsf-ajax-' . $capability, 'nonce', true );
492
  }
493
 
494
  /**
495
  * CSS for the AutoDescription Bar
496
  *
497
  * @since 2.1.9
498
+ * @since 3.0.0 Now also outputs colors.
499
  *
500
  * @param $hook the current page
501
  */
516
 
517
  \wp_enqueue_style( $this->css_name );
518
 
519
+ $color_css = $this->get_admin_color_css()
520
+ and \wp_add_inline_style( $this->css_name, $color_css );
521
  }
522
 
523
  /**
539
  $registered = true;
540
 
541
  \wp_register_style( $this->css_name, THE_SEO_FRAMEWORK_DIR_URL . "lib/css/{$this->css_name}{$rtl}{$suffix}.css", array(), THE_SEO_FRAMEWORK_VERSION, 'all' );
542
+ }
543
 
544
+ /**
545
+ * Outputs additional CSS based on admin theme colors.
546
+ *
547
+ * @since 3.0.0
548
+ *
549
+ * @return string Additional admin CSS.
550
+ */
551
+ protected function get_admin_color_css() {
552
+
553
+ //* @see wp_style_loader_src()
554
+ $scheme = \get_user_option( 'admin_color' ) ?: 'fresh';
555
+
556
+ $_colors = $GLOBALS['_wp_admin_css_colors'];
557
+
558
+ if ( ! isset( $_colors[ $scheme ]->colors ) || ! is_array( $_colors[ $scheme ]->colors ) )
559
+ return '';
560
+
561
+ $_scheme = $_colors[ $scheme ]->colors;
562
+
563
+ $bg = $_scheme[0];
564
+ $bg_accent = $_scheme[1];
565
+ $color = $_scheme[2];
566
+ $color_accent = $_scheme[3];
567
+
568
+ $bg_alt_font = '#' . $this->get_relative_fontcolor( $bg );
569
+ // $bg_accent_alt_font = '#' . $this->get_relative_fontcolor( $bg_accent );
570
+
571
+ $css = array(
572
+ '.tsf-flex-nav-tab .tsf-flex-nav-tab-radio:checked + .tsf-flex-nav-tab-label' => array(
573
+ "box-shadow:0 -2px 0 0 $color_accent inset",
574
+ ),
575
+ '.tsf-tooltip-text-wrap' => array(
576
+ "background-color:$bg_accent",
577
+ "color:$bg_alt_font",
578
+ ),
579
+ '.tsf-tooltip-arrow:after' => array(
580
+ "border-top-color:$bg_accent",
581
+ ),
582
+ '.tsf-tooltip-down .tsf-tooltip-arrow:after' => array(
583
+ "border-bottom-color:$bg_accent",
584
+ ),
585
+ );
586
+
587
+ /**
588
+ * Applies filters 'the_seo_framework_admin_color_css'
589
+ *
590
+ * @since 3.0.0
591
+ * @param array $css The current styles.
592
+ * @param string $scheme The current admin scheme.
593
+ */
594
+ $css = (array) \apply_filters( 'the_seo_framework_admin_color_css', $css, $scheme );
595
+
596
+ $out = '';
597
+ foreach ( $css as $attr => $style )
598
+ $out .= $attr . '{' . implode( ';', $style ) . '}';
599
+
600
+ return $out;
601
  }
602
 
603
  /**
606
  * @since 2.8.0
607
  *
608
  * @param array $removable_query_args
609
+ * @return array The adjusted removable query args.
610
  */
611
  public function add_removable_query_args( $removable_query_args = array() ) {
612
 
670
  * Provides an accessible error for when redirecting fails.
671
  *
672
  * @since 2.9.2
673
+ * @see https://developer.wordpress.org/reference/functions/wp_redirect/
674
  *
675
  * @param string $target The redirect target location. Should be escaped.
676
  * @return void
708
  * @since 2.6.0
709
  * @since 2.9.0 : 1. Changed capability from 'publish_posts' to 'edit_posts'.
710
  * 2. Added json header.
711
+ * @securitycheck 3.0.0 OK.
712
  * @access private
713
  */
714
  public function wp_ajax_update_counter_type() {
716
  if ( $this->is_admin() && $this->doing_ajax() ) :
717
 
718
  $this->check_tsf_ajax_referer( 'edit_posts' );
719
+
720
+ //* Remove output buffer.
721
+ $this->clean_response_header();
722
+
723
  //* If current user isn't allowed to edit posts, don't do anything and kill PHP.
724
  if ( ! \current_user_can( 'edit_posts' ) ) {
 
 
 
725
  //* Encode and echo results. Requires JSON decode within JS.
726
  echo json_encode( array( 'type' => 'failure', 'value' => '' ) );
727
  exit;
745
  'value' => $value,
746
  );
747
 
 
 
 
748
  //* Encode and echo results. Requires JSON decode within JS.
749
  echo json_encode( $results );
750
 
763
  * 4. It no longer accepts a default context.
764
  *
765
  * @since 2.9.0
766
+ * @securitycheck 3.0.0 OK.
767
  * @access private
768
  */
769
  public function wp_ajax_crop_image() {
821
  * Filters the cropped image attachment metadata.
822
  *
823
  * @since 4.3.0 WordPress Core
 
824
  * @see wp_generate_attachment_metadata()
825
  *
826
  * @param array $metadata Attachment metadata.
inc/classes/admin-pages.class.php CHANGED
@@ -108,9 +108,9 @@ class Admin_Pages extends Inpost {
108
  $menu = array(
109
  'page_title' => \esc_html__( 'SEO Settings', 'autodescription' ),
110
  'menu_title' => \esc_html__( 'SEO', 'autodescription' ),
111
- 'capability' => $this->settings_capability(),
112
  'menu_slug' => $this->seo_settings_page_slug,
113
- 'callback' => array( $this, 'admin' ),
114
  'icon' => 'dashicons-search',
115
  'position' => '90.9001',
116
  );
@@ -160,50 +160,36 @@ class Admin_Pages extends Inpost {
160
  $this->handle_update_post();
161
 
162
  //* Output metaboxes.
163
- \add_action( $this->seo_settings_page_hook . '_settings_page_boxes', array( $this, 'do_metaboxes' ) );
164
- \add_action( 'load-' . $this->seo_settings_page_hook, array( $this, 'metaboxes' ) );
165
  }
166
 
167
  /**
168
- * Echo out the do_metaboxes() and wrapping markup.
169
  *
170
- * @since 2.2.2
 
171
  */
172
- public function do_metaboxes() {
173
- ?>
174
- <div class="metabox-holder columns-2">
175
- <div class="postbox-container-1">
176
- <?php
177
- \do_action( 'the_seo_framework_before_siteadmin_metaboxes', $this->seo_settings_page_hook );
178
-
179
- \do_meta_boxes( $this->seo_settings_page_hook, 'main', null );
180
-
181
- if ( isset( $GLOBALS['wp_meta_boxes'][ $this->seo_settings_page_hook ]['main_extra'] ) )
182
- \do_meta_boxes( $this->seo_settings_page_hook, 'main_extra', null );
183
-
184
- \do_action( 'the_seo_framework_after_siteadmin_metaboxes', $this->seo_settings_page_hook );
185
- ?>
186
- </div>
187
- <div class="postbox-container-2">
188
- <?php
189
- \do_action( 'the_seo_framework_before_siteadmin_metaboxes_side', $this->seo_settings_page_hook );
190
-
191
- /**
192
- * @TODO fill this in
193
- * @priority low 2.9.0
194
- */
195
-
196
- \do_action( 'the_seo_framework_after_siteadmin_metaboxes_side', $this->seo_settings_page_hook );
197
- ?>
198
- </div>
199
- </div>
200
- <?php
201
  }
202
 
203
  /**
204
- * Register meta boxes on the Site SEO Settings page.
205
  *
206
- * @since 2.2.2
 
 
 
 
 
 
 
 
 
 
207
  *
208
  * @see $this->general_metabox() Callback for General Settings box.
209
  * @see $this->title_metabox() Callback for Title Settings box.
@@ -216,7 +202,7 @@ class Admin_Pages extends Inpost {
216
  * @see $this->sitemaps_metabox() Callback for Sitemap Settings box.
217
  * @see $this->feed_metabox() Callback for Feed Settings box.
218
  */
219
- public function metaboxes() {
220
 
221
  /**
222
  * Various metabox filters.
@@ -347,63 +333,13 @@ class Admin_Pages extends Inpost {
347
  );
348
  }
349
 
350
- /**
351
- * Use this as the settings admin callback to create an admin page with sortable metaboxes.
352
- * Create a 'settings_boxes' method to add metaboxes.
353
- *
354
- * @since 2.2.2
355
- * @todo deprecate (method name is arbitrary) and convert to view.
356
- */
357
- public function admin() {
358
-
359
- ?>
360
- <div class="wrap tsf-metaboxes">
361
- <form method="post" action="options.php">
362
-
363
- <?php \wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
364
- <?php \wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
365
- <?php \settings_fields( $this->settings_field ); ?>
366
-
367
- <div class="tsf-top-wrap">
368
- <h1><?php echo \esc_html( \get_admin_page_title() ); ?></h1>
369
- <p class="tsf-top-buttons">
370
- <?php
371
- \submit_button( $this->page_defaults['save_button_text'], 'primary', 'submit', false, array( 'id' => '' ) );
372
- \submit_button( $this->page_defaults['reset_button_text'], 'secondary tsf-js-confirm-reset', $this->get_field_name( 'tsf-settings-reset' ), false, array( 'id' => '' ) );
373
- ?>
374
- </p>
375
- </div>
376
-
377
- <?php \do_action( "{$this->seo_settings_page_hook}_settings_page_boxes", $this->seo_settings_page_hook ); ?>
378
-
379
- <div class="tsf-bottom-buttons">
380
- <?php
381
- \submit_button( $this->page_defaults['save_button_text'], 'primary', 'submit', false, array( 'id' => '' ) );
382
- \submit_button( $this->page_defaults['reset_button_text'], 'secondary tsf-js-confirm-reset', $this->get_field_name( 'tsf-settings-reset' ), false, array( 'id' => '' ) );
383
- ?>
384
- </div>
385
- </form>
386
- </div>
387
- <?php // Add postbox listeners ?>
388
- <script type="text/javascript">
389
- //<![CDATA[
390
- jQuery(document).ready( function($) {
391
- // close postboxes that should be closed
392
- $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
393
- // postboxes setup
394
- postboxes.add_postbox_toggles('<?php echo \esc_js( $this->seo_settings_page_hook ); ?>');
395
- });
396
- //]]>
397
- </script>
398
- <?php
399
-
400
- }
401
-
402
  /**
403
  * Display notices on the save or reset of settings.
404
  *
405
  * @since 2.2.2
 
406
  * @todo convert the "get" into secure "error_notice" option. See TSF Extension Manager.
 
407
  *
408
  * @return void
409
  */
@@ -519,7 +455,7 @@ class Admin_Pages extends Inpost {
519
  *
520
  * @param string $input The input to wrap. Should already be escaped.
521
  * @param boolean $echo Whether to escape echo or just return.
522
- * @return Wrapped $input.
523
  */
524
  public function wrap_fields( $input = '', $echo = false ) {
525
 
@@ -544,7 +480,7 @@ class Admin_Pages extends Inpost {
544
  * @param string $label The checkbox description label.
545
  * @param string $description Addition description to place beneath the checkbox.
546
  * @param bool $escape Whether to escape the label and description.
547
- * @return HTML checkbox output.
548
  */
549
  public function make_checkbox( $field_id = '', $label = '', $description = '', $escape = true ) {
550
 
@@ -586,7 +522,7 @@ class Admin_Pages extends Inpost {
586
  * @param string $description Addition description to place beneath the checkbox.
587
  * @param string $placeholder The text field placeholder.
588
  * @param bool $escape Whether to escape the label and description.
589
- * @return HTML text field output.
590
  */
591
  public function make_textfield( $field_id = '', $label = '', $description = '', $placeholder = '', $escape = true ) {
592
 
@@ -620,20 +556,30 @@ class Admin_Pages extends Inpost {
620
  * Return a wrapped question mark.
621
  *
622
  * @since 2.6.0
 
623
  *
624
  * @param string $description The descriptive on-hover title.
625
  * @param string $link The non-escaped link.
626
  * @param bool $echo Whether to echo or return.
627
- * @return HTML checkbox output if $echo is false.
628
  */
629
  public function make_info( $description = '', $link = '', $echo = true ) {
630
 
631
  if ( $link ) {
632
- $output = '<a href="' . \esc_url( $link, array( 'http', 'https' ) ) . '" target="_blank" title="' . \esc_attr( $description ) . '">[?]</a>';
 
 
 
 
633
  } else {
634
- $output = '<span title="' . \esc_attr( $description ) . '">[?]</span>';
 
 
 
635
  }
636
 
 
 
637
  if ( $echo ) {
638
  //* Already escaped.
639
  echo $output;
@@ -831,7 +777,6 @@ class Admin_Pages extends Inpost {
831
  * Also registers additional i18n strings for JS.
832
  *
833
  * @since 2.8.0
834
- * @todo optimize? Sanitation and translations are duplicated -> microseconds...
835
  *
836
  * @param string $input_id Required. The HTML input id to pass URL into.
837
  * @return string The image uploader button.
@@ -841,11 +786,20 @@ class Admin_Pages extends Inpost {
841
  if ( ! $input_id )
842
  return '';
843
 
844
- $content = sprintf( '<a href="%1$s" class="tsf-set-social-image button button-primary button-small" title="%2$s" id="%3$s-select" data-inputid="%3$s">%4$s</a>',
845
- \esc_url( \get_upload_iframe_src( 'image', $this->get_the_real_ID() ) ),
846
- \esc_attr_x( 'Select social image', 'Button hover', 'autodescription' ),
847
- \esc_attr( $input_id ),
848
- \esc_html__( 'Select Image', 'autodescription' )
 
 
 
 
 
 
 
 
 
849
  );
850
 
851
  $button_labels = array(
@@ -859,8 +813,117 @@ class Admin_Pages extends Inpost {
859
  );
860
 
861
  //* Already escaped. Turn off escaping.
862
- $this->additional_js_l10n( \esc_attr( $input_id ), $button_labels, false, false );
863
 
864
  return $content;
865
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
866
  }
108
  $menu = array(
109
  'page_title' => \esc_html__( 'SEO Settings', 'autodescription' ),
110
  'menu_title' => \esc_html__( 'SEO', 'autodescription' ),
111
+ 'capability' => $this->get_settings_capability(),
112
  'menu_slug' => $this->seo_settings_page_slug,
113
+ 'callback' => array( $this, '_output_seo_settings_wrap' ),
114
  'icon' => 'dashicons-search',
115
  'position' => '90.9001',
116
  );
160
  $this->handle_update_post();
161
 
162
  //* Output metaboxes.
163
+ \add_action( $this->seo_settings_page_hook . '_settings_page_boxes', array( $this, '_output_seo_settings_columns' ) );
164
+ \add_action( 'load-' . $this->seo_settings_page_hook, array( $this, '_register_seo_settings_metaboxes' ) );
165
  }
166
 
167
  /**
168
+ * Outputs SEO Settings page wrap.
169
  *
170
+ * @since 3.0.0
171
+ * @access private
172
  */
173
+ public function _output_seo_settings_wrap() {
174
+ \do_action( 'the_seo_framework_pre_seo_settings' );
175
+ $this->get_view( 'admin/seo-settings-wrap', get_defined_vars() );
176
+ \do_action( 'the_seo_framework_pro_seo_settings' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  }
178
 
179
  /**
180
+ * Outputs SEO Settings columns.
181
  *
182
+ * @since 3.0.0
183
+ * @access private
184
+ */
185
+ public function _output_seo_settings_columns() {
186
+ $this->get_view( 'admin/seo-settings-columns', get_defined_vars() );
187
+ }
188
+
189
+ /**
190
+ * Registers meta boxes on the Site SEO Settings page.
191
+ *
192
+ * @since 3.0.0
193
  *
194
  * @see $this->general_metabox() Callback for General Settings box.
195
  * @see $this->title_metabox() Callback for Title Settings box.
202
  * @see $this->sitemaps_metabox() Callback for Sitemap Settings box.
203
  * @see $this->feed_metabox() Callback for Feed Settings box.
204
  */
205
+ public function _register_seo_settings_metaboxes() {
206
 
207
  /**
208
  * Various metabox filters.
333
  );
334
  }
335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  /**
337
  * Display notices on the save or reset of settings.
338
  *
339
  * @since 2.2.2
340
+ * @securitycheck 3.0.0 OK. NOTE: Users can however MANUALLY trigger these on the SEO settings page.
341
  * @todo convert the "get" into secure "error_notice" option. See TSF Extension Manager.
342
+ * @todo convert $this->page_defaults to inline texts. It's now uselessly rendering.
343
  *
344
  * @return void
345
  */
455
  *
456
  * @param string $input The input to wrap. Should already be escaped.
457
  * @param boolean $echo Whether to escape echo or just return.
458
+ * @return string|void Wrapped $input.
459
  */
460
  public function wrap_fields( $input = '', $echo = false ) {
461
 
480
  * @param string $label The checkbox description label.
481
  * @param string $description Addition description to place beneath the checkbox.
482
  * @param bool $escape Whether to escape the label and description.
483
+ * @return string HTML checkbox output.
484
  */
485
  public function make_checkbox( $field_id = '', $label = '', $description = '', $escape = true ) {
486
 
522
  * @param string $description Addition description to place beneath the checkbox.
523
  * @param string $placeholder The text field placeholder.
524
  * @param bool $escape Whether to escape the label and description.
525
+ * @return string HTML text field output.
526
  */
527
  public function make_textfield( $field_id = '', $label = '', $description = '', $placeholder = '', $escape = true ) {
528
 
556
  * Return a wrapped question mark.
557
  *
558
  * @since 2.6.0
559
+ * @since 3.0.0 Links are now no longer followed, referred or bound to opener.
560
  *
561
  * @param string $description The descriptive on-hover title.
562
  * @param string $link The non-escaped link.
563
  * @param bool $echo Whether to echo or return.
564
+ * @return string HTML checkbox output if $echo is false.
565
  */
566
  public function make_info( $description = '', $link = '', $echo = true ) {
567
 
568
  if ( $link ) {
569
+ $output = sprintf(
570
+ '<a href="%1$s" class="tsf-tooltip-item" target="_blank" rel="nofollow noreferrer noopener" title="%2$s" data-desc="%2$s">[?]</a>',
571
+ \esc_url( $link, array( 'http', 'https' ) ),
572
+ \esc_attr( $description )
573
+ );
574
  } else {
575
+ $output = sprintf(
576
+ '<span class="tsf-tooltip-item" title="%1$s" data-desc="%1$s">[?]</span>',
577
+ \esc_attr( $description )
578
+ );
579
  }
580
 
581
+ $output = sprintf( '<span class="tsf-tooltip-wrap">%s</span>', $output );
582
+
583
  if ( $echo ) {
584
  //* Already escaped.
585
  echo $output;
777
  * Also registers additional i18n strings for JS.
778
  *
779
  * @since 2.8.0
 
780
  *
781
  * @param string $input_id Required. The HTML input id to pass URL into.
782
  * @return string The image uploader button.
786
  if ( ! $input_id )
787
  return '';
788
 
789
+ $s_input_id = \esc_attr( $input_id );
790
+
791
+ $content = vsprintf(
792
+ '<a href="%1$s" class="tsf-set-social-image button button-primary button-small" title="%2$s" id="%3$s-select"
793
+ data-inputid="%3$s" data-width="%4$s" data-height="%5$s" data-flex="%6$d">%7$s</a>',
794
+ array(
795
+ \esc_url( \get_upload_iframe_src( 'image', $this->get_the_real_ID() ) ),
796
+ \esc_attr_x( 'Select social image', 'Button hover', 'autodescription' ),
797
+ $s_input_id,
798
+ '1200',
799
+ '630',
800
+ true,
801
+ \esc_html__( 'Select Image', 'autodescription' ),
802
+ )
803
  );
804
 
805
  $button_labels = array(
813
  );
814
 
815
  //* Already escaped. Turn off escaping.
816
+ $this->additional_js_l10n( $s_input_id, $button_labels, false, false );
817
 
818
  return $content;
819
  }
820
+
821
+ /**
822
+ * Returns logo uploader form buttons.
823
+ * Also registers additional i18n strings for JS.
824
+ *
825
+ * @since 3.0.0
826
+ *
827
+ * @param string $input_id Required. The HTML input id to pass URL into.
828
+ * @return string The image uploader button.
829
+ */
830
+ public function get_logo_uploader_form( $input_id ) {
831
+
832
+ if ( ! $input_id )
833
+ return '';
834
+
835
+ $s_input_id = \esc_attr( $input_id );
836
+
837
+ $content = vsprintf(
838
+ '<a href="%1$s" class="tsf-set-social-image button button-primary button-small" title="%2$s" id="%3$s-select"
839
+ data-inputid="%3$s" data-width="%4$s" data-height="%5$s" data-flex="%6$d">%7$s</a>',
840
+ array(
841
+ \esc_url( \get_upload_iframe_src( 'image', $this->get_the_real_ID() ) ),
842
+ '',
843
+ $s_input_id,
844
+ '512',
845
+ '512',
846
+ false,
847
+ \esc_html__( 'Select Logo', 'autodescription' ),
848
+ )
849
+ );
850
+
851
+ $button_labels = array(
852
+ 'select' => \esc_attr__( 'Select Logo', 'autodescription' ),
853
+ 'select_title' => '',
854
+ 'change' => \esc_attr__( 'Change Logo', 'autodescription' ),
855
+ 'remove' => \esc_attr__( 'Remove Logo', 'autodescription' ),
856
+ 'remove_title' => \esc_attr__( 'Unset selected logo', 'autodescription' ),
857
+ 'frame_title' => \esc_attr_x( 'Select Logo', 'Frame title', 'autodescription' ),
858
+ 'frame_button' => \esc_attr__( 'Use this image', 'autodescription' ),
859
+ );
860
+
861
+ //* Already escaped. Turn off escaping.
862
+ $this->additional_js_l10n( $s_input_id, $button_labels, false, false );
863
+
864
+ return $content;
865
+ }
866
+
867
+ /**
868
+ * Outputs floating title HTML for JavaScript.
869
+ *
870
+ * @since 3.0.0
871
+ */
872
+ public function output_floating_title_elements() {
873
+ ?>
874
+ <span id="tsf-title-offset" class="hide-if-no-js"></span>
875
+ <span id="tsf-title-placeholder" class="hide-if-no-js"></span>
876
+ <span id="tsf-title-placeholder-prefix" class="hide-if-no-js"></span>
877
+ <?php
878
+ }
879
+
880
+ /**
881
+ * Outputs character counter wrap for both JavaScript and no-Javascript.
882
+ *
883
+ * @since 3.0.0
884
+ *
885
+ * @param string $for The input ID it's for.
886
+ * @param string $initial The initial value for no-JS.
887
+ * @param bool $display Whether to display the counter.
888
+ */
889
+ public function output_character_counter_wrap( $for, $initial = 0, $display = true ) {
890
+ printf(
891
+ '<div class="tsf-counter-wrap" %s><span class="description tsf-counter">%s</span><span class="hide-if-no-js tsf-ajax"></span></div>',
892
+ $display ? '' : 'style="display:none;"',
893
+ sprintf(
894
+ /* translators: %s = number */
895
+ \esc_html__( 'Characters Used: %s', 'autodescription' ),
896
+ sprintf(
897
+ '<span id="%s_chars">%s</span>',
898
+ \esc_attr( $for ),
899
+ (int) mb_strlen( $initial )
900
+ )
901
+ )
902
+ );
903
+ }
904
+
905
+ /**
906
+ * Outputs pixel counter wrap for javascript.
907
+ *
908
+ * @since 3.0.0
909
+ *
910
+ * @param string $for The input ID it's for.
911
+ * @param string $type Whether it's a 'title' or 'description' counter.
912
+ * @param bool $display Whether to display the counter.
913
+ */
914
+ public function output_pixel_counter_wrap( $for, $type, $display = true ) {
915
+ printf(
916
+ '<div class="tsf-pixel-counter-wrap hide-if-no-js" %s>%s%s</div>',
917
+ $display ? '' : 'style="display:none;"',
918
+ sprintf(
919
+ '<div id="%s_pixels" class="tsf-tooltip-wrap">%s</div>',
920
+ \esc_attr( $for ),
921
+ '<span class="tsf-pixel-counter-bar tsf-tooltip-item" aria-label="" data-desc=""><span class="tsf-pixel-counter-fluid"></span></span>'
922
+ ),
923
+ sprintf(
924
+ '<div class="tsf-pixel-shadow-wrap"><span class="tsf-pixel-counter-shadow tsf-%s-pixel-counter-shadow"></span></div>',
925
+ \esc_attr( $type )
926
+ )
927
+ );
928
+ }
929
  }
inc/classes/cache.class.php CHANGED
@@ -64,10 +64,19 @@ class Cache extends Sitemaps {
64
  *
65
  * @since 2.5.2
66
  *
67
- * @var string The Theme Doing It Right Transient Name.
68
  */
69
  protected $theme_doing_it_right_transient;
70
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Constructor, load parent constructor and set up caches.
73
  */
@@ -148,6 +157,9 @@ class Cache extends Sitemaps {
148
  \add_action( 'post_updated', array( $this, 'delete_post_cache' ) );
149
  \add_action( 'page_updated', array( $this, 'delete_post_cache' ) );
150
 
 
 
 
151
  $run = true;
152
  }
153
 
@@ -166,15 +178,19 @@ class Cache extends Sitemaps {
166
  }
167
 
168
  /**
169
- * Delete transient on post save.
170
  *
171
  * @since 2.8.0
 
172
  *
173
  * @param int $post_id The Post ID that has been updated.
174
  * @return bool True on success, false on failure.
175
  */
176
  public function delete_post_cache( $post_id ) {
177
 
 
 
 
178
  $success = array();
179
 
180
  $success[] = $this->delete_cache( 'post', $post_id );
@@ -188,6 +204,30 @@ class Cache extends Sitemaps {
188
  return ! in_array( false, $success, true );
189
  }
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  /**
192
  * Deletes cache on profile save.
193
  *
@@ -284,6 +324,10 @@ class Cache extends Sitemaps {
284
  return $this->object_cache_delete( $this->get_robots_txt_cache_key() );
285
  break;
286
 
 
 
 
 
287
  case 'detection' :
288
  return $this->delete_theme_dir_transient();
289
  break;
@@ -380,7 +424,7 @@ class Cache extends Sitemaps {
380
  * @param string $value Transient value. Expected to not be SQL-escaped.
381
  * @param int $expiration Optional Transient expiration date, optional. Expected to not be SQL-escaped.
382
  */
383
- public function set_transient( $transient, $value, $expiration = '' ) {
384
 
385
  if ( $this->the_seo_framework_use_transients )
386
  \set_transient( $transient, $value, $expiration );
@@ -469,6 +513,7 @@ class Cache extends Sitemaps {
469
  * @since 2.8.0:
470
  * 1. Added locale suffix.
471
  * 2. Added check for option 'cache_sitemap'.
 
472
  * @global int $blog_id
473
  */
474
  public function setup_transient_names() {
@@ -478,11 +523,13 @@ class Cache extends Sitemaps {
478
  * When the caching mechanism changes. Change this value.
479
  * Use hex. e.g. 0, 1, 2, 9, a, b
480
  */
481
- $sitemap_revision = '3';
482
- $theme_dir_revision = '0';
 
483
 
484
  $this->sitemap_transient = $this->is_option_checked( 'cache_sitemap' ) ? $this->add_cache_key_suffix( 'tsf_sitemap_' . $sitemap_revision ) : '';
485
  $this->theme_doing_it_right_transient = 'tsf_tdir_' . $theme_dir_revision . '_' . $blog_id;
 
486
  }
487
 
488
  /**
@@ -519,7 +566,7 @@ class Cache extends Sitemaps {
519
 
520
  $cache_key = $this->generate_cache_key( $page_id, $taxonomy, $type );
521
 
522
- $revision = '2';
523
  $additions = $this->add_description_additions( $page_id, $taxonomy );
524
 
525
  if ( $additions ) {
@@ -563,13 +610,12 @@ class Cache extends Sitemaps {
563
 
564
  $cache_key = $this->generate_cache_key( $page_id, $taxonomy, $type );
565
 
566
- $revision = '5';
567
 
568
  /**
569
  * Change key based on options.
570
  */
571
  $options = $this->enable_ld_json_breadcrumbs() ? '1' : '0';
572
- $options .= $this->enable_ld_json_sitename() ? '1' : '0';
573
  $options .= $this->enable_ld_json_searchbox() ? '1' : '0';
574
 
575
  return 'tsf_' . $revision . '_' . $options . '_ldjs_' . $cache_key;
@@ -822,18 +868,18 @@ class Cache extends Sitemaps {
822
  * @since 2.8.0 1: $locale is now static.
823
  * 2: $key may now be empty.
824
  * @staticvar string $locale
 
825
  *
826
  * @return string the cache key.
827
  */
828
  protected function add_cache_key_suffix( $key = '' ) {
829
- global $blog_id;
830
 
831
  static $locale = null;
832
 
833
  if ( is_null( $locale ) )
834
  $locale = strtolower( \get_locale() );
835
 
836
- return $key . '_' . $blog_id . '_' . $locale;
837
  }
838
 
839
  /**
@@ -970,6 +1016,8 @@ class Cache extends Sitemaps {
970
  *
971
  * @since 2.9.1
972
  * @uses THE_SEO_FRAMEWORK_DB_VERSION as cache key buster.
 
 
973
  *
974
  * @param int $id The ID. Defaults to $this->get_the_real_ID();
975
  * @param string $taxonomy The term taxonomy
@@ -983,10 +1031,10 @@ class Cache extends Sitemaps {
983
  */
984
  $key = $this->generate_cache_key_by_type( $id, $taxonomy, $type ) . '_' . THE_SEO_FRAMEWORK_DB_VERSION;
985
 
986
- $page = '1';
987
- $paged = '1';
988
 
989
- return $cache_key = 'seo_framework_output_' . $key . '_' . $paged . '_' . $page;
990
  }
991
 
992
  /**
@@ -1011,13 +1059,13 @@ class Cache extends Sitemaps {
1011
  *
1012
  * @since 2.3.0
1013
  * @since 2.7.0 : Added admin referer check.
 
1014
  *
1015
  * @return bool Whether if sitemap transient is deleted.
1016
  */
1017
  public function delete_sitemap_transient_permalink_updated() {
1018
 
1019
  if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) {
1020
-
1021
  if ( \check_admin_referer( 'update-permalink' ) )
1022
  return $this->delete_cache( 'sitemap' );
1023
  }
@@ -1126,10 +1174,8 @@ class Cache extends Sitemaps {
1126
  */
1127
  public function delete_theme_dir_transient( $value = null, $options = null ) {
1128
 
1129
- if ( isset( $options['type'] ) ) {
1130
- if ( 'theme' !== $options['type'] )
1131
- return false;
1132
- }
1133
 
1134
  \delete_transient( $this->theme_doing_it_right_transient );
1135
 
@@ -1158,4 +1204,44 @@ class Cache extends Sitemaps {
1158
  \set_transient( $this->theme_doing_it_right_transient, $dir, 0 );
1159
  }
1160
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1161
  }
64
  *
65
  * @since 2.5.2
66
  *
67
+ * @var string
68
  */
69
  protected $theme_doing_it_right_transient;
70
 
71
+ /**
72
+ * The excluded Post IDs transient name.
73
+ *
74
+ * @since 3.0.0
75
+ *
76
+ * @var string
77
+ */
78
+ protected $excluded_post_ids_transient;
79
+
80
  /**
81
  * Constructor, load parent constructor and set up caches.
82
  */
157
  \add_action( 'post_updated', array( $this, 'delete_post_cache' ) );
158
  \add_action( 'page_updated', array( $this, 'delete_post_cache' ) );
159
 
160
+ //* Excluded IDs cache.
161
+ \add_action( 'save_post', array( $this, 'delete_excluded_ids_cache' ) );
162
+
163
  $run = true;
164
  }
165
 
178
  }
179
 
180
  /**
181
+ * Deletes transient on post save.
182
  *
183
  * @since 2.8.0
184
+ * @since 3.0.0 Process is halted when no valid $post_id is supplied.
185
  *
186
  * @param int $post_id The Post ID that has been updated.
187
  * @return bool True on success, false on failure.
188
  */
189
  public function delete_post_cache( $post_id ) {
190
 
191
+ if ( ! $post_id )
192
+ return false;
193
+
194
  $success = array();
195
 
196
  $success[] = $this->delete_cache( 'post', $post_id );
204
  return ! in_array( false, $success, true );
205
  }
206
 
207
+ /**
208
+ * Deletes excluded post IDs cache.
209
+ *
210
+ * @since 3.0.0
211
+ *
212
+ * @return bool True on success, false on failure.
213
+ */
214
+ public function delete_excluded_ids_cache() {
215
+ return $this->delete_cache( 'excluded_post_ids' );
216
+ }
217
+
218
+ /**
219
+ * Deletes excluded post IDs transient cache.
220
+ *
221
+ * @since 3.0.0
222
+ * @see $this->delete_excluded_ids_cache()
223
+ *
224
+ * @return bool True
225
+ */
226
+ public function delete_excluded_post_ids_transient() {
227
+ \delete_transient( $this->excluded_post_ids_transient );
228
+ return true;
229
+ }
230
+
231
  /**
232
  * Deletes cache on profile save.
233
  *
324
  return $this->object_cache_delete( $this->get_robots_txt_cache_key() );
325
  break;
326
 
327
+ case 'excluded_post_ids' :
328
+ return $this->delete_excluded_post_ids_transient();
329
+ break;
330
+
331
  case 'detection' :
332
  return $this->delete_theme_dir_transient();
333
  break;
424
  * @param string $value Transient value. Expected to not be SQL-escaped.
425
  * @param int $expiration Optional Transient expiration date, optional. Expected to not be SQL-escaped.
426
  */
427
+ public function set_transient( $transient, $value, $expiration = 0 ) {
428
 
429
  if ( $this->the_seo_framework_use_transients )
430
  \set_transient( $transient, $value, $expiration );
513
  * @since 2.8.0:
514
  * 1. Added locale suffix.
515
  * 2. Added check for option 'cache_sitemap'.
516
+ * @since 3.0.0 Now also sets up $excluded_post_ids_transient
517
  * @global int $blog_id
518
  */
519
  public function setup_transient_names() {
523
  * When the caching mechanism changes. Change this value.
524
  * Use hex. e.g. 0, 1, 2, 9, a, b
525
  */
526
+ $sitemap_revision = '4';
527
+ $theme_dir_revision = '1';
528
+ $exclude_revision = '0';
529
 
530
  $this->sitemap_transient = $this->is_option_checked( 'cache_sitemap' ) ? $this->add_cache_key_suffix( 'tsf_sitemap_' . $sitemap_revision ) : '';
531
  $this->theme_doing_it_right_transient = 'tsf_tdir_' . $theme_dir_revision . '_' . $blog_id;
532
+ $this->excluded_post_ids_transient = 'tsf_exclude_' . $exclude_revision . '_' . $blog_id;
533
  }
534
 
535
  /**
566
 
567
  $cache_key = $this->generate_cache_key( $page_id, $taxonomy, $type );
568
 
569
+ $revision = '3';
570
  $additions = $this->add_description_additions( $page_id, $taxonomy );
571
 
572
  if ( $additions ) {
610
 
611
  $cache_key = $this->generate_cache_key( $page_id, $taxonomy, $type );
612
 
613
+ $revision = '6';
614
 
615
  /**
616
  * Change key based on options.
617
  */
618
  $options = $this->enable_ld_json_breadcrumbs() ? '1' : '0';
 
619
  $options .= $this->enable_ld_json_searchbox() ? '1' : '0';
620
 
621
  return 'tsf_' . $revision . '_' . $options . '_ldjs_' . $cache_key;
868
  * @since 2.8.0 1: $locale is now static.
869
  * 2: $key may now be empty.
870
  * @staticvar string $locale
871
+ * @global string $blog_id
872
  *
873
  * @return string the cache key.
874
  */
875
  protected function add_cache_key_suffix( $key = '' ) {
 
876
 
877
  static $locale = null;
878
 
879
  if ( is_null( $locale ) )
880
  $locale = strtolower( \get_locale() );
881
 
882
+ return $key . '_' . $GLOBALS['blog_id'] . '_' . $locale;
883
  }
884
 
885
  /**
1016
  *
1017
  * @since 2.9.1
1018
  * @uses THE_SEO_FRAMEWORK_DB_VERSION as cache key buster.
1019
+ * @uses $this->generate_cache_key_by_type()
1020
+ * @see $this->get_meta_output_cache_key_by_query()
1021
  *
1022
  * @param int $id The ID. Defaults to $this->get_the_real_ID();
1023
  * @param string $taxonomy The term taxonomy
1031
  */
1032
  $key = $this->generate_cache_key_by_type( $id, $taxonomy, $type ) . '_' . THE_SEO_FRAMEWORK_DB_VERSION;
1033
 
1034
+ //= Refers to the first page, always.
1035
+ $_page = $_paged = '1';
1036
 
1037
+ return $cache_key = 'seo_framework_output_' . $key . '_' . $_paged . '_' . $_page;
1038
  }
1039
 
1040
  /**
1059
  *
1060
  * @since 2.3.0
1061
  * @since 2.7.0 : Added admin referer check.
1062
+ * @securitycheck 3.0.0 OK.
1063
  *
1064
  * @return bool Whether if sitemap transient is deleted.
1065
  */
1066
  public function delete_sitemap_transient_permalink_updated() {
1067
 
1068
  if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) {
 
1069
  if ( \check_admin_referer( 'update-permalink' ) )
1070
  return $this->delete_cache( 'sitemap' );
1071
  }
1174
  */
1175
  public function delete_theme_dir_transient( $value = null, $options = null ) {
1176
 
1177
+ if ( isset( $options['type'] ) && 'theme' !== $options['type'] )
1178
+ return false;
 
 
1179
 
1180
  \delete_transient( $this->theme_doing_it_right_transient );
1181
 
1204
  \set_transient( $this->theme_doing_it_right_transient, $dir, 0 );
1205
  }
1206
  }
1207
+
1208
+ /**
1209
+ * Builds and returns the excluded post IDs transient.
1210
+ *
1211
+ * @since 3.0.0
1212
+ * @staticvar array $cache
1213
+ *
1214
+ * @return array : { 'archive', 'search' }
1215
+ */
1216
+ public function get_excluded_ids_from_cache() {
1217
+
1218
+ static $cache = null;
1219
+
1220
+ if ( null === $cache )
1221
+ $cache = $this->get_transient( $this->excluded_post_ids_transient );
1222
+
1223
+ if ( false === $cache ) {
1224
+ global $wpdb;
1225
+ $cache = array();
1226
+
1227
+ //= Two separated equals queries are faster than a single IN with 'meta_key'.
1228
+ $cache['archive'] = $wpdb->get_results(
1229
+ $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '%s'", 'exclude_from_archive' )
1230
+ );
1231
+ $cache['search'] = $wpdb->get_results(
1232
+ $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '%s'", 'exclude_local_search' )
1233
+ );
1234
+
1235
+ foreach ( array( 'archive', 'search' ) as $key ) {
1236
+ array_walk( $cache[ $key ], function( &$v ) {
1237
+ $v = $v->meta_value ? (int) $v->post_id : false;
1238
+ } );
1239
+ $cache[ $key ] = array_filter( $cache[ $key ] );
1240
+ }
1241
+
1242
+ $this->set_transient( $this->excluded_post_ids_transient, $cache );
1243
+ }
1244
+
1245
+ return $cache;
1246
+ }
1247
  }
inc/classes/compat.class.php CHANGED
@@ -43,9 +43,6 @@ class Compat extends Core {
43
 
44
  //* Jetpack compat.
45
  \add_action( 'init', array( $this, 'jetpack_compat' ) );
46
-
47
- //* BuddyPress front-end compat.
48
- \remove_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
49
  }
50
 
51
  /**
@@ -63,36 +60,32 @@ class Compat extends Core {
63
  $this->_include_compat( 'mbstring', 'php' );
64
  }
65
 
 
 
 
 
 
 
 
66
  if ( $this->is_theme( 'genesis' ) ) {
67
  //* Genesis Framework
68
  $this->_include_compat( 'genesis', 'theme' );
69
  }
70
 
71
- if ( defined( 'DOMAIN_MAPPING' ) ) {
72
- if ( $this->detect_plugin( array( 'functions' => array( 'redirect_to_mapped_domain' ) ) ) ) {
73
- //* Donncha domain mapping.
74
- $this->_include_compat( 'donncha-dm', 'plugin' );
75
- } elseif ( $this->detect_plugin( array( 'functions' => array( 'domainmap_launch' ) ) ) ) {
76
- //* WPMUdev domain mapping.
77
- $this->_include_compat( 'wpmudev-dm', 'plugin' );
78
- }
79
- }
80
-
81
- if ( $this->detect_plugin( array( 'globals' => array( 'polylang' ) ) ) ) {
82
- //* PolyLang... it includes compat for WPML, but let's see how this works for now.
83
- $this->_include_compat( 'polylang', 'plugin' );
84
- } elseif ( $this->detect_plugin( array( 'constants' => array( 'ICL_LANGUAGE_CODE' ) ) ) ) {
85
  //* WPML
86
  $this->_include_compat( 'wpml', 'plugin' );
87
- } elseif ( $this->detect_plugin( array( 'constants' => array( 'QTX_VERSION' ) ) ) ) {
88
- //* qTranslate X
89
- $this->_include_compat( 'qtranslatex', 'plugin' );
90
  }
91
 
92
  if ( $this->detect_plugin( array( 'globals' => array( 'ultimatemember' ) ) ) ) {
93
  //* Ultimate Member
94
  $this->_include_compat( 'ultimatemember', 'plugin' );
95
  }
 
 
 
 
 
96
 
97
  if ( $this->detect_plugin( array( 'functions' => array( 'bbpress' ) ) ) ) {
98
  //* bbPress
@@ -118,8 +111,8 @@ class Compat extends Core {
118
 
119
  static $included = array();
120
 
121
- isset( $included[ $what ][ $type ] )
122
- or $included[ $what ][ $type ] = (bool) require_once( THE_SEO_FRAMEWORK_DIR_PATH_COMPAT . $type . '-' . $what . '.php' );
123
 
124
  return $included[ $what ][ $type ];
125
  }
43
 
44
  //* Jetpack compat.
45
  \add_action( 'init', array( $this, 'jetpack_compat' ) );
 
 
 
46
  }
47
 
48
  /**
60
  $this->_include_compat( 'mbstring', 'php' );
61
  }
62
 
63
+ $wp_version = $GLOBALS['wp_version'];
64
+
65
+ if ( version_compare( $wp_version, '4.6', '<' ) ) {
66
+ //* WP 4.6.0
67
+ $this->_include_compat( '460', 'wp' );
68
+ }
69
+
70
  if ( $this->is_theme( 'genesis' ) ) {
71
  //* Genesis Framework
72
  $this->_include_compat( 'genesis', 'theme' );
73
  }
74
 
75
+ if ( $this->detect_plugin( array( 'constants' => array( 'ICL_LANGUAGE_CODE' ) ) ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  //* WPML
77
  $this->_include_compat( 'wpml', 'plugin' );
 
 
 
78
  }
79
 
80
  if ( $this->detect_plugin( array( 'globals' => array( 'ultimatemember' ) ) ) ) {
81
  //* Ultimate Member
82
  $this->_include_compat( 'ultimatemember', 'plugin' );
83
  }
84
+ if ( $this->detect_plugin( array( 'globals' => array( 'bp' ) ) ) ) {
85
+ //* BuddyPress
86
+ $this->_include_compat( 'buddypress', 'plugin' );
87
+
88
+ }
89
 
90
  if ( $this->detect_plugin( array( 'functions' => array( 'bbpress' ) ) ) ) {
91
  //* bbPress
111
 
112
  static $included = array();
113
 
114
+ if ( ! isset( $included[ $what ][ $type ] ) )
115
+ $included[ $what ][ $type ] = (bool) require THE_SEO_FRAMEWORK_DIR_PATH_COMPAT . $type . '-' . $what . '.php';
116
 
117
  return $included[ $what ][ $type ];
118
  }
inc/classes/core.class.php CHANGED
@@ -54,7 +54,7 @@ class Core {
54
  */
55
  final public function __set( $name, $value ) {
56
  /**
57
- * For now, no deprecation is being handled; as no properties are deprecated.
58
  */
59
  $this->_deprecated_function( 'the_seo_framework()->' . \esc_html( $name ), 'unknown' );
60
 
@@ -76,7 +76,7 @@ class Core {
76
 
77
  switch ( $name ) :
78
  case 'pagehook' :
79
- $this->_deprecated_function( 'the_seo_framework()->' . \esc_html( $name ), '2.7.0', 'the_seo_framework()->seo_settings_page_hook' );
80
  return $this->seo_settings_page_hook;
81
  break;
82
 
@@ -120,7 +120,7 @@ class Core {
120
 
121
  if ( $this->the_seo_framework_debug ) {
122
 
123
- $debug_instance = \The_SEO_Framework\Debug::get_instance();
124
 
125
  \add_action( 'the_seo_framework_do_before_output', array( $debug_instance, 'set_debug_query_output_cache' ) );
126
  \add_action( 'admin_footer', array( $debug_instance, 'debug_screens' ) );
@@ -140,9 +140,8 @@ class Core {
140
  protected function clean_response_header() {
141
 
142
  if ( $level = ob_get_level() ) {
143
- while ( $level ) {
144
  ob_end_clean();
145
- $level--;
146
  }
147
  return true;
148
  }
@@ -160,7 +159,7 @@ class Core {
160
  *
161
  * @param string $view The file name.
162
  * @param array $args The arguments to be supplied within the file name.
163
- * Each array key is converted to a variable with its value attached.
164
  * @param string $instance The instance suffix to call back upon.
165
  */
166
  public function get_view( $view, array $args = array(), $instance = 'main' ) {
@@ -170,7 +169,7 @@ class Core {
170
 
171
  $file = THE_SEO_FRAMEWORK_DIR_PATH_VIEWS . $view . '.php';
172
 
173
- include( $file );
174
  }
175
 
176
  /**
@@ -241,6 +240,8 @@ class Core {
241
  *
242
  * @since 2.2.8
243
  * @since 2.9.2 : Added TSFEM link.
 
 
244
  *
245
  * @param array $links The current links.
246
  * @return array The plugin links.
@@ -250,9 +251,9 @@ class Core {
250
  $tsf_links = array();
251
 
252
  if ( $this->load_options )
253
- $tsf_links['settings'] = '<a href="' . \esc_url( \admin_url( 'admin.php?page=' . $this->seo_settings_page_slug ) ) . '">' . \esc_html__( 'SEO Settings', 'autodescription' ) . '</a>';
254
 
255
- $tsf_links['home'] = '<a href="' . \esc_url( 'https://theseoframework.com/' ) . '" rel="noopener" target="_blank">' . \esc_html_x( 'Plugin Home', 'As in: The Plugin Home Page', 'autodescription' ) . '</a>';
256
 
257
  /**
258
  * These are weak checks.
@@ -261,7 +262,7 @@ class Core {
261
  if ( ! defined( 'TSF_EXTENSION_MANAGER_VERSION' ) ) {
262
  $tsfem = \get_plugins( '/the-seo-framework-extension-manager' );
263
  if ( empty( $tsfem ) )
264
- $tsf_links['tsfem'] = '<a href="' . \esc_url( \__( 'https://wordpress.org/plugins/the-seo-framework-extension-manager/', 'autodescription' ) ) . '" rel="noopener" target="_blank">' . \esc_html_x( 'Extensions', 'Plugin extensions', 'autodescription' ) . '</a>';
265
  }
266
 
267
  return array_merge( $tsf_links, $links );
@@ -572,18 +573,32 @@ class Core {
572
  /**
573
  * Returns the minimum role required to adjust settings.
574
  *
575
- * Applies filter 'the_seo_framework_settings_capability' : string
576
- * This filter changes the minimum role for viewing and editing the plugin's settings.
577
- *
578
- * @since 2.6.0
579
- * @access private
580
  *
581
  * @return string The minimum required capability for SEO Settings.
582
  */
583
- public function settings_capability() {
 
 
 
 
 
 
584
  return (string) \apply_filters( 'the_seo_framework_settings_capability', 'manage_options' );
585
  }
586
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  /**
588
  * Returns the SEO Settings page URL.
589
  *
@@ -612,7 +627,7 @@ class Core {
612
  *
613
  * @param bool $guess : If true, the timezone will be guessed from the
614
  * WordPress core gmt_offset option.
615
- * @return string|empty PHP Timezone String.
616
  */
617
  public function get_timezone_string( $guess = false ) {
618
 
@@ -710,6 +725,28 @@ class Core {
710
  return '';
711
  }
712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
713
  /**
714
  * Counts words encounters from input string.
715
  * Case insensitive. Returns first encounter of each word if found multiple times.
54
  */
55
  final public function __set( $name, $value ) {
56
  /**
57
+ * For now, no deprecation is being handled; as no properties have been deprecated.
58
  */
59
  $this->_deprecated_function( 'the_seo_framework()->' . \esc_html( $name ), 'unknown' );
60
 
76
 
77
  switch ( $name ) :
78
  case 'pagehook' :
79
+ $this->_deprecated_function( 'the_seo_framework()->pagehook', '2.7.0', 'the_seo_framework()->seo_settings_page_hook' );
80
  return $this->seo_settings_page_hook;
81
  break;
82
 
120
 
121
  if ( $this->the_seo_framework_debug ) {
122
 
123
+ $debug_instance = Debug::get_instance();
124
 
125
  \add_action( 'the_seo_framework_do_before_output', array( $debug_instance, 'set_debug_query_output_cache' ) );
126
  \add_action( 'admin_footer', array( $debug_instance, 'debug_screens' ) );
140
  protected function clean_response_header() {
141
 
142
  if ( $level = ob_get_level() ) {
143
+ while ( $level-- ) {
144
  ob_end_clean();
 
145
  }
146
  return true;
147
  }
159
  *
160
  * @param string $view The file name.
161
  * @param array $args The arguments to be supplied within the file name.
162
+ * Each array key is converted to a variable with its value attached.
163
  * @param string $instance The instance suffix to call back upon.
164
  */
165
  public function get_view( $view, array $args = array(), $instance = 'main' ) {
169
 
170
  $file = THE_SEO_FRAMEWORK_DIR_PATH_VIEWS . $view . '.php';
171
 
172
+ include $file;
173
  }
174
 
175
  /**
240
  *
241
  * @since 2.2.8
242
  * @since 2.9.2 : Added TSFEM link.
243
+ * @since 3.0.0 : 1. Shortened names.
244
+ * 2. Added noreferrer to the external links.
245
  *
246
  * @param array $links The current links.
247
  * @return array The plugin links.
251
  $tsf_links = array();
252
 
253
  if ( $this->load_options )
254
+ $tsf_links['settings'] = '<a href="' . \esc_url( \admin_url( 'admin.php?page=' . $this->seo_settings_page_slug ) ) . '">' . \esc_html__( 'Settings', 'autodescription' ) . '</a>';
255
 
256
+ $tsf_links['home'] = '<a href="' . \esc_url( 'https://theseoframework.com/' ) . '" rel="noreferrer noopener" target="_blank">' . \esc_html_x( 'Home', 'As in: The Plugin Home Page', 'autodescription' ) . '</a>';
257
 
258
  /**
259
  * These are weak checks.
262
  if ( ! defined( 'TSF_EXTENSION_MANAGER_VERSION' ) ) {
263
  $tsfem = \get_plugins( '/the-seo-framework-extension-manager' );
264
  if ( empty( $tsfem ) )
265
+ $tsf_links['tsfem'] = '<a href="' . \esc_url( \__( 'https://wordpress.org/plugins/the-seo-framework-extension-manager/', 'autodescription' ) ) . '" rel="noreferrer noopener" target="_blank">' . \esc_html_x( 'Extensions', 'Plugin extensions', 'autodescription' ) . '</a>';
266
  }
267
 
268
  return array_merge( $tsf_links, $links );
573
  /**
574
  * Returns the minimum role required to adjust settings.
575
  *
576
+ * @since 3.0.0
 
 
 
 
577
  *
578
  * @return string The minimum required capability for SEO Settings.
579
  */
580
+ public function get_settings_capability() {
581
+ /**
582
+ * Applies filters 'the_seo_framework_settings_capability'
583
+ *
584
+ * @since 2.6.0
585
+ * @string $capability The user capability required to adjust settings.
586
+ */
587
  return (string) \apply_filters( 'the_seo_framework_settings_capability', 'manage_options' );
588
  }
589
 
590
+ /**
591
+ * Determines if the current user can do settings.
592
+ * Not cached as it's imposing security functionality.
593
+ *
594
+ * @since 3.0.0
595
+ *
596
+ * @return bool
597
+ */
598
+ public function can_access_settings() {
599
+ return \current_user_can( $this->get_settings_capability() );
600
+ }
601
+
602
  /**
603
  * Returns the SEO Settings page URL.
604
  *
627
  *
628
  * @param bool $guess : If true, the timezone will be guessed from the
629
  * WordPress core gmt_offset option.
630
+ * @return string PHP Timezone String.
631
  */
632
  public function get_timezone_string( $guess = false ) {
633
 
725
  return '';
726
  }
727
 
728
+ /**
729
+ * Returns timestamp format based on timestamp settings.
730
+ *
731
+ * @since 3.0.0
732
+ *
733
+ * @return string The timestamp format used in PHP date.
734
+ */
735
+ public function get_timestamp_format() {
736
+ return '1' === $this->get_option( 'timestamps_format' ) ? 'Y-m-d\TH:iP' : 'Y-m-d';
737
+ }
738
+
739
+ /**
740
+ * Determines if time is used in the timestamp format.
741
+ *
742
+ * @since 3.0.0
743
+ *
744
+ * @return bool True if time is used. False otherwise.
745
+ */
746
+ public function uses_time_in_timestamp_format() {
747
+ return '1' === $this->get_option( 'timestamps_format' );
748
+ }
749
+
750
  /**
751
  * Counts words encounters from input string.
752
  * Case insensitive. Returns first encounter of each word if found multiple times.
inc/classes/debug.class.php CHANGED
@@ -209,29 +209,29 @@ final class Debug implements Debug_Interface {
209
  * @since 2.8.0 Now escapes all input, except for $message.
210
  * @access private
211
  *
212
- * @param string $function The function that was called.
213
- * @param string $message A message explaining what has been done incorrectly.
214
- * @param string $version The version of WordPress where the message was added.
215
  */
216
  public function _doing_it_wrong( $function, $message, $version = null ) {
217
  /**
218
- * Fires when the given function is being used incorrectly.
219
- *
220
- * @since WP Core 3.1.0
221
- *
222
- * @param string $function The function that was called.
223
- * @param string $message A message explaining what has been done incorrectly.
224
- * @param string $version The version of WordPress where the message was added.
225
- */
226
  \do_action( 'doing_it_wrong_run', $function, $message, $version );
227
 
228
  /**
229
- * Filter whether to trigger an error for _doing_it_wrong() calls.
230
- *
231
- * @since 3.1.0
232
- *
233
- * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
234
- */
235
  if ( WP_DEBUG && \apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
236
 
237
  set_error_handler( array( $this, 'error_handler_doing_it_wrong' ) );
@@ -272,8 +272,8 @@ final class Debug implements Debug_Interface {
272
  *
273
  * @since 2.7.0
274
  *
275
- * @param string $p_or_m The Property or Method.
276
- * @param string $message A message explaining what has been done incorrectly.
277
  */
278
  \do_action( 'the_seo_framework_inaccessible_p_or_m_run', $p_or_m, $message );
279
 
@@ -451,8 +451,7 @@ final class Debug implements Debug_Interface {
451
  * @return bool True if there's output.
452
  */
453
  public static function has_debug_output() {
454
- $instance = static::get_instance();
455
- return (bool) $instance->debug_output;
456
  }
457
 
458
  /**
@@ -462,11 +461,8 @@ final class Debug implements Debug_Interface {
462
  * @access private
463
  */
464
  public static function _output_debug() {
465
-
466
- $instance = static::get_instance();
467
  //* Already escaped.
468
- echo $instance->debug_output;
469
-
470
  }
471
 
472
  /**
@@ -864,11 +860,8 @@ final class Debug implements Debug_Interface {
864
  * @access private
865
  */
866
  public static function _output_debug_header() {
867
-
868
- $instance = static::get_instance();
869
  //* Already escaped.
870
- echo $instance->get_debug_header_output();
871
-
872
  }
873
 
874
  /**
209
  * @since 2.8.0 Now escapes all input, except for $message.
210
  * @access private
211
  *
212
+ * @param string $function The function that was called.
213
+ * @param string $message A message explaining what has been done incorrectly.
214
+ * @param string $version The version of WordPress where the message was added.
215
  */
216
  public function _doing_it_wrong( $function, $message, $version = null ) {
217
  /**
218
+ * Fires when the given function is being used incorrectly.
219
+ *
220
+ * @since WP Core 3.1.0
221
+ *
222
+ * @param string $function The function that was called.
223
+ * @param string $message A message explaining what has been done incorrectly.
224
+ * @param string $version The version of WordPress where the message was added.
225
+ */
226
  \do_action( 'doing_it_wrong_run', $function, $message, $version );
227
 
228
  /**
229
+ * Filter whether to trigger an error for _doing_it_wrong() calls.
230
+ *
231
+ * @since 3.1.0
232
+ *
233
+ * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
234
+ */
235
  if ( WP_DEBUG && \apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
236
 
237
  set_error_handler( array( $this, 'error_handler_doing_it_wrong' ) );
272
  *
273
  * @since 2.7.0
274
  *
275
+ * @param string $p_or_m The Property or Method.
276
+ * @param string $message A message explaining what has been done incorrectly.
277
  */
278
  \do_action( 'the_seo_framework_inaccessible_p_or_m_run', $p_or_m, $message );
279
 
451
  * @return bool True if there's output.
452
  */
453
  public static function has_debug_output() {
454
+ return (bool) static::get_instance()->debug_output;
 
455
  }
456
 
457
  /**
461
  * @access private
462
  */
463
  public static function _output_debug() {
 
 
464
  //* Already escaped.
465
+ echo static::get_instance()->debug_output;
 
466
  }
467
 
468
  /**
860
  * @access private
861
  */
862
  public static function _output_debug_header() {
 
 
863
  //* Already escaped.
864
+ echo static::get_instance()->get_debug_header_output();
 
865
  }
866
 
867
  /**
inc/classes/deprecated.class.php CHANGED
@@ -1,1290 +1,2012 @@
1
- <?php
2
- /**
3
- * @package The_SEO_Framework\Classes\Deprecated
4
- */
5
- namespace The_SEO_Framework;
6
-
7
- defined( 'ABSPATH' ) or die;
8
-
9
- /**
10
- * The SEO Framework plugin
11
- * Copyright (C) 2015 - 2017 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
15
- * by the Free Software Foundation.
16
- *
17
- * This program is distributed in the hope that it will be useful,
18
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
- * GNU General Public License for more details.
21
- *
22
- * You should have received a copy of the GNU General Public License
23
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
24
- */
25
-
26
- defined( 'ABSPATH' ) or die;
27
-
28
- /**
29
- * Class The_SEO_Framework\Deprecated
30
- *
31
- * Contains all deprecated functions.
32
- *
33
- * @since 2.8.0
34
- */
35
- final class Deprecated {
36
-
37
- /**
38
- * Constructor. Does nothing.
39
- */
40
- public function __construct() { }
41
-
42
- /**
43
- * HomePage Metabox General Tab Output.
44
- *
45
- * @since 2.6.0
46
- * @see $this->homepage_metabox() Callback for HomePage Settings box.
47
- *
48
- * @deprecated
49
- * @since 2.7.0
50
- */
51
- public function homepage_metabox_general() {
52
- \the_seo_framework()->_deprecated_function( 'The_SEO_Framework_Metaboxes::' . __FUNCTION__, '2.7.0', 'The_SEO_Framework_Metaboxes::homepage_metabox_general_tab()' );
53
- \the_seo_framework()->get_view( 'metaboxes/homepage-metabox', array(), 'general' );
54
- }
55
-
56
- /**
57
- * HomePage Metabox Additions Tab Output.
58
- *
59
- * @since 2.6.0
60
- * @see $this->homepage_metabox() Callback for HomePage Settings box.
61
- *
62
- * @deprecated
63
- * @since 2.7.0
64
- */
65
- public function homepage_metabox_additions() {
66
- \the_seo_framework()->_deprecated_function( 'The_SEO_Framework_Metaboxes::' . __FUNCTION__, '2.7.0', 'The_SEO_Framework_Metaboxes::homepage_metabox_additions_tab()' );
67
- \the_seo_framework()->get_view( 'metaboxes/homepage-metabox', array(), 'additions' );
68
- }
69
-
70
- /**
71
- * HomePage Metabox Robots Tab Output
72
- *
73
- * @since 2.6.0
74
- * @see $this->homepage_metabox() Callback for HomePage Settings box.
75
- *
76
- * @deprecated
77
- * @since 2.7.0
78
- */
79
- public function homepage_metabox_robots() {
80
- \the_seo_framework()->_deprecated_function( 'The_SEO_Framework_Metaboxes::' . __FUNCTION__, '2.7.0', 'The_SEO_Framework_Metaboxes::homepage_metabox_robots_tab()' );
81
- \the_seo_framework()->get_view( 'metaboxes/homepage-metabox', array(), 'robots' );
82
- }
83
-
84
- /**
85
- * Delete transient for the automatic description for blog on save request.
86
- * Returns old option, since that's passed for sanitation within WP Core.
87
- *
88
- * @since 2.3.3
89
- *
90
- * @deprecated
91
- * @since 2.7.0
92
- *
93
- * @param string $old_option The previous blog description option.
94
- * @return string Previous option.
95
- */
96
- public function delete_auto_description_blog_transient( $old_option ) {
97
-
98
- \the_seo_framework()->_deprecated_function( 'The_SEO_Framework_Transients::' . __FUNCTION__, '2.7.0', 'The_SEO_Framework_Transients::delete_auto_description_frontpage_transient()' );
99
-
100
- \the_seo_framework()->delete_auto_description_transient( \the_seo_framework()->get_the_front_page_ID(), '', 'frontpage' );
101
-
102
- return $old_option;
103
- }
104
-
105
- /**
106
- * Add term meta data into options table of the term.
107
- * Adds separated database options for terms, as the terms table doesn't allow for addition.
108
- *
109
- * Applies filters array the_seo_framework_term_meta_defaults : Array of default term SEO options
110
- * Applies filters mixed the_seo_framework_term_meta_{field} : Override filter for specifics.
111
- * Applies filters array the_seo_framework_term_meta : Override output for term or taxonomy.
112
- *
113
- * @since 2.1.8
114
- *
115
- * @deprecated silently.
116
- * @since WordPress 4.4.0
117
- * @since The SEO Framework 2.7.0
118
- * @since 2.8.0: Deprecated visually.
119
- *
120
- * @param object $term Database row object.
121
- * @param string $taxonomy Taxonomy name that $term is part of.
122
- * @return object $term Database row object.
123
- */
124
- public function get_term_filter( $term, $taxonomy ) {
125
-
126
- \the_seo_framework()->_deprecated_function( 'The_SEO_Framework_Transients::' . __FUNCTION__, '2.7.0', 'WordPress Core "get_term_meta()"' );
127
-
128
- return false;
129
- }