SmartCrawl SEO - Version 2.2.5

Version Description

  • New: New filters for modifying OpenGraph values
  • New: Improved accuracy of readability analysis

  • Fix: Missing columns on the post list page

  • Fix: Certain websites throwing 404 error on redirection

  • Fix: SEO metabox shown for non-public posts

  • Fix: Better Gutenberg compatibility

  • Fix: Warning on sitemap settings page

  • Fix: Added ability to increase analysis request timeout

  • Fix: Improved autoloader performance

  • Fix: Warning in metabox placeholder loader

  • Fix: Inaccurate preview when more recent post revision available

  • Fix: Update the AIOSEOP importer to include the latest version

  • Fix: Stylesheet URL incorrect in sub-site sitemaps

Download this release

Release Info

Developer khaxan
Plugin Icon 128x128 SmartCrawl SEO
Version 2.2.5
Comparing to
See all releases

Code changes from version 2.2.4.1 to 2.2.5

autoloader.php CHANGED
@@ -1,22 +1,38 @@
1
  <?php
2
 
3
- function smartcrawl_autoload( $class ) {
4
- $mappings_file = dirname( __FILE__ ) . '/class-mappings.php';
5
- if ( ! file_exists( $mappings_file ) ) {
6
- return;
7
- }
 
 
 
8
 
9
- $class_mappings = include $mappings_file;
10
- if ( ! isset( $class_mappings[ $class ] ) ) {
11
- return;
12
  }
13
 
14
- $class_path = untrailingslashit( SMARTCRAWL_PLUGIN_DIR ) . $class_mappings[ $class ];
15
- if ( ! file_exists( $class_path ) ) {
16
- return;
 
 
 
17
  }
18
 
19
- include $class_path;
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
- spl_autoload_register( 'smartcrawl_autoload' );
1
  <?php
2
 
3
+ class Smartcrawl_Autoloader {
4
+ private static $class_mappings = array();
5
+
6
+ private static function load_from_file() {
7
+ $mappings_file = dirname( __FILE__ ) . '/class-mappings.php';
8
+ if ( file_exists( $mappings_file ) ) {
9
+ return include $mappings_file;
10
+ }
11
 
12
+ return array();
 
 
13
  }
14
 
15
+ private static function get_class_mappings() {
16
+ if ( empty( self::$class_mappings ) ) {
17
+ self::$class_mappings = self::load_from_file();
18
+ }
19
+
20
+ return self::$class_mappings;
21
  }
22
 
23
+ public static function autoload( $class ) {
24
+ $class_mappings = self::get_class_mappings();
25
+ if ( ! isset( $class_mappings[ $class ] ) ) {
26
+ return;
27
+ }
28
+
29
+ $class_path = untrailingslashit( SMARTCRAWL_PLUGIN_DIR ) . $class_mappings[ $class ];
30
+ if ( ! file_exists( $class_path ) ) {
31
+ return;
32
+ }
33
+
34
+ include $class_path;
35
+ }
36
  }
37
 
38
+ spl_autoload_register( array( 'Smartcrawl_Autoloader', 'autoload' ) );
changelog.txt CHANGED
@@ -2,6 +2,23 @@ Plugin Name: SmartCrawl SEO
2
 
3
  Change Log:
4
  ----------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  2.2.4.1 - 2018-12-11
6
  ----------------------------------------------------------------------
7
  - Fix: Show the WP.org rating request to admins only
2
 
3
  Change Log:
4
  ----------------------------------------------------------------------
5
+ 2.2.5 - 2019-02-18
6
+ ----------------------------------------------------------------------
7
+ - Add: New filters for modifying OpenGraph values
8
+ - Add: Improved accuracy of readability analysis
9
+
10
+ - Fix: Missing columns on the post list page
11
+ - Fix: Certain websites throwing 404 error on redirection
12
+ - Fix: SEO metabox shown for non-public posts
13
+ - Fix: Better Gutenberg compatibility
14
+ - Fix: Warning on sitemap settings page
15
+ - Fix: Added ability to increase analysis request timeout
16
+ - Fix: Improved autoloader performance
17
+ - Fix: Warning in metabox placeholder loader
18
+ - Fix: Inaccurate preview when more recent post revision available
19
+ - Fix: Update the AIOSEOP importer to include the latest version
20
+ - Fix: Stylesheet URL incorrect in sub-site sitemaps
21
+
22
  2.2.4.1 - 2018-12-11
23
  ----------------------------------------------------------------------
24
  - Fix: Show the WP.org rating request to admins only
config.php CHANGED
@@ -82,6 +82,9 @@ if ( ! defined( 'SMARTCRAWL_WHITELABEL_ON' ) ) {
82
  if ( ! defined( 'SMARTCRAWL_OMIT_PORT_MATCHES' ) ) {
83
  define( 'SMARTCRAWL_OMIT_PORT_MATCHES', false );
84
  }
 
 
 
85
 
86
  /**
87
  * Setup plugin path and url.
82
  if ( ! defined( 'SMARTCRAWL_OMIT_PORT_MATCHES' ) ) {
83
  define( 'SMARTCRAWL_OMIT_PORT_MATCHES', false );
84
  }
85
+ if ( ! defined( 'SMARTCRAWL_ANALYSIS_REQUEST_TIMEOUT' ) ) {
86
+ define( 'SMARTCRAWL_ANALYSIS_REQUEST_TIMEOUT', 5 );
87
+ }
88
 
89
  /**
90
  * Setup plugin path and url.
includes/admin/metabox.php CHANGED
@@ -98,10 +98,17 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
98
  return;
99
  }
100
 
101
- $latest_post_version = smartcrawl_get_latest_post_version( $post_id );
 
 
 
 
 
 
 
102
  $result['success'] = true;
103
  $result['markup'] = $this->_load( 'metabox/metabox-preview', array(
104
- 'post' => $latest_post_version,
105
  ) );
106
 
107
  wp_send_json( $result );
@@ -127,8 +134,8 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
127
  ) );
128
  Smartcrawl_Settings_Admin::register_global_admin_scripts();
129
  wp_enqueue_script( 'wds_metabox_onpage', SMARTCRAWL_PLUGIN_URL . '/js/wds-metabox.js', array(
 
130
  'wds-select2',
131
- 'autosave',
132
  ), $version );
133
  wp_localize_script( 'wds_metabox_onpage', '_wds_metabox', array(
134
  'nonce' => wp_create_nonce( 'wds-metabox-nonce' ),
@@ -160,7 +167,7 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
160
  /**
161
  * Handles actual metabox rendering
162
  */
163
- public function smartcrawl_meta_boxes($post) {
164
  $robots_noindex_value = (int) smartcrawl_get_value( 'meta-robots-noindex' );
165
  $robots_nofollow_value = (int) smartcrawl_get_value( 'meta-robots-nofollow' );
166
  $robots_index_value = (int) smartcrawl_get_value( 'meta-robots-index' );
@@ -206,11 +213,14 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
206
  if ( function_exists( 'add_meta_box' ) ) {
207
  // Show branding for singular installs.
208
  $metabox_title = is_multisite() ? __( 'SmartCrawl', 'wds' ) : 'SmartCrawl';
209
- $post_types = get_post_types(array(
210
  'show_ui' => true, // Only if it actually supports WP UI.
211
- ));
 
212
  foreach ( $post_types as $posttype ) {
213
- if ( 'attachment' === $posttype ) { continue; }
 
 
214
  if ( $show ) {
215
  add_meta_box( 'wds-wds-meta-box', $metabox_title, array(
216
  &$this,
@@ -408,10 +418,12 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
408
  * @return array
409
  */
410
  public function smartcrawl_page_title_column_heading( $columns ) {
 
 
411
  return array_merge(
412
- array_slice( $columns, 0, 2 ),
413
  array( 'page-title' => __( 'Title Tag', 'wds' ) ),
414
- array_slice( $columns, 2, 6 ),
415
  array( 'page-meta-robots' => __( 'Robots Meta', 'wds' ) )
416
  );
417
  }
@@ -553,29 +565,32 @@ class Smartcrawl_Metabox extends Smartcrawl_Renderable {
553
  * Handle metabox live update requests
554
  */
555
  public function smartcrawl_metabox_live_update() {
 
556
  $data = $this->get_request_data();
557
- $id = (int) $data['id'];
558
- $post = get_post( $id );
559
-
560
- $post_data = sanitize_post( $data['post'] );
561
-
562
- /* Merge live post data with currently saved post data */
563
- $post->post_author = $post_data['post_author'];
564
- $post->post_title = $post_data['post_title'];
565
- $post->post_excerpt = $post_data['excerpt'];
566
- $post->post_content = $post_data['content'];
567
- $post->post_type = $post_data['post_type'];
568
-
569
- $title = smartcrawl_get_seo_title( $post );
570
- $description = smartcrawl_get_seo_desc( $post );
571
-
572
- wp_send_json( array(
573
- 'title' => $title,
574
- 'description' => $description,
575
- 'focus' => smartcrawl_get_value( 'focus-keywords', $id ),
576
- 'keywords' => smartcrawl_get_value( 'keywords', $id ),
577
- ) );
 
578
 
 
579
  die();
580
  }
581
 
98
  return;
99
  }
100
 
101
+ $is_dirty = (boolean) smartcrawl_get_array_value( $data, 'is_dirty' );
102
+ /**
103
+ * If there is_dirty flag is set i.e. are unsaved changes in the editor then we
104
+ * will fetch the latest post revision and preview that.
105
+ */
106
+ $post_to_preview = $is_dirty
107
+ ? smartcrawl_get_latest_post_version( $post_id )
108
+ : get_post( $post_id );
109
  $result['success'] = true;
110
  $result['markup'] = $this->_load( 'metabox/metabox-preview', array(
111
+ 'post' => $post_to_preview,
112
  ) );
113
 
114
  wp_send_json( $result );
134
  ) );
135
  Smartcrawl_Settings_Admin::register_global_admin_scripts();
136
  wp_enqueue_script( 'wds_metabox_onpage', SMARTCRAWL_PLUGIN_URL . '/js/wds-metabox.js', array(
137
+ 'underscore',
138
  'wds-select2',
 
139
  ), $version );
140
  wp_localize_script( 'wds_metabox_onpage', '_wds_metabox', array(
141
  'nonce' => wp_create_nonce( 'wds-metabox-nonce' ),
167
  /**
168
  * Handles actual metabox rendering
169
  */
170
+ public function smartcrawl_meta_boxes( $post ) {
171
  $robots_noindex_value = (int) smartcrawl_get_value( 'meta-robots-noindex' );
172
  $robots_nofollow_value = (int) smartcrawl_get_value( 'meta-robots-nofollow' );
173
  $robots_index_value = (int) smartcrawl_get_value( 'meta-robots-index' );
213
  if ( function_exists( 'add_meta_box' ) ) {
214
  // Show branding for singular installs.
215
  $metabox_title = is_multisite() ? __( 'SmartCrawl', 'wds' ) : 'SmartCrawl';
216
+ $post_types = get_post_types( array(
217
  'show_ui' => true, // Only if it actually supports WP UI.
218
+ 'public' => true, // ... and is public
219
+ ) );
220
  foreach ( $post_types as $posttype ) {
221
+ if ( 'attachment' === $posttype ) {
222
+ continue;
223
+ }
224
  if ( $show ) {
225
  add_meta_box( 'wds-wds-meta-box', $metabox_title, array(
226
  &$this,
418
  * @return array
419
  */
420
  public function smartcrawl_page_title_column_heading( $columns ) {
421
+ $title_idx = array_search( 'title', array_keys( $columns ) );
422
+ $title_idx = ! empty( $title_idx ) ? $title_idx + 1 : 2;
423
  return array_merge(
424
+ array_slice( $columns, 0, $title_idx ),
425
  array( 'page-title' => __( 'Title Tag', 'wds' ) ),
426
+ array_slice( $columns, $title_idx, count( $columns ) ),
427
  array( 'page-meta-robots' => __( 'Robots Meta', 'wds' ) )
428
  );
429
  }
565
  * Handle metabox live update requests
566
  */
567
  public function smartcrawl_metabox_live_update() {
568
+ $response = array();
569
  $data = $this->get_request_data();
570
+ $id = (int) smartcrawl_get_array_value( $data, 'id' );
571
+ if ( $id ) {
572
+ $post = get_post( $id );
573
+
574
+ $post_data = sanitize_post( $data['post'] );
575
+
576
+ /* Merge live post data with currently saved post data */
577
+ $post->post_author = $post_data['post_author'];
578
+ $post->post_title = $post_data['post_title'];
579
+ $post->post_excerpt = $post_data['excerpt'];
580
+ $post->post_content = $post_data['content'];
581
+ $post->post_type = $post_data['post_type'];
582
+
583
+ $title = smartcrawl_get_seo_title( $post );
584
+ $description = smartcrawl_get_seo_desc( $post );
585
+ $response = array(
586
+ 'title' => $title,
587
+ 'description' => $description,
588
+ 'focus' => smartcrawl_get_value( 'focus-keywords', $id ),
589
+ 'keywords' => smartcrawl_get_value( 'keywords', $id ),
590
+ );
591
+ }
592
 
593
+ wp_send_json( $response );
594
  die();
595
  }
596
 
includes/admin/templates/sitemap/sitemap-settings.php CHANGED
@@ -4,6 +4,7 @@ $sitemap_tab_name = __( 'Sitemap', 'wds' );
4
  $url_crawler_tab_id = 'tab_url_crawler';
5
  $url_crawler_tab_name = __( 'URL Crawler', 'wds' );
6
  $crawl_url = Smartcrawl_Sitemap_Settings::crawl_url();
 
7
  ?>
8
 
9
  <div id="container" class="wrap wrap-wds wds-page wds-sitemap-settings">
@@ -13,7 +14,6 @@ $crawl_url = Smartcrawl_Sitemap_Settings::crawl_url();
13
  <div class="actions">
14
  <?php if ( Smartcrawl_Settings::get_setting( 'sitemap' ) ) { ?>
15
  <?php
16
- $service = Smartcrawl_Service::get( Smartcrawl_Service::SERVICE_SEO );
17
  $end = $service->get_last_run_timestamp();
18
  $end = ! empty( $end ) && is_numeric( $end )
19
  ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $end )
4
  $url_crawler_tab_id = 'tab_url_crawler';
5
  $url_crawler_tab_name = __( 'URL Crawler', 'wds' );
6
  $crawl_url = Smartcrawl_Sitemap_Settings::crawl_url();
7
+ $service = Smartcrawl_Service::get( Smartcrawl_Service::SERVICE_SEO );
8
  ?>
9
 
10
  <div id="container" class="wrap wrap-wds wds-page wds-sitemap-settings">
14
  <div class="actions">
15
  <?php if ( Smartcrawl_Settings::get_setting( 'sitemap' ) ) { ?>
16
  <?php
 
17
  $end = $service->get_last_run_timestamp();
18
  $end = ! empty( $end ) && is_numeric( $end )
19
  ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $end )
includes/core/checks/class-wds-check-slug-keywords.php CHANGED
@@ -12,7 +12,7 @@ class Smartcrawl_Check_Slug_Keywords extends Smartcrawl_Check_Post_Abstract {
12
 
13
  public function apply() {
14
  $text = $this->get_markup();
15
- $subject = join( ' ', preg_split( '/[-_]/', $text ) );
16
 
17
  $this->_state = $this->has_focus( $subject );
18
 
12
 
13
  public function apply() {
14
  $text = $this->get_markup();
15
+ $subject = join( ' ', preg_split( '/[\-_]/', $text ) );
16
 
17
  $this->_state = $this->has_focus( $subject );
18
 
includes/core/class-wds-aioseop-importer.php CHANGED
@@ -13,6 +13,7 @@ class Smartcrawl_AIOSEOP_Importer extends Smartcrawl_Importer {
13
  'aioseop_options/modules/aiosp_opengraph_options/aiosp_opengraph_hometitle' => 'home_og_fields_enabled',
14
  'aioseop_options/modules/aiosp_opengraph_options/aiosp_opengraph_description' => 'home_og_fields_enabled',
15
  );
 
16
  // phpcs:enable
17
 
18
  public function data_exists() {
@@ -23,7 +24,10 @@ class Smartcrawl_AIOSEOP_Importer extends Smartcrawl_Importer {
23
  return false;
24
  }
25
 
26
- return strpos( $version, '2.9' ) === 0;
 
 
 
27
  }
28
 
29
  public function import_options() {
13
  'aioseop_options/modules/aiosp_opengraph_options/aiosp_opengraph_hometitle' => 'home_og_fields_enabled',
14
  'aioseop_options/modules/aiosp_opengraph_options/aiosp_opengraph_description' => 'home_og_fields_enabled',
15
  );
16
+
17
  // phpcs:enable
18
 
19
  public function data_exists() {
24
  return false;
25
  }
26
 
27
+ return apply_filters(
28
+ 'wds-import-aioseop-data-exists',
29
+ strpos( $version, '2.11' ) === 0
30
+ );
31
  }
32
 
33
  public function import_options() {
includes/core/class-wds-controller-analysis.php CHANGED
@@ -445,13 +445,17 @@ class Smartcrawl_Controller_Analysis extends Smartcrawl_Renderable {
445
  return;
446
  }
447
 
 
 
 
448
  /**
449
- * Since this code might be running as a result of an auto-save, we will use the latest post revision
450
- * to run a fresh analysis.
451
  */
452
- $latest_post_version = smartcrawl_get_latest_post_version( (int) $data['post_id'] );
453
- $this->analyze_post( $latest_post_version->ID );
454
- $post = get_post( (int) $data['post_id'] );
 
455
 
456
  $out = array();
457
  ob_start();
445
  return;
446
  }
447
 
448
+ $is_dirty = (boolean) smartcrawl_get_array_value( $data, 'is_dirty' );
449
+ $post_id = (int) smartcrawl_get_array_value( $data, 'post_id' );
450
+ $post = get_post( $post_id );
451
  /**
452
+ * If there is_dirty flag is set i.e. are unsaved changes in the editor then we
453
+ * will fetch the latest post revision and analyze that.
454
  */
455
+ $post_to_analyze = $is_dirty
456
+ ? smartcrawl_get_latest_post_version( $post_id )
457
+ : $post;
458
+ $this->analyze_post( $post_to_analyze->ID );
459
 
460
  $out = array();
461
  ob_start();
includes/core/class-wds-core-request.php CHANGED
@@ -63,14 +63,15 @@ class Smartcrawl_Core_Request {
63
  }
64
  $hasher = new PasswordHash( 8, true );
65
  $cookies[] = new WP_Http_Cookie( array(
66
- 'name' => 'wp-postpass_' . COOKIEHASH,
67
  'value' => $hasher->HashPassword( $post->post_password ),
68
- ));
69
  }
70
 
71
  if ( ! empty( $cookies ) ) {
72
  $params['cookies'] = $cookies;
73
  }
 
74
 
75
  $response = wp_remote_get( $url, $params );
76
 
@@ -88,4 +89,10 @@ class Smartcrawl_Core_Request {
88
 
89
  return (string) trim( join( "\n", $bits ) );
90
  }
 
 
 
 
 
 
91
  }
63
  }
64
  $hasher = new PasswordHash( 8, true );
65
  $cookies[] = new WP_Http_Cookie( array(
66
+ 'name' => 'wp-postpass_' . COOKIEHASH,
67
  'value' => $hasher->HashPassword( $post->post_password ),
68
+ ) );
69
  }
70
 
71
  if ( ! empty( $cookies ) ) {
72
  $params['cookies'] = $cookies;
73
  }
74
+ $params['timeout'] = $this->get_timeout();
75
 
76
  $response = wp_remote_get( $url, $params );
77
 
89
 
90
  return (string) trim( join( "\n", $bits ) );
91
  }
92
+
93
+ private function get_timeout() {
94
+ return defined( 'SMARTCRAWL_ANALYSIS_REQUEST_TIMEOUT' )
95
+ ? SMARTCRAWL_ANALYSIS_REQUEST_TIMEOUT
96
+ : 5;
97
+ }
98
  }
includes/core/class-wds-model-redirection.php CHANGED
@@ -21,6 +21,14 @@ class Smartcrawl_Model_Redirection extends Smartcrawl_Model {
21
  public function get_redirection( $source, $fallback = false ) {
22
  $redirections = $this->get_all_redirections();
23
 
 
 
 
 
 
 
 
 
24
  return ! empty( $redirections[ $source ] )
25
  ? $redirections[ $source ]
26
  : $fallback;
@@ -209,18 +217,12 @@ class Smartcrawl_Model_Redirection extends Smartcrawl_Model {
209
  $protocol = is_ssl() ? 'https:' : 'http:';
210
  $domain = $_SERVER['HTTP_HOST'];
211
 
212
- $port = (int) $_SERVER['SERVER_PORT'] ? ':' . (int) $_SERVER['SERVER_PORT'] : '';
213
- if ( is_ssl() && 443 === (int) $_SERVER['SERVER_PORT'] ) {
214
- $port = '';
215
- }
216
- if ( ! is_ssl() && 80 === (int) $_SERVER['SERVER_PORT'] ) {
217
- $port = '';
218
- }
219
- if ( smartcrawl_is_switch_active( 'SMARTCRAWL_OMIT_PORT_MATCHES' ) ) {
220
- $port = '';
221
- }
222
 
223
- $request = $_SERVER['REQUEST_URI'];
224
 
225
  $source = $protocol . '//' . $domain . $port . $request;
226
 
@@ -230,6 +232,22 @@ class Smartcrawl_Model_Redirection extends Smartcrawl_Model {
230
  );
231
  }
232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  public function get_type() {
234
  return 'redirection';
235
  }
21
  public function get_redirection( $source, $fallback = false ) {
22
  $redirections = $this->get_all_redirections();
23
 
24
+ $source = in_array( trailingslashit( $source ), array_keys( $redirections ) )
25
+ ? trailingslashit( $source )
26
+ : ( in_array( untrailingslashit( $source ), array_keys( $redirections ) )
27
+ ? untrailingslashit( $source )
28
+ : $source
29
+ )
30
+ ;
31
+
32
  return ! empty( $redirections[ $source ] )
33
  ? $redirections[ $source ]
34
  : $fallback;
217
  $protocol = is_ssl() ? 'https:' : 'http:';
218
  $domain = $_SERVER['HTTP_HOST'];
219
 
220
+ $port = smartcrawl_is_switch_active( 'SMARTCRAWL_OMIT_PORT_MATCHES' )
221
+ ? ''
222
+ : $this->get_current_request_port()
223
+ ;
 
 
 
 
 
 
224
 
225
+ $request = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
226
 
227
  $source = $protocol . '//' . $domain . $port . $request;
228
 
232
  );
233
  }
234
 
235
+ /**
236
+ * Fetches the current request port
237
+ *
238
+ * @return int|string Port number or empty string
239
+ */
240
+ public function get_current_request_port() {
241
+ $port = (int) $_SERVER['SERVER_PORT'] ? ':' . (int) $_SERVER['SERVER_PORT'] : '';
242
+ if ( is_ssl() && 443 === (int) $_SERVER['SERVER_PORT'] ) {
243
+ $port = '';
244
+ }
245
+ if ( ! is_ssl() && 80 === (int) $_SERVER['SERVER_PORT'] ) {
246
+ $port = '';
247
+ }
248
+ return $port;
249
+ }
250
+
251
  public function get_type() {
252
  return 'redirection';
253
  }
includes/core/class-wds-opengraph-value-helper.php CHANGED
@@ -12,15 +12,17 @@ class Smartcrawl_OpenGraph_Value_Helper extends Smartcrawl_Type_Traverser {
12
  }
13
 
14
  public function get_title() {
15
- return $this->title;
16
  }
17
 
18
  public function get_description() {
19
- return $this->description;
20
  }
21
 
22
  public function get_images() {
23
- return array_unique( array_map( 'trim', $this->images ) );
 
 
24
  }
25
 
26
  public function is_enabled() {
@@ -67,7 +69,7 @@ class Smartcrawl_OpenGraph_Value_Helper extends Smartcrawl_Type_Traverser {
67
 
68
  // Add featured image as the last resort
69
  if ( has_post_thumbnail( $post ) ) {
70
- $this->images[] = get_the_post_thumbnail_url($post);
71
  }
72
 
73
  $this->enabled = ! $disabled;
12
  }
13
 
14
  public function get_title() {
15
+ return apply_filters( 'wds_custom_og_title', $this->title );
16
  }
17
 
18
  public function get_description() {
19
+ return apply_filters( 'wds_custom_og_description', $this->description );
20
  }
21
 
22
  public function get_images() {
23
+ $images = array_unique( array_map( 'trim', $this->images ) );
24
+
25
+ return apply_filters( 'wds_custom_og_image', $images );
26
  }
27
 
28
  public function is_enabled() {
69
 
70
  // Add featured image as the last resort
71
  if ( has_post_thumbnail( $post ) ) {
72
+ $this->images[] = get_the_post_thumbnail_url( $post );
73
  }
74
 
75
  $this->enabled = ! $disabled;
includes/core/class-wds-renderable.php CHANGED
@@ -28,7 +28,7 @@ abstract class Smartcrawl_Renderable {
28
  * @return mixed (string)View output on success, (bool)false on failure
29
  */
30
  protected function _load( $view, $args = array() ) {
31
- $view = preg_replace( '/[^-_a-z0-9\/]/i', '', $view );
32
  if ( empty( $view ) ) {
33
  return false;
34
  }
28
  * @return mixed (string)View output on success, (bool)false on failure
29
  */
30
  protected function _load( $view, $args = array() ) {
31
+ $view = preg_replace( '/[^\-_a-z0-9\/]/i', '', $view );
32
  if ( empty( $view ) ) {
33
  return false;
34
  }
includes/core/class-wds-string.php CHANGED
@@ -260,7 +260,7 @@ class Smartcrawl_String {
260
  * -2 for encoding issue
261
  */
262
  public static function syllables_count( $text ) {
263
- $syls = array();
264
 
265
  if ( empty( $text ) ) {
266
  return - 1;
@@ -268,21 +268,73 @@ class Smartcrawl_String {
268
  $words = self::words( $text );
269
 
270
  foreach ( $words as $word ) {
271
- $word = preg_replace( '/[^a-z]/', '', $word );
272
- if ( empty( $word ) ) {
273
- continue;
274
- } // Nothing here.
275
- $word = preg_replace( '/^[aeiouy]|[aeiouy]$/', '', $word );
276
- $tmp = preg_split( '/[aeiouy]+/', $word, null, PREG_SPLIT_NO_EMPTY );
277
- if ( 2 === count( $tmp ) && strlen( $word ) <= 4 ) {
278
- $tmp = array( $word );
279
- } // Simple threshold approximation.
280
- $syls = array_merge( $syls, $tmp );
281
  }
282
- if ( count( $syls ) === 0 /*|| count($syls) === count($words)*/ ) {
283
  return - 2;
284
  } // Well that didn't work...
285
- return count( $syls );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  }
287
 
288
  /**
260
  * -2 for encoding issue
261
  */
262
  public static function syllables_count( $text ) {
263
+ $syls = 0;
264
 
265
  if ( empty( $text ) ) {
266
  return - 1;
268
  $words = self::words( $text );
269
 
270
  foreach ( $words as $word ) {
271
+ $syllables_count_word = self::syllables_count_word( $word );
272
+ $syls += $syllables_count_word;
 
 
 
 
 
 
 
 
273
  }
274
+ if ( $syls === 0 ) {
275
  return - 2;
276
  } // Well that didn't work...
277
+
278
+ return $syls;
279
+ }
280
+
281
+ /**
282
+ * Uses the method on https://howmanysyllables.com/howtocountsyllables
283
+ *
284
+ * @param $word
285
+ *
286
+ * @return int
287
+ */
288
+ private static function syllables_count_word( $word ) {
289
+ $word = trim( $word );
290
+ $unacceptable = (boolean) preg_match_all( '/[^a-zA-Z]/', $word );
291
+ if ( $unacceptable ) {
292
+ return 0;
293
+ }
294
+
295
+ $length = strlen( $word );
296
+ if ( $length < 3 ) {
297
+ // e.g. we, to, a
298
+ return 1;
299
+ }
300
+
301
+ // Count the number of vowels (A, E, I, O, U) in the word.
302
+ // Add 1 every time the letter 'y' makes the sound of a vowel
303
+ $syllables = preg_match_all( '/[aeiouy]/', $word );
304
+
305
+ // Subtract 1 for each silent vowel (like the silent 'e' at the end of a word).
306
+ $ends_with_e = self::ends_with( $word, 'e' );
307
+ $syllables -= $ends_with_e ? 1 : 0;
308
+
309
+ if ( $ends_with_e && $length === 3 ) {
310
+ // e.g. the, eve, axe
311
+ return 1;
312
+ }
313
+
314
+ // Subtract 1 for each diphthong
315
+ $diphthongs = preg_match_all( '/[aeiouy]{2}/', $word );
316
+ $syllables -= $diphthongs;
317
+
318
+ // Subtract 1 for each triphthong
319
+ $triphthongs = preg_match_all( '/[aeiouy]{3}/', $word );
320
+ $syllables -= $triphthongs;
321
+
322
+ // Does the word end with "le" or "les?" Add 1 only if the letter before the "le" is a consonant.
323
+ $ends_with_le = (boolean) preg_match_all( '/[^aeiouy]le|les$/', $word );
324
+ $syllables += $ends_with_le ? 1 : 0;
325
+
326
+ return $syllables <= 0
327
+ ? 0
328
+ : $syllables;
329
+ }
330
+
331
+ public static function ends_with( $haystack, $needle ) {
332
+ $length = strlen( $needle );
333
+ if ( $length == 0 ) {
334
+ return true;
335
+ }
336
+
337
+ return ( substr( $haystack, - $length ) === $needle );
338
  }
339
 
340
  /**
includes/core/class-wds-yoast-importer.php CHANGED
@@ -21,7 +21,10 @@ class Smartcrawl_Yoast_Importer extends Smartcrawl_Importer {
21
  return false;
22
  }
23
 
24
- return strpos( $version, '9.' ) === 0;
 
 
 
25
  }
26
 
27
  public function import_options() {
21
  return false;
22
  }
23
 
24
+ return apply_filters(
25
+ 'wds-import-yoast-data-exists',
26
+ strpos( $version, '9.' ) === 0
27
+ );
28
  }
29
 
30
  public function import_options() {
includes/core/core.php CHANGED
@@ -756,7 +756,19 @@ function smartcrawl_kill_stuck_transient( $key ) {
756
  * @return bool
757
  */
758
  function smartcrawl_is_switch_active( $switch ) {
759
- return defined( $switch ) ? constant( $switch ) : false;
 
 
 
 
 
 
 
 
 
 
 
 
760
  }
761
 
762
  /**
756
  * @return bool
757
  */
758
  function smartcrawl_is_switch_active( $switch ) {
759
+ $result = defined( $switch ) ? constant( $switch ) : false;
760
+
761
+ /**
762
+ * Checks if a define switch is toggled on
763
+ *
764
+ * Used in tests.
765
+ *
766
+ * @param bool $result Whether the switch is turned on.
767
+ * @param string $switch Switch name.
768
+ *
769
+ * @return bool
770
+ */
771
+ return (bool) apply_filters( 'smartcrawl_switch_active', $result, $switch );
772
  }
773
 
774
  /**
includes/external/simple_html_dom.php CHANGED
@@ -680,7 +680,7 @@ class simple_html_dom_node
680
  // This implies that an html attribute specifier may start with an @ sign that is NOT captured by the expression.
681
  // farther study is required to determine of this should be documented or removed.
682
  // $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
683
- $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
684
  preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
685
  if (is_object($debugObject)) {$debugObject->debugLog(2, "Matches Array: ", $matches);}
686
 
@@ -886,7 +886,7 @@ class simple_html_dom_node
886
  {
887
  // Thanks to user gnarf from stackoverflow for this regular expression.
888
  $attributes = array();
889
- preg_match_all("/([\w-]+)\s*:\s*([^;]+)\s*;?/", $this->attr['style'], $matches, PREG_SET_ORDER);
890
  foreach ($matches as $match) {
891
  $attributes[$match[1]] = $match[2];
892
  }
@@ -1361,7 +1361,7 @@ class simple_html_dom
1361
  return true;
1362
  }
1363
 
1364
- if (!preg_match("/^[\w-:]+$/", $tag)) {
1365
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1366
  if ($this->char==='<') {
1367
  $this->link_nodes($node, false);
@@ -1718,4 +1718,4 @@ class simple_html_dom
1718
  function loadFile() {$args = func_get_args();$this->load_file($args);}
1719
  }
1720
 
1721
- ?>
680
  // This implies that an html attribute specifier may start with an @ sign that is NOT captured by the expression.
681
  // farther study is required to determine of this should be documented or removed.
682
  // $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
683
+ $pattern = "/([\w\-:\*]*)(?:\#([\w\-]+)|\.([\w\-]+))?(?:\[@?(!?[\w\-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
684
  preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
685
  if (is_object($debugObject)) {$debugObject->debugLog(2, "Matches Array: ", $matches);}
686
 
886
  {
887
  // Thanks to user gnarf from stackoverflow for this regular expression.
888
  $attributes = array();
889
+ preg_match_all("/([\w\-]+)\s*:\s*([^;]+)\s*;?/", $this->attr['style'], $matches, PREG_SET_ORDER);
890
  foreach ($matches as $match) {
891
  $attributes[$match[1]] = $match[2];
892
  }
1361
  return true;
1362
  }
1363
 
1364
+ if (!preg_match("/^[\w\-:]+$/", $tag)) {
1365
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
1366
  if ($this->char==='<') {
1367
  $this->link_nodes($node, false);
1718
  function loadFile() {$args = func_get_args();$this->load_file($args);}
1719
  }
1720
 
1721
+ ?>
includes/js/wds-metabox.js CHANGED
@@ -5,51 +5,110 @@
5
  *
6
  * @param {Object} e Event object (optional)
7
  */
8
- function render_fields_change (e) {
9
  var $currentTarget = $(e.currentTarget),
10
- field = false,
11
- value = false;
 
12
 
13
- if($currentTarget.is('#title')) {
14
- field = 'title';
15
- } else if($currentTarget.is('#content') || $currentTarget.is('#excerpt')) {
16
- field = 'desc';
17
  }
18
 
19
- if( field ){
20
- $.post(ajaxurl, {
21
- id: wp.autosave.getPostData().post_id,
22
- action: "wds_metabox_update",
23
- post: wp.autosave.getPostData(),
24
- _wds_nonce: _wds_metabox.nonce
25
- }, 'json').done(function (rsp) {
26
- var description = (rsp || {}).description || '',
27
- title = (rsp || {}).title || '';
28
- $('#wds_title').attr('placeholder',title);
29
- $('#wds_metadesc').attr('placeholder',description);
30
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  function refresh_meta_field_placeholders() {
36
- // The following line will trigger a call to ajax wds_metabox_update
37
- $('input#title').trigger('input');
 
 
 
 
38
  }
39
 
40
- function init () {
41
  window.setTimeout( function() {
42
  var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
43
  if( editor ) {
44
  editor.on('change', function(e) {
45
  e.currentTarget = $('#content');
46
- _.debounce(render_fields_change.bind(e), 1000);
47
  });
48
  }
49
  }, 1000 );
50
- $(document).on("input","input#title,textarea#content,textarea#excerpt",_.debounce(render_fields_change, 1000)).trigger('input');
 
51
 
52
- $('.wds-horizontal-tab-nav').on('click', '.wds-nav-item', function(){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  $('.wds-horizontal-tab-nav .active').removeClass('active');
54
  $(this).addClass('active');
55
  });
@@ -66,6 +125,14 @@
66
  // Boot
67
  $(init);
68
 
 
 
 
 
 
 
 
 
69
  /**
70
  * Deal with SEO analysis updates
71
  */
@@ -80,7 +147,8 @@
80
 
81
  var data = $.extend({
82
  action: 'wds-analysis-get-editor-analysis',
83
- post_id: wp.autosave.getPostData().post_id,
 
84
  wds_title: title,
85
  wds_description: description,
86
  wds_focus_keywords: focus_keywords,
@@ -132,24 +200,43 @@
132
 
133
  function handle_refresh_click() {
134
  before_ajax_request_blocking();
 
 
 
 
 
 
135
 
136
- var cback = function () {
 
137
  handle_autosave();
138
  // Re-hook our regular autosave handler
139
  $(document).on('after-autosave.smartcrawl', handle_autosave);
140
  };
 
 
 
 
 
 
 
 
141
  var editorSync = (tinyMCE || {}).triggerSave;
142
  if (editorSync) {
143
  editorSync();
144
  }
145
- var save = (((wp || {}).autosave || {}).server || {}).triggerSave;
146
- if (save) {
147
- // We are already hooked to autosave so let's disable our regular autosave handler momentarily to avoid multiple calls ...
148
- $(document).off('after-autosave.smartcrawl');
149
- // hook a new handler to heartbeat-tick.autosave
150
- $(document).one('heartbeat-tick.autosave', cback);
 
 
 
 
151
  wp.autosave.server.triggerSave();
152
- } else cback();
153
  }
154
 
155
  function before_ajax_request_blocking() {
@@ -243,7 +330,7 @@
243
  ;
244
  return $.post(ajaxurl, {
245
  action: action,
246
- post_id: wp.autosave.getPostData().post_id,
247
  check_id: check_id,
248
  _wds_nonce: _wds_metabox.nonce
249
  }, 'json');
@@ -299,6 +386,7 @@
299
  wds_title: title,
300
  wds_description: description,
301
  post_id: post_id,
 
302
  _wds_nonce: _wds_metabox.nonce
303
  }, 'json').done(function (data) {
304
  if ((data || {}).success) {
@@ -311,12 +399,50 @@
311
  });
312
  }
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  function init_analysis () {
315
  window.render_update = render_update;
316
  window.Wds.dismissible_message();
317
 
318
  $(document)
319
- .on('after-autosave.smartcrawl', handle_autosave)
 
320
  .on('click', '#wds-wds-meta-box .wds-ignore', handle_ignore_toggle)
321
  .on('click', '#wds-wds-meta-box .wds-unignore', handle_ignore_toggle)
322
  .on('click', '#wds-wds-meta-box a[href="#reload"]', handle_update)
@@ -340,7 +466,10 @@
340
  }
341
  });
342
 
343
- handle_page_load();
 
 
 
344
 
345
  // Set metabox state on page load based on cookie value.
346
  // Fixes: https://app.asana.com/0/0/580085427092951/f
5
  *
6
  * @param {Object} e Event object (optional)
7
  */
8
+ function classic_post_fields_change_handler (e) {
9
  var $currentTarget = $(e.currentTarget),
10
+ field = $currentTarget.is('#title')
11
+ || $currentTarget.is('#content')
12
+ || $currentTarget.is('#excerpt');
13
 
14
+ if( field ){
15
+ refresh_meta_field_placeholders_ajax();
 
 
16
  }
17
 
18
+ }
19
+
20
+ function refresh_meta_field_placeholders_ajax() {
21
+ $.post(ajaxurl, {
22
+ id: get_post_data().post_id,
23
+ action: "wds_metabox_update",
24
+ post: get_post_data(),
25
+ _wds_nonce: _wds_metabox.nonce
26
+ }, 'json').done(function (rsp) {
27
+ var description = (rsp || {}).description || '',
28
+ title = (rsp || {}).title || '';
29
+
30
+ $('#wds_title').attr('placeholder', title);
31
+ $('#wds_metadesc').attr('placeholder', description);
32
+ });
33
+ }
34
+
35
+ function is_classic_editor_active() {
36
+ return $('input#title').length && (wp || {}).autosave;
37
+ }
38
+
39
+ function is_gutenberg_active() {
40
+ var data = (wp || {}).data;
41
+ return data && data.select && data.dispatch;
42
+ }
43
+
44
+ function get_post_data() {
45
+ if (is_gutenberg_active()) {
46
+ return get_gutenberg_data();
47
+ } else if (is_classic_editor_active()) {
48
+ return wp.autosave.getPostData();
49
  }
50
 
51
+ return {};
52
+ }
53
+
54
+ function get_gutenberg_data() {
55
+ var fields = ['content', 'excerpt', 'post_author', 'post_id', 'post_title', 'post_type'],
56
+ data = {};
57
+
58
+ _.each(fields, function (field) {
59
+ data[field] = wp.data.select("core/editor").getEditedPostAttribute(field.replace('post_', '')) || '';
60
+ });
61
+
62
+ if (!data.post_id) {
63
+ data.post_id = $('#post_ID').val() || 0;
64
+ }
65
+
66
+ return data;
67
  }
68
 
69
  function refresh_meta_field_placeholders() {
70
+ if (is_classic_editor_active()) {
71
+ // The following line will trigger a call to ajax wds_metabox_update
72
+ $('input#title').trigger('input');
73
+ } else {
74
+ refresh_meta_field_placeholders_ajax();
75
+ }
76
  }
77
 
78
+ function hook_classic_editor_listeners() {
79
  window.setTimeout( function() {
80
  var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
81
  if( editor ) {
82
  editor.on('change', function(e) {
83
  e.currentTarget = $('#content');
84
+ _.debounce(classic_post_fields_change_handler.bind(e), 1000);
85
  });
86
  }
87
  }, 1000 );
88
+ $(document).on("input","input#title,textarea#content,textarea#excerpt",_.debounce(classic_post_fields_change_handler, 1000)).trigger('input');
89
+ }
90
 
91
+ function hook_gutenberg_listeners() {
92
+ if (!is_gutenberg_active()) {
93
+ return;
94
+ }
95
+
96
+ var debounced = _.debounce(refresh_meta_field_placeholders_ajax, 5000);
97
+ wp.data.subscribe(function () {
98
+ if (wp.data.select("core/editor").isEditedPostDirty()) {
99
+ debounced();
100
+ }
101
+ });
102
+ }
103
+
104
+ function init() {
105
+ if (is_gutenberg_active()) {
106
+ hook_gutenberg_listeners();
107
+ } else if (is_classic_editor_active()) {
108
+ hook_classic_editor_listeners();
109
+ }
110
+
111
+ $('.wds-horizontal-tab-nav').on('click', '.wds-nav-item', function () {
112
  $('.wds-horizontal-tab-nav .active').removeClass('active');
113
  $(this).addClass('active');
114
  });
125
  // Boot
126
  $(init);
127
 
128
+ function is_edited_post_dirty() {
129
+ if (is_gutenberg_active()) {
130
+ return wp.data.select("core/editor").isEditedPostDirty();
131
+ } else {
132
+ return wp.autosave.server.postChanged();
133
+ }
134
+ }
135
+
136
  /**
137
  * Deal with SEO analysis updates
138
  */
147
 
148
  var data = $.extend({
149
  action: 'wds-analysis-get-editor-analysis',
150
+ post_id: get_post_data().post_id,
151
+ is_dirty: is_edited_post_dirty() ? 1 : 0,
152
  wds_title: title,
153
  wds_description: description,
154
  wds_focus_keywords: focus_keywords,
200
 
201
  function handle_refresh_click() {
202
  before_ajax_request_blocking();
203
+ if (is_classic_editor_active()) {
204
+ hook_to_heartbeat();
205
+ trigger_tinymce_save();
206
+ }
207
+ trigger_autosave();
208
+ }
209
 
210
+ function hook_to_heartbeat() {
211
+ var handle_heartbeat = function () {
212
  handle_autosave();
213
  // Re-hook our regular autosave handler
214
  $(document).on('after-autosave.smartcrawl', handle_autosave);
215
  };
216
+
217
+ // We are already hooked to autosave so let's disable our regular autosave handler momentarily to avoid multiple calls ...
218
+ $(document).off('after-autosave.smartcrawl');
219
+ // hook a new handler to heartbeat-tick.autosave
220
+ $(document).one('heartbeat-tick.autosave', handle_heartbeat);
221
+ }
222
+
223
+ function trigger_tinymce_save() {
224
  var editorSync = (tinyMCE || {}).triggerSave;
225
  if (editorSync) {
226
  editorSync();
227
  }
228
+ }
229
+
230
+ function trigger_autosave() {
231
+ if (is_gutenberg_active()) {
232
+ if (wp.data.select("core/editor").isEditedPostAutosaveable()) {
233
+ wp.data.dispatch("core/editor").autosave();
234
+ } else {
235
+ trigger_custom_autosave_event();
236
+ }
237
+ } else if (is_classic_editor_active()) {
238
  wp.autosave.server.triggerSave();
239
+ }
240
  }
241
 
242
  function before_ajax_request_blocking() {
330
  ;
331
  return $.post(ajaxurl, {
332
  action: action,
333
+ post_id: get_post_data().post_id,
334
  check_id: check_id,
335
  _wds_nonce: _wds_metabox.nonce
336
  }, 'json');
386
  wds_title: title,
387
  wds_description: description,
388
  post_id: post_id,
389
+ is_dirty: is_edited_post_dirty() ? 1 : 0,
390
  _wds_nonce: _wds_metabox.nonce
391
  }, 'json').done(function (data) {
392
  if ((data || {}).success) {
399
  });
400
  }
401
 
402
+ function register_api_fetch_middleware() {
403
+ if (!(wp || {}).apiFetch) {
404
+ return;
405
+ }
406
+
407
+ wp.apiFetch.use(function (options, next) {
408
+ var result = next(options);
409
+ result.then(function () {
410
+ if (is_autosave_request(options) || is_post_save_request(options)) {
411
+ trigger_custom_autosave_event();
412
+ }
413
+ });
414
+
415
+ return result;
416
+ });
417
+ }
418
+
419
+ function is_autosave_request(request) {
420
+ return request && request.path
421
+ && request.path.includes('/autosaves');
422
+ }
423
+
424
+ function is_post_save_request(request) {
425
+ var post = get_post_data(),
426
+ post_id = post.post_id,
427
+ post_type = post.post_type;
428
+
429
+ return request && request.path
430
+ && request.method === 'PUT'
431
+ && request.path.includes('/' + post_id)
432
+ && request.path.includes('/' + post_type);
433
+ }
434
+
435
+ function trigger_custom_autosave_event() {
436
+ $(document).trigger('wds-after-autosave');
437
+ }
438
+
439
  function init_analysis () {
440
  window.render_update = render_update;
441
  window.Wds.dismissible_message();
442
 
443
  $(document)
444
+ .on('after-autosave.smartcrawl', trigger_custom_autosave_event)
445
+ .on('wds-after-autosave', handle_autosave)
446
  .on('click', '#wds-wds-meta-box .wds-ignore', handle_ignore_toggle)
447
  .on('click', '#wds-wds-meta-box .wds-unignore', handle_ignore_toggle)
448
  .on('click', '#wds-wds-meta-box a[href="#reload"]', handle_update)
466
  }
467
  });
468
 
469
+ $(window)
470
+ .on('load', handle_page_load)
471
+ .on('load', register_api_fetch_middleware)
472
+ ;
473
 
474
  // Set metabox state on page load based on cookie value.
475
  // Fixes: https://app.asana.com/0/0/580085427092951/f
includes/tools/onpage.php CHANGED
@@ -670,7 +670,7 @@ class Smartcrawl_OnPage {
670
  // News keywords.
671
  $resolver = $this->get_resolver();
672
  $news_meta = $resolver->is_singular() ? stripslashes( smartcrawl_get_value( 'news_keywords' ) ) : false;
673
- $news_meta = trim( preg_replace( '/\s\s+/', ' ', preg_replace( '/[^-_,a-z0-9 ]/i', ' ', $news_meta ) ) );
674
  if ( $news_meta ) {
675
  echo '<meta name="news_keywords" content="' . esc_attr( $news_meta ) . '" />' . "\n";
676
  }
670
  // News keywords.
671
  $resolver = $this->get_resolver();
672
  $news_meta = $resolver->is_singular() ? stripslashes( smartcrawl_get_value( 'news_keywords' ) ) : false;
673
+ $news_meta = trim( preg_replace( '/\s\s+/', ' ', preg_replace( '/[^\-_,a-z0-9 ]/i', ' ', $news_meta ) ) );
674
  if ( $news_meta ) {
675
  echo '<meta name="news_keywords" content="' . esc_attr( $news_meta ) . '" />' . "\n";
676
  }
includes/tools/sitemaps.php CHANGED
@@ -286,7 +286,7 @@ class Smartcrawl_Xml_Sitemap {
286
  * Loads all items that will get into a sitemap.
287
  */
288
  private function _load_all_items() {
289
- $this->_add_item( home_url('/'), 1, 'daily' ); // Home URL.
290
  $this->_load_post_items();
291
  $this->_load_taxonomy_items();
292
  // Load BuddyPress-specific items.
@@ -676,20 +676,9 @@ class Smartcrawl_Xml_Sitemap {
676
  * @return string
677
  */
678
  private function _get_stylesheet( $xsl ) {
679
- if ( is_multisite() && defined( 'SUBDOMAIN_INSTALL' ) && ! SUBDOMAIN_INSTALL ) {
680
- $plugin_host = wp_parse_url( SMARTCRAWL_PLUGIN_URL, PHP_URL_HOST );
681
- $xsl_host = preg_replace(
682
- '/^https?:\/\/' . preg_quote( $plugin_host . '/', '/' ) . '/',
683
- '', SMARTCRAWL_PLUGIN_URL
684
- );
685
- $xsl_host = '../' . $xsl_host;
686
-
687
- return "<?xml-stylesheet type='text/xml' href='{$xsl_host}admin/templates/xsl/{$xsl}.xsl'?>\n";
688
- } else {
689
- $plugin_dir_url = plugin_dir_url( dirname( __FILE__ ) );
690
 
691
- return "<?xml-stylesheet type='text/xml' href='{$plugin_dir_url}admin/templates/xsl/{$xsl}.xsl'?>\n";
692
- }
693
  }
694
 
695
  /**
286
  * Loads all items that will get into a sitemap.
287
  */
288
  private function _load_all_items() {
289
+ $this->_add_item( home_url( '/' ), 1, 'daily' ); // Home URL.
290
  $this->_load_post_items();
291
  $this->_load_taxonomy_items();
292
  // Load BuddyPress-specific items.
676
  * @return string
677
  */
678
  private function _get_stylesheet( $xsl ) {
679
+ $plugin_dir_url = SMARTCRAWL_PLUGIN_URL;
 
 
 
 
 
 
 
 
 
 
680
 
681
+ return "<?xml-stylesheet type='text/xml' href='{$plugin_dir_url}admin/templates/xsl/{$xsl}.xsl'?>\n";
 
682
  }
683
 
684
  /**
includes/tools/video-sitemaps.php CHANGED
@@ -280,7 +280,7 @@ class Smartcrawl_Xml_VideoSitemap {
280
  }
281
 
282
  $post = get_post( $post_id );
283
- $src = preg_match( '#(http://wordpress.tv/[-_/.a-z0-9]+)#i', $post->post_content, $matches );
284
  if ( empty( $matches[1] ) ) {
285
  return false;
286
  }
280
  }
281
 
282
  $post = get_post( $post_id );
283
+ $src = preg_match( '#(http://wordpress.tv/[\-_/.a-z0-9]+)#i', $post->post_content, $matches );
284
  if ( empty( $matches[1] ) ) {
285
  return false;
286
  }
languages/wds.pot CHANGED
@@ -1,17 +1,18 @@
1
- # Copyright (C) 2018 WPMU DEV
2
  # This file is distributed under the same license as the SmartCrawl package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: SmartCrawl 2.2.4.1\n"
6
- "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/wpmu-dev-seo\n"
7
- "POT-Creation-Date: 2018-12-11 04:55:00+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
- "X-Generator: grunt-wp-i18n1.0.2\n"
15
 
16
  #: includes/admin/admin.php:134 includes/admin/settings/settings.php:248
17
  #: includes/admin/settings/settings.php:319
@@ -43,84 +44,84 @@ msgstr ""
43
  msgid "You can fix this here"
44
  msgstr ""
45
 
46
- #: includes/admin/metabox.php:119
47
  msgid "{TOTAL_LEFT} characters left"
48
  msgstr ""
49
 
50
- #: includes/admin/metabox.php:120
51
  msgid "Over {MAX_COUNT} characters ({CURRENT_COUNT})"
52
  msgstr ""
53
 
54
- #: includes/admin/metabox.php:121
55
  msgid ""
56
  "Over {MAX_COUNT} characters ({CURRENT_COUNT}) - make sure your SEO title is "
57
  "shorter"
58
  msgstr ""
59
 
60
- #: includes/admin/metabox.php:137
61
  #: includes/admin/templates/metabox/analysis-readability.php:67
62
  #: includes/admin/templates/metabox/analysis-seo-analysis.php:24
63
  msgid "Analyzing content, please wait a few moments"
64
  msgstr ""
65
 
66
- #: includes/admin/metabox.php:170
67
  msgid "NO ODP (Block Open Directory Project description of the page)"
68
  msgstr ""
69
 
70
- #: includes/admin/metabox.php:171
71
  msgid "NO YDIR (Don't display the Yahoo! Directory titles and abstracts)"
72
  msgstr ""
73
 
74
- #: includes/admin/metabox.php:172 includes/admin/metabox.php:457
75
  msgid "No Archive"
76
  msgstr ""
77
 
78
- #: includes/admin/metabox.php:173 includes/admin/metabox.php:458
79
  msgid "No Snippet"
80
  msgstr ""
81
 
82
- #: includes/admin/metabox.php:176
83
  msgid "Automatic prioritization"
84
  msgstr ""
85
 
86
- #: includes/admin/metabox.php:177
87
  msgid "1 - Highest priority"
88
  msgstr ""
89
 
90
- #: includes/admin/metabox.php:179
91
  msgid "High priority (root pages default)"
92
  msgstr ""
93
 
94
- #: includes/admin/metabox.php:181
95
  msgid "Secondary priority (subpages default)"
96
  msgstr ""
97
 
98
- #: includes/admin/metabox.php:182
99
  msgid "Medium priority"
100
  msgstr ""
101
 
102
- #: includes/admin/metabox.php:186
103
  msgid "Lowest priority"
104
  msgstr ""
105
 
106
- #: includes/admin/metabox.php:413
107
  #: includes/admin/templates/quick-edit-title.php:5
108
  msgid "Title Tag"
109
  msgstr ""
110
 
111
- #: includes/admin/metabox.php:415
112
  msgid "Robots Meta"
113
  msgstr ""
114
 
115
- #: includes/admin/metabox.php:436
116
  msgid "Redirects to %s"
117
  msgstr ""
118
 
119
- #: includes/admin/metabox.php:455
120
  msgid "No ODP"
121
  msgstr ""
122
 
123
- #: includes/admin/metabox.php:456
124
  msgid "No YDIR"
125
  msgstr ""
126
 
@@ -1186,7 +1187,7 @@ msgstr ""
1186
  #: includes/admin/templates/dashboard/dashboard-content-analysis-seo-overview.php:32
1187
  #: includes/admin/templates/dashboard/dashboard-content-analysis-seo-overview.php:57
1188
  #: includes/admin/templates/post-list/post-seo-analysis-good.php:2
1189
- #: includes/core/class-wds-controller-analysis.php:638
1190
  msgid "Good"
1191
  msgstr ""
1192
 
@@ -3987,19 +3988,19 @@ msgstr ""
3987
  msgid "N/A"
3988
  msgstr ""
3989
 
3990
- #: includes/core/class-wds-controller-analysis.php:632
3991
  msgid "No Focus Keyword"
3992
  msgstr ""
3993
 
3994
- #: includes/core/class-wds-controller-analysis.php:635
3995
  msgid "Needs Improvement"
3996
  msgstr ""
3997
 
3998
- #: includes/core/class-wds-controller-analysis.php:657
3999
  msgid "SEO:"
4000
  msgstr ""
4001
 
4002
- #: includes/core/class-wds-controller-analysis.php:664
4003
  msgid "Readability:"
4004
  msgstr ""
4005
 
1
+ # Copyright (C) 2019 WPMU DEV
2
  # This file is distributed under the same license as the SmartCrawl package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: SmartCrawl 2.2.5\n"
6
+ "Report-Msgid-Bugs-To: "
7
+ "https://wordpress.org/support/plugin/smartcrawl-regular\n"
8
+ "POT-Creation-Date: 2019-04-12 06:10:23+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "X-Generator: grunt-wp-i18n 1.0.3\n"
16
 
17
  #: includes/admin/admin.php:134 includes/admin/settings/settings.php:248
18
  #: includes/admin/settings/settings.php:319
44
  msgid "You can fix this here"
45
  msgstr ""
46
 
47
+ #: includes/admin/metabox.php:126
48
  msgid "{TOTAL_LEFT} characters left"
49
  msgstr ""
50
 
51
+ #: includes/admin/metabox.php:127
52
  msgid "Over {MAX_COUNT} characters ({CURRENT_COUNT})"
53
  msgstr ""
54
 
55
+ #: includes/admin/metabox.php:128
56
  msgid ""
57
  "Over {MAX_COUNT} characters ({CURRENT_COUNT}) - make sure your SEO title is "
58
  "shorter"
59
  msgstr ""
60
 
61
+ #: includes/admin/metabox.php:144
62
  #: includes/admin/templates/metabox/analysis-readability.php:67
63
  #: includes/admin/templates/metabox/analysis-seo-analysis.php:24
64
  msgid "Analyzing content, please wait a few moments"
65
  msgstr ""
66
 
67
+ #: includes/admin/metabox.php:177
68
  msgid "NO ODP (Block Open Directory Project description of the page)"
69
  msgstr ""
70
 
71
+ #: includes/admin/metabox.php:178
72
  msgid "NO YDIR (Don't display the Yahoo! Directory titles and abstracts)"
73
  msgstr ""
74
 
75
+ #: includes/admin/metabox.php:179 includes/admin/metabox.php:469
76
  msgid "No Archive"
77
  msgstr ""
78
 
79
+ #: includes/admin/metabox.php:180 includes/admin/metabox.php:470
80
  msgid "No Snippet"
81
  msgstr ""
82
 
83
+ #: includes/admin/metabox.php:183
84
  msgid "Automatic prioritization"
85
  msgstr ""
86
 
87
+ #: includes/admin/metabox.php:184
88
  msgid "1 - Highest priority"
89
  msgstr ""
90
 
91
+ #: includes/admin/metabox.php:186
92
  msgid "High priority (root pages default)"
93
  msgstr ""
94
 
95
+ #: includes/admin/metabox.php:188
96
  msgid "Secondary priority (subpages default)"
97
  msgstr ""
98
 
99
+ #: includes/admin/metabox.php:189
100
  msgid "Medium priority"
101
  msgstr ""
102
 
103
+ #: includes/admin/metabox.php:193
104
  msgid "Lowest priority"
105
  msgstr ""
106
 
107
+ #: includes/admin/metabox.php:425
108
  #: includes/admin/templates/quick-edit-title.php:5
109
  msgid "Title Tag"
110
  msgstr ""
111
 
112
+ #: includes/admin/metabox.php:427
113
  msgid "Robots Meta"
114
  msgstr ""
115
 
116
+ #: includes/admin/metabox.php:448
117
  msgid "Redirects to %s"
118
  msgstr ""
119
 
120
+ #: includes/admin/metabox.php:467
121
  msgid "No ODP"
122
  msgstr ""
123
 
124
+ #: includes/admin/metabox.php:468
125
  msgid "No YDIR"
126
  msgstr ""
127
 
1187
  #: includes/admin/templates/dashboard/dashboard-content-analysis-seo-overview.php:32
1188
  #: includes/admin/templates/dashboard/dashboard-content-analysis-seo-overview.php:57
1189
  #: includes/admin/templates/post-list/post-seo-analysis-good.php:2
1190
+ #: includes/core/class-wds-controller-analysis.php:642
1191
  msgid "Good"
1192
  msgstr ""
1193
 
3988
  msgid "N/A"
3989
  msgstr ""
3990
 
3991
+ #: includes/core/class-wds-controller-analysis.php:636
3992
  msgid "No Focus Keyword"
3993
  msgstr ""
3994
 
3995
+ #: includes/core/class-wds-controller-analysis.php:639
3996
  msgid "Needs Improvement"
3997
  msgstr ""
3998
 
3999
+ #: includes/core/class-wds-controller-analysis.php:661
4000
  msgid "SEO:"
4001
  msgstr ""
4002
 
4003
+ #: includes/core/class-wds-controller-analysis.php:668
4004
  msgid "Readability:"
4005
  msgstr ""
4006
 
readme.txt CHANGED
@@ -6,8 +6,8 @@ Tags: SEO, Search Engine Optimization, Sitemap, PageRank, website ranking, SEO t
6
  Author URI: https://premium.wpmudev.org/
7
  Author: WPMU DEV
8
  Requires at least: 4.6
9
- Tested up to: 5.0
10
- Stable tag: 2.2.4.1
11
 
12
  The SEO checker and optimization tool that helps you rank higher and get discovered in search engines.
13
 
@@ -59,7 +59,7 @@ Love SmartCrawl! WPMU DEV has some other awesome free plugins you should checkou
59
  - [Hustle](https://wordpress.org/plugins/wordpress-popup/) - Pop-ups, Slide-ins and Email Opt-ins
60
  - [Defender](https://wordpress.org/plugins/defender-security/) - Security, Monitoring, and Hack Protection
61
 
62
- And if you want scheduled SEO scans, reports, automatic keyword linking and access to our suite of site management tools you can always take the next step with a [WPMU DEV Membership](https://premium.wpmudev.org/project/smartcrawl-wordpress-seo/). Give it a go free for 30 days.
63
 
64
  == Frequently Asked Questions ==
65
 
@@ -86,6 +86,23 @@ SmartCrawl works with any normal WP content and page builders shouldn’t be an
86
 
87
  == Changelog ==
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  = 2.2.4.1 =
90
 
91
  * Fix: Show the WP.org rating request to admins only
@@ -300,9 +317,9 @@ SmartCrawl works with any normal WP content and page builders shouldn’t be an
300
 
301
  == About Us ==
302
  WPMU DEV is a premium supplier of quality WordPress plugins, services and support. Join us here:
303
- [https://premium.wpmudev.org/](https://premium.wpmudev.org/?utm_source=wordpress.org&utm_medium=readme)
304
 
305
  Don't forget to stay up to date on everything WordPress from the Internet's number one resource:
306
- [WPMU DEV Blog](https://premium.wpmudev.org/blog/?utm_source=wordpress.org&utm_medium=readme)
307
 
308
  Hey, one more thing... we hope you enjoy our [free offerings](http://profiles.wordpress.org/WPMUDEV/) as much as we've loved making them for you!
6
  Author URI: https://premium.wpmudev.org/
7
  Author: WPMU DEV
8
  Requires at least: 4.6
9
+ Tested up to: 5.1
10
+ Stable tag: 2.2.5
11
 
12
  The SEO checker and optimization tool that helps you rank higher and get discovered in search engines.
13
 
59
  - [Hustle](https://wordpress.org/plugins/wordpress-popup/) - Pop-ups, Slide-ins and Email Opt-ins
60
  - [Defender](https://wordpress.org/plugins/defender-security/) - Security, Monitoring, and Hack Protection
61
 
62
+ And if you want scheduled SEO scans, reports, automatic keyword linking and access to our suite of site management tools you can always take the next step with a [WPMU DEV Membership](https://premium.wpmudev.org/project/smartcrawl-wordpress-seo/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=smartcrawl-readme&utm_content=wpmu_dev_membership#trial). Give it a go free for 30 days.
63
 
64
  == Frequently Asked Questions ==
65
 
86
 
87
  == Changelog ==
88
 
89
+ = 2.2.5 =
90
+
91
+ * New: New filters for modifying OpenGraph values
92
+ * New: Improved accuracy of readability analysis
93
+
94
+ * Fix: Missing columns on the post list page
95
+ * Fix: Certain websites throwing 404 error on redirection
96
+ * Fix: SEO metabox shown for non-public posts
97
+ * Fix: Better Gutenberg compatibility
98
+ * Fix: Warning on sitemap settings page
99
+ * Fix: Added ability to increase analysis request timeout
100
+ * Fix: Improved autoloader performance
101
+ * Fix: Warning in metabox placeholder loader
102
+ * Fix: Inaccurate preview when more recent post revision available
103
+ * Fix: Update the AIOSEOP importer to include the latest version
104
+ * Fix: Stylesheet URL incorrect in sub-site sitemaps
105
+
106
  = 2.2.4.1 =
107
 
108
  * Fix: Show the WP.org rating request to admins only
317
 
318
  == About Us ==
319
  WPMU DEV is a premium supplier of quality WordPress plugins, services and support. Join us here:
320
+ [https://premium.wpmudev.org/](https://premium.wpmudev.org/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=smartcrawl-readme&utm_content=wpmu_dev_link)
321
 
322
  Don't forget to stay up to date on everything WordPress from the Internet's number one resource:
323
+ [WPMU DEV Blog](https://premium.wpmudev.org/?utm_source=wordpress.org&utm_medium=readme&utm_campaign=smartcrawl-readme&utm_content=wpmu_dev_blog_link)
324
 
325
  Hey, one more thing... we hope you enjoy our [free offerings](http://profiles.wordpress.org/WPMUDEV/) as much as we've loved making them for you!
wpmu-dev-seo.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: SmartCrawl
4
  * Plugin URI: http://premium.wpmudev.org/project/wpmu-dev-seo/
5
  * Description: Every SEO option that a site requires, in one easy bundle.
6
- * Version: 2.2.4.1
7
  * Network: true
8
  * Text Domain: wds
9
  * Author: WPMU DEV
@@ -29,7 +29,7 @@
29
  */
30
 
31
 
32
- define( 'SMARTCRAWL_VERSION', '2.2.4.1' );
33
 
34
  class Smartcrawl_Loader {
35
 
3
  * Plugin Name: SmartCrawl
4
  * Plugin URI: http://premium.wpmudev.org/project/wpmu-dev-seo/
5
  * Description: Every SEO option that a site requires, in one easy bundle.
6
+ * Version: 2.2.5
7
  * Network: true
8
  * Text Domain: wds
9
  * Author: WPMU DEV
29
  */
30
 
31
 
32
+ define( 'SMARTCRAWL_VERSION', '2.2.5' );
33
 
34
  class Smartcrawl_Loader {
35