All in One SEO Pack - Version 2.9.1

Version Description

Download this release

Release Info

Developer hallsofmontezuma
Plugin Icon 128x128 All in One SEO Pack
Version 2.9.1
Comparing to
See all releases

Code changes from version 2.9 to 2.9.1

admin/aioseop_module_class.php CHANGED
@@ -1575,7 +1575,8 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Module' ) ) {
1575
  return false;
1576
  }
1577
 
1578
- $size = apply_filters( 'aioseop_attachment_size', apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', 'full' ) ) );
 
1579
  $image = wp_get_attachment_image_src( $post_thumbnail_id, $size );
1580
 
1581
  return $image[0];
@@ -1606,7 +1607,7 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Module' ) ) {
1606
  );
1607
 
1608
  if ( empty( $attachments ) && 'attachment' == get_post_type( $post->ID ) ) {
1609
- $size = apply_filters( 'aioseop_attachment_size', apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', 'full' ) ) );
1610
  $image = wp_get_attachment_image_src( $post->ID, $size );
1611
  }
1612
 
@@ -1621,7 +1622,7 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Module' ) ) {
1621
  /* Loop through each attachment. Once the $order_of_image (default is '1') is reached, break the loop. */
1622
  foreach ( $attachments as $id => $attachment ) {
1623
  if ( ++ $i == 1 ) {
1624
- $size = apply_filters( 'aioseop_attachment_size', apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', 'full' ) ) );
1625
  $image = wp_get_attachment_image_src( $id, $size );
1626
  $alt = trim( strip_tags( get_post_field( 'post_excerpt', $id ) ) );
1627
  break;
@@ -1640,20 +1641,21 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Module' ) ) {
1640
  * @return bool
1641
  */
1642
  function get_the_image_by_scan( $p = null ) {
1643
- $url = false;
1644
-
1645
  if ( $p === null ) {
1646
  global $post;
1647
  } else {
1648
  $post = $p;
1649
  }
1650
 
1651
- $images = aiosp_common::parse_content_for_images( $post );
1652
- if ( $images ) {
1653
- $url = aiosp_common::get_image_src_for_url( $images[0], 'full' );
 
 
 
1654
  }
1655
 
1656
- return $url;
1657
  }
1658
 
1659
 
1575
  return false;
1576
  }
1577
 
1578
+ // Check if someone is using built-in WP filter.
1579
+ $size = apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', 'large' ) );
1580
  $image = wp_get_attachment_image_src( $post_thumbnail_id, $size );
1581
 
1582
  return $image[0];
1607
  );
1608
 
1609
  if ( empty( $attachments ) && 'attachment' == get_post_type( $post->ID ) ) {
1610
+ $size = apply_filters( 'aioseop_attachment_size', 'large' );
1611
  $image = wp_get_attachment_image_src( $post->ID, $size );
1612
  }
1613
 
1622
  /* Loop through each attachment. Once the $order_of_image (default is '1') is reached, break the loop. */
1623
  foreach ( $attachments as $id => $attachment ) {
1624
  if ( ++ $i == 1 ) {
1625
+ $size = apply_filters( 'aioseop_attachment_size', 'large' );
1626
  $image = wp_get_attachment_image_src( $id, $size );
1627
  $alt = trim( strip_tags( get_post_field( 'post_excerpt', $id ) ) );
1628
  break;
1641
  * @return bool
1642
  */
1643
  function get_the_image_by_scan( $p = null ) {
 
 
1644
  if ( $p === null ) {
1645
  global $post;
1646
  } else {
1647
  $post = $p;
1648
  }
1649
 
1650
+ /* Search the post's content for the <img /> tag and get its URL. */
1651
+ preg_match_all( '|<img.*?src=[\'"](.*?)[\'"].*?>|i', get_post_field( 'post_content', $post->ID ), $matches );
1652
+
1653
+ /* If there is a match for the image, return its URL. */
1654
+ if ( isset( $matches ) && ! empty( $matches[1][0] ) ) {
1655
+ return $matches[1][0];
1656
  }
1657
 
1658
+ return false;
1659
  }
1660
 
1661
 
admin/display/credits-content.php CHANGED
@@ -68,7 +68,7 @@
68
  </li>
69
  <li class="wp-person" id="EkoJR">
70
  <a class="web" target="_blank" href="https://profiles.wordpress.org/EkoJR/"><img alt="" class="gravatar" src="https://secure.gravatar.com/avatar/bb4c78fe944b58bd5f127d836500c30a?s=200&d=mm&r=g">
71
- Stanislav Samoilenko</a>
72
  </li>
73
  <li class="wp-person" id="webaware">
74
  <a class="web" target="_blank" href="https://profiles.wordpress.org/webaware/"><img alt="" class="gravatar" src="https://secure.gravatar.com/avatar/aee800bc3644d9ebfa33c1ed9df5d958?s=200&d=mm&r=g">
68
  </li>
69
  <li class="wp-person" id="EkoJR">
70
  <a class="web" target="_blank" href="https://profiles.wordpress.org/EkoJR/"><img alt="" class="gravatar" src="https://secure.gravatar.com/avatar/bb4c78fe944b58bd5f127d836500c30a?s=200&d=mm&r=g">
71
+ Ben Reames</a>
72
  </li>
73
  <li class="wp-person" id="webaware">
74
  <a class="web" target="_blank" href="https://profiles.wordpress.org/webaware/"><img alt="" class="gravatar" src="https://secure.gravatar.com/avatar/aee800bc3644d9ebfa33c1ed9df5d958?s=200&d=mm&r=g">
aioseop_class.php CHANGED
@@ -186,9 +186,9 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
186
  'paged_format' => __( 'This string gets appended/prepended to titles of paged index pages (like home or archive pages).', 'all-in-one-seo-pack' )
187
  . __( 'The following macros are supported:', 'all-in-one-seo-pack' )
188
  . '<ul><li>' . __( '%page% - The page number', 'all-in-one-seo-pack' ) . '</li></ul>',
189
- 'enablecpost' => __( 'Check this if you want to use All in One SEO Pack with any Custom Post Types on this site.', 'all-in-one-seo-pack' ),
190
  'cpostadvanced' => __( 'This will show or hide the advanced options for SEO for Custom Post Types.', 'all-in-one-seo-pack' ),
191
- 'cpostactive' => __( 'Use these checkboxes to select which Post Types you want to use All in One SEO Pack with.', 'all-in-one-seo-pack' ),
192
  'taxactive' => __( 'Use these checkboxes to select which Taxonomies you want to use All in One SEO Pack with.', 'all-in-one-seo-pack' ),
193
  'cposttitles' => __( 'This allows you to set the title tags for each Custom Post Type.', 'all-in-one-seo-pack' ),
194
  'posttypecolumns' => __( 'This lets you select which screens display the SEO Title, SEO Keywords and SEO Description columns.', 'all-in-one-seo-pack' ),
@@ -511,7 +511,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
511
  'condshow' => array( 'aiosp_rewrite_titles' => 1 ),
512
  ),
513
  'enablecpost' => array(
514
- 'name' => __( 'SEO for Custom Post Types:', 'all-in-one-seo-pack' ),
515
  'default' => 'on',
516
  'type' => 'radio',
517
  'initial_options' => array(
@@ -520,7 +520,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
520
  ),
521
  ),
522
  'cpostactive' => array(
523
- 'name' => __( 'SEO on only these post types:', 'all-in-one-seo-pack' ),
524
  'type' => 'multicheckbox',
525
  'default' => array( 'post', 'page' ),
526
  'condshow' => array( 'aiosp_enablecpost' => 'on' ),
@@ -1039,7 +1039,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
1039
  ),
1040
  ),
1041
  'cpt' => array(
1042
- 'name' => __( 'Custom Post Type Settings', 'all-in-one-seo-pack' ),
1043
  'help_link' => 'https://semperplugins.com/documentation/custom-post-type-settings/',
1044
  'options' => array( 'enablecpost', 'cpostadvanced', 'taxactive', 'cpostactive', 'cposttitles' ),
1045
  ),
@@ -1594,7 +1594,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
1594
  * Gets the title that will be used by AIOSEOP for title rewrites or returns false.
1595
  *
1596
  * @param WP_Post $post the post object
1597
- * @param bool $use_original_title_format should the original title format be used viz. post_title | blog_title. This parameter was introduced
1598
  * to resolve issue#986
1599
  *
1600
  * @return bool|string
@@ -2625,6 +2625,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
2625
  */
2626
  function trim_text_without_filters_full_length( $text ) {
2627
  $text = str_replace( ']]>', ']]&gt;', $text );
 
2628
  $text = wp_strip_all_tags( $text );
2629
 
2630
  return trim( $text );
@@ -2640,6 +2641,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
2640
  */
2641
  function trim_excerpt_without_filters( $text, $max = 0 ) {
2642
  $text = str_replace( ']]>', ']]&gt;', $text );
 
2643
  $text = wp_strip_all_tags( $text );
2644
  // Treat other common word-break characters like a space.
2645
  $text2 = preg_replace( '/[,._\-=+&!\?;:*]/s', ' ', $text );
@@ -3903,7 +3905,7 @@ class All_in_One_SEO_Pack extends All_in_One_SEO_Pack_Module {
3903
  global $aioseop_update_checker, $wp_query, $aioseop_options, $posts;
3904
  static $aioseop_dup_counter = 0;
3905
  $aioseop_dup_counter ++;
3906
-
3907
  if ( ! defined( 'AIOSEOP_UNIT_TESTING' ) && $aioseop_dup_counter > 1 ) {
3908
  echo "\n<!-- " . sprintf( __( 'Debug Warning: All in One SEO Pack meta data was included again from %1$s filter. Called %2$s times!', 'all-in-one-seo-pack' ), current_filter(), $aioseop_dup_counter ) . " -->\n";
3909
  if ( ! empty( $old_wp_query ) ) {
186
  'paged_format' => __( 'This string gets appended/prepended to titles of paged index pages (like home or archive pages).', 'all-in-one-seo-pack' )
187
  . __( 'The following macros are supported:', 'all-in-one-seo-pack' )
188
  . '<ul><li>' . __( '%page% - The page number', 'all-in-one-seo-pack' ) . '</li></ul>',
189
+ 'enablecpost' => __( 'Enable this if you want to use All in One SEO Pack with any Content Types on this site. Posts and Pages are enabled by default', 'all-in-one-seo-pack' ),
190
  'cpostadvanced' => __( 'This will show or hide the advanced options for SEO for Custom Post Types.', 'all-in-one-seo-pack' ),
191
+ 'cpostactive' => __( 'Use these checkboxes to select which Content Types you want to use All in One SEO Pack with.', 'all-in-one-seo-pack' ),
192
  'taxactive' => __( 'Use these checkboxes to select which Taxonomies you want to use All in One SEO Pack with.', 'all-in-one-seo-pack' ),
193
  'cposttitles' => __( 'This allows you to set the title tags for each Custom Post Type.', 'all-in-one-seo-pack' ),
194
  'posttypecolumns' => __( 'This lets you select which screens display the SEO Title, SEO Keywords and SEO Description columns.', 'all-in-one-seo-pack' ),
511
  'condshow' => array( 'aiosp_rewrite_titles' => 1 ),
512
  ),
513
  'enablecpost' => array(
514
+ 'name' => __( 'SEO for Content Types:', 'all-in-one-seo-pack' ),
515
  'default' => 'on',
516
  'type' => 'radio',
517
  'initial_options' => array(
520
  ),
521
  ),
522
  'cpostactive' => array(
523
+ 'name' => __( 'SEO on only these Content Types:', 'all-in-one-seo-pack' ),
524
  'type' => 'multicheckbox',
525
  'default' => array( 'post', 'page' ),
526
  'condshow' => array( 'aiosp_enablecpost' => 'on' ),
1039
  ),
1040
  ),
1041
  'cpt' => array(
1042
+ 'name' => __( 'Content Type Settings', 'all-in-one-seo-pack' ),
1043
  'help_link' => 'https://semperplugins.com/documentation/custom-post-type-settings/',
1044
  'options' => array( 'enablecpost', 'cpostadvanced', 'taxactive', 'cpostactive', 'cposttitles' ),
1045
  ),
1594
  * Gets the title that will be used by AIOSEOP for title rewrites or returns false.
1595
  *
1596
  * @param WP_Post $post the post object
1597
+ * @param bool $use_original_title_format should the original title format be used viz. post_title | blog_title. This parameter was introduced
1598
  * to resolve issue#986
1599
  *
1600
  * @return bool|string
2625
  */
2626
  function trim_text_without_filters_full_length( $text ) {
2627
  $text = str_replace( ']]>', ']]&gt;', $text );
2628
+ $text = strip_shortcodes( $text );
2629
  $text = wp_strip_all_tags( $text );
2630
 
2631
  return trim( $text );
2641
  */
2642
  function trim_excerpt_without_filters( $text, $max = 0 ) {
2643
  $text = str_replace( ']]>', ']]&gt;', $text );
2644
+ $text = strip_shortcodes( $text );
2645
  $text = wp_strip_all_tags( $text );
2646
  // Treat other common word-break characters like a space.
2647
  $text2 = preg_replace( '/[,._\-=+&!\?;:*]/s', ' ', $text );
3905
  global $aioseop_update_checker, $wp_query, $aioseop_options, $posts;
3906
  static $aioseop_dup_counter = 0;
3907
  $aioseop_dup_counter ++;
3908
+
3909
  if ( ! defined( 'AIOSEOP_UNIT_TESTING' ) && $aioseop_dup_counter > 1 ) {
3910
  echo "\n<!-- " . sprintf( __( 'Debug Warning: All in One SEO Pack meta data was included again from %1$s filter. Called %2$s times!', 'all-in-one-seo-pack' ), current_filter(), $aioseop_dup_counter ) . " -->\n";
3911
  if ( ! empty( $old_wp_query ) ) {
all_in_one_seo_pack.php CHANGED
@@ -3,8 +3,8 @@
3
  /*
4
  Plugin Name: All In One SEO Pack
5
  Plugin URI: https://semperplugins.com/all-in-one-seo-pack-pro-version/
6
- Description: Out-of-the-box SEO for your WordPress blog. Features like XML Sitemaps, SEO for custom post types, SEO for blogs or business sites, SEO for ecommerce sites, and much more. More than 30 million downloads since 2007.
7
- Version: 2.9
8
  Author: Michael Torbert
9
  Author URI: https://semperplugins.com/all-in-one-seo-pack-pro-version/
10
  Text Domain: all-in-one-seo-pack
@@ -12,7 +12,7 @@ Domain Path: /i18n/
12
  */
13
 
14
  /*
15
- Copyright (C) 2007-2017 Michael Torbert, https://semperfiwebdesign.com
16
 
17
  This program is free software; you can redistribute it and/or modify
18
  it under the terms of the GNU General Public License as published by
@@ -32,14 +32,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
32
  * The original WordPress SEO plugin.
33
  *
34
  * @package All-in-One-SEO-Pack
35
- * @version 2.9
36
  */
37
 
38
  if ( ! defined( 'AIOSEOPPRO' ) ) {
39
  define( 'AIOSEOPPRO', false );
40
  }
41
  if ( ! defined( 'AIOSEOP_VERSION' ) ) {
42
- define( 'AIOSEOP_VERSION', '2.9' );
43
  }
44
  global $aioseop_plugin_name;
45
  $aioseop_plugin_name = 'All in One SEO Pack';
3
  /*
4
  Plugin Name: All In One SEO Pack
5
  Plugin URI: https://semperplugins.com/all-in-one-seo-pack-pro-version/
6
+ Description: Out-of-the-box SEO for your WordPress blog. Features like XML Sitemaps, SEO for custom post types, SEO for blogs or business sites, SEO for ecommerce sites, and much more. More than 50 million downloads since 2007.
7
+ Version: 2.9.1
8
  Author: Michael Torbert
9
  Author URI: https://semperplugins.com/all-in-one-seo-pack-pro-version/
10
  Text Domain: all-in-one-seo-pack
12
  */
13
 
14
  /*
15
+ Copyright (C) 2007-2018 Michael Torbert, https://semperfiwebdesign.com
16
 
17
  This program is free software; you can redistribute it and/or modify
18
  it under the terms of the GNU General Public License as published by
32
  * The original WordPress SEO plugin.
33
  *
34
  * @package All-in-One-SEO-Pack
35
+ * @version 2.9.1
36
  */
37
 
38
  if ( ! defined( 'AIOSEOPPRO' ) ) {
39
  define( 'AIOSEOPPRO', false );
40
  }
41
  if ( ! defined( 'AIOSEOP_VERSION' ) ) {
42
+ define( 'AIOSEOP_VERSION', '2.9.1' );
43
  }
44
  global $aioseop_plugin_name;
45
  $aioseop_plugin_name = 'All in One SEO Pack';
inc/aiosp_common.php CHANGED
@@ -14,18 +14,6 @@
14
  class aiosp_common {
15
  // @codingStandardsIgnoreEnd
16
 
17
- /**
18
- * The allowed image extensions.
19
- *
20
- * @var array $image_extensions The allowed image extensions.
21
- */
22
- private static $image_extensions = array(
23
- 'jpg',
24
- 'jpeg',
25
- 'png',
26
- 'gif',
27
- );
28
-
29
  /**
30
  * aiosp_common constructor.
31
  *
@@ -171,383 +159,6 @@ class aiosp_common {
171
  return $url;
172
  }
173
 
174
- /**
175
- * Determines if the given image URL is an attachment and, if it is, gets the correct image URL according to the requested size.
176
- *
177
- * @param string $url The url of the image.
178
- * @param string $size The size of the image to return.
179
- *
180
- * @return string
181
- */
182
- public static function get_image_src_for_url( $url, $size = 'thumbnail' ) {
183
- // let's check if this image is an attachment.
184
- $dir = wp_get_upload_dir();
185
- $path = $url;
186
-
187
- $site_url = parse_url( $dir['url'] );
188
- $image_path = parse_url( $path );
189
-
190
- //force the protocols to match if needed
191
- if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
192
- $path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
193
- }
194
-
195
- if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) {
196
- $path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
197
- }
198
-
199
-
200
- global $wpdb;
201
- $attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s", '%' . basename( $path ) . '%' ) );
202
-
203
- if ( $attachment_id ) {
204
- $size = apply_filters( 'aioseop_attachment_size', apply_filters( 'aioseop_thumbnail_size', apply_filters( 'post_thumbnail_size', $size ) ) );
205
- // if this is a valid attachment, get the correct size.
206
- $image = wp_get_attachment_image_src( $attachment_id, $size );
207
- if ( $image ) {
208
- $url = $image[0];
209
- }
210
- }
211
-
212
- return $url;
213
- }
214
-
215
- /**
216
- * Fetch images from WP, Jetpack and WooCommerce galleries.
217
- *
218
- * @param string $post The post.
219
- * @param array $images the array of images.
220
- *
221
- * @return void
222
- * @since 2.4.2
223
- */
224
- public static function get_gallery_images( $post, &$images ) {
225
- if ( false === apply_filters( 'aioseo_include_images_in_wp_gallery', true ) ) {
226
- return;
227
- }
228
-
229
- // Check images galleries in the content. DO NOT run the_content filter here as it might cause issues with other shortcodes.
230
- if ( has_shortcode( $post->post_content, 'gallery' ) ) {
231
- // Get the jetpack gallery images.
232
- if ( class_exists( 'Jetpack_PostImages' ) ) {
233
- // the method specifies default width and height so we need to provide these values to override the defaults.
234
- // since there is no way to determine the original image's dimensions, we will fetch the 'large' size image here.
235
- $jetpack = Jetpack_PostImages::get_images( $post->ID, self::get_dimensions_for_image_size( 'large' ) );
236
- if ( $jetpack ) {
237
- foreach ( $jetpack as $jetpack_image ) {
238
- $images[] = $jetpack_image['src'];
239
- }
240
- }
241
- }
242
-
243
- // Get the default WP gallery images.
244
- $galleries = get_post_galleries( $post, false );
245
- if ( $galleries ) {
246
- foreach ( $galleries as $gallery ) {
247
- $images = array_merge( $images, $gallery['src'] );
248
- }
249
- }
250
- }
251
-
252
- // Check WooCommerce product gallery.
253
- if ( class_exists( 'WooCommerce' ) ) {
254
- $woo_images = get_post_meta( $post->ID, '_product_image_gallery', true );
255
- if ( ! empty( $woo_images ) ) {
256
- $woo_images = array_filter( explode( ',', $woo_images ) );
257
- if ( is_array( $woo_images ) ) {
258
- foreach ( $woo_images as $id ) {
259
- $images[] = wp_get_attachment_url( $id );
260
- }
261
- }
262
- }
263
- }
264
-
265
- $images = array_unique( $images );
266
- }
267
-
268
- /**
269
- * Fetch the width and height for the specified image size.
270
- *
271
- * @param string $size The image size e.g. 'large', 'medium' etc.
272
- *
273
- * @since 2.4.3
274
- */
275
- private function get_dimensions_for_image_size( $size ) {
276
- $sizes = get_intermediate_image_sizes();
277
- if ( ! in_array( $size, $sizes, true ) ) {
278
- // our specified size does not exist in the registered sizes, so let's use the largest one available.
279
- $size = end( $sizes );
280
- }
281
-
282
- if ( $size ) {
283
- return array(
284
- 'width' => get_option( "{$size}_size_w" ),
285
- 'height' => get_option( "{$size}_size_h" ),
286
- );
287
- }
288
- return null;
289
- }
290
-
291
- /**
292
- * Parses the content to find out if specified images galleries exist and if they do, parse them for images.
293
- * Supports NextGen.
294
- *
295
- * @param string $content The post content.
296
- *
297
- * @since 2.4.2
298
- *
299
- * @return string
300
- */
301
- public static function get_content_from_galleries( $content ) {
302
- // Support for NextGen Gallery.
303
- static $gallery_types = array( 'ngg_images' );
304
- $types = apply_filters( 'aioseop_gallery_shortcodes', $gallery_types );
305
-
306
- $gallery_content = '';
307
-
308
- if ( ! $types ) {
309
- return $gallery_content;
310
- }
311
-
312
- $found = array();
313
- if ( $types ) {
314
- foreach ( $types as $type ) {
315
- if ( has_shortcode( $content, $type ) ) {
316
- $found[] = $type;
317
- }
318
- }
319
- }
320
-
321
- // If none of the shortcodes-of-interest are found, bail.
322
- if ( empty( $found ) ) {
323
- return $gallery_content;
324
- }
325
-
326
- $galleries = array();
327
-
328
- if ( ! preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) ) {
329
- return $gallery_content;
330
- }
331
-
332
- // Collect the shortcodes and their attributes.
333
- foreach ( $found as $type ) {
334
- foreach ( $matches as $shortcode ) {
335
- if ( $type === $shortcode[2] ) {
336
-
337
- $attributes = shortcode_parse_atts( $shortcode[3] );
338
-
339
- if ( '' === $attributes ) { // Valid shortcode without any attributes.
340
- $attributes = array();
341
- }
342
-
343
- $galleries[ $shortcode[2] ] = $attributes;
344
- }
345
- }
346
- }
347
-
348
- // Recreate the shortcodes and then render them to get the HTML content.
349
- if ( $galleries ) {
350
- foreach ( $galleries as $shortcode => $attributes ) {
351
- $code = '[' . $shortcode;
352
- foreach ( $attributes as $key => $value ) {
353
- $code .= " $key=$value";
354
- }
355
- $code .= ']';
356
- $gallery_content .= do_shortcode( $code );
357
- }
358
- }
359
-
360
- return $gallery_content;
361
- }
362
-
363
- /**
364
- * Parses the content of the post provided for images and galleries.
365
- *
366
- * @param WP_Post $post The post to parse.
367
- * @return array
368
- */
369
- public static function parse_content_for_images( WP_Post $post ) {
370
- $images = array();
371
- $content = $post->post_content;
372
-
373
- self::get_gallery_images( $post, $images );
374
-
375
- $content .= self::get_content_from_galleries( $content );
376
-
377
- self::parse_dom_for_images( $content, $images );
378
-
379
- return $images;
380
- }
381
-
382
- /**
383
- * Parse the post for images.
384
- *
385
- * @param string $content the post content.
386
- * @param array $images the array of images.
387
- *
388
- * @return void
389
- */
390
- public static function parse_dom_for_images( $content, &$images ) {
391
- // These tags should be WITHOUT trailing space because some plugins such as the nextgen gallery put newlines immediately after <img.
392
- $total = substr_count( $content, '<img' ) + substr_count( $content, '<IMG' );
393
- // no images found.
394
- if ( 0 === $total ) {
395
- return;
396
- }
397
-
398
- if ( class_exists( 'DOMDocument' ) ) {
399
- $dom = new domDocument();
400
- // Non-compliant HTML might give errors, so ignore them.
401
- libxml_use_internal_errors( true );
402
- $dom->loadHTML( $content );
403
- libxml_clear_errors();
404
- $dom->preserveWhiteSpace = false;
405
- $matches = $dom->getElementsByTagName( 'img' );
406
- foreach ( $matches as $match ) {
407
- $images[] = $match->getAttribute( 'src' );
408
- }
409
- } else {
410
- // Fall back to regex, but also report an error.
411
- global $img_err_msg;
412
- if ( ! isset( $img_err_msg ) ) {
413
- // we will log this error message only once, not per post.
414
- $img_err_msg = true;
415
- aiosp_log( 'DOMDocument not found; using REGEX' );
416
- }
417
- preg_match_all( '/<img.*src=([\'"])?(.*?)\\1/', $content, $matches );
418
- if ( $matches && isset( $matches[2] ) ) {
419
- $images = array_merge( $images, $matches[2] );
420
- }
421
- }
422
- }
423
-
424
- /**
425
- * Fetch image attributes such as title and caption given the image URL.
426
- *
427
- * @param string $url The image URL.
428
- */
429
- public static function get_image_attributes( $url ) {
430
- $attributes = array();
431
- global $wpdb;
432
- $attachment = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $url ) );
433
- if ( $attachment && is_array( $attachment ) && is_numeric( $attachment[0] ) ) {
434
- $attributes = array(
435
- 'image:caption' => self::get_image_caption( $attachment[0] ),
436
- 'image:title' => get_the_title( $attachment[0] ),
437
- );
438
- }
439
- return $attributes;
440
- }
441
-
442
- /**
443
- * Wrapper around `wp_get_attachment_caption` because it was introduced only in WP 4.6.0.
444
- *
445
- * @param int $attachment_id The attachment ID.
446
- */
447
- public static function get_image_caption( $attachment_id ) {
448
- global $wp_version;
449
- if ( version_compare( $wp_version, '4.6.0', '<' ) ) {
450
- $post_id = (int) $attachment_id;
451
- if ( ! $post = get_post( $post_id ) ) {
452
- return false;
453
- }
454
-
455
- if ( 'attachment' !== $post->post_type ) {
456
- return false;
457
- }
458
-
459
- $caption = $post->post_excerpt;
460
- return apply_filters( 'wp_get_attachment_caption', $caption, $post->ID );
461
- }
462
-
463
- return wp_get_attachment_caption( $attachment_id );
464
- }
465
-
466
- /**
467
- * Cleans the URL so that its acceptable in the sitemap.
468
- *
469
- * @param string $url The image url.
470
- *
471
- * @since 2.4.1
472
- *
473
- * @return string
474
- */
475
- public static function clean_url( $url ) {
476
- // remove the query string.
477
- $url = strtok( $url, '?' );
478
- // make the url XML-safe.
479
- $url = htmlspecialchars( $url );
480
- // Make the url absolute, if its relative.
481
- $url = aiosp_common::absolutize_url( $url );
482
- return apply_filters( 'aioseop_clean_url', $url );
483
- }
484
-
485
- /**
486
- * Validate the image.
487
- * NOTE: We will use parse_url here instead of wp_parse_url as we will correct the URLs beforehand and
488
- * this saves us the need to check PHP version support.
489
- *
490
- * @param string $image The image src.
491
- *
492
- * @since 2.4.1
493
- * @since 2.4.3 Compatibility with Pre v4.7 wp_parse_url().
494
- *
495
- * @return bool
496
- */
497
- public static function is_image_valid( $image ) {
498
- global $wp_version;
499
-
500
- // Bail if empty image.
501
- if ( empty( $image ) ) {
502
- return false;
503
- }
504
-
505
- global $wp_version;
506
- if ( version_compare( $wp_version, '4.4', '<' ) ) {
507
- $p_url = parse_url( $image );
508
- $url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
509
- } elseif ( version_compare( $wp_version, '4.7', '<' ) ) {
510
- // Compatability for older WP version that don't have 4.7 changes.
511
- // @link https://core.trac.wordpress.org/changeset/38726
512
- $p_url = wp_parse_url( $image );
513
- $url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
514
- } else {
515
- $component = PHP_URL_PATH;
516
- $url = wp_parse_url( $image, $component );
517
- }
518
-
519
- // make the url absolute, if its relative.
520
- $image = aiosp_common::absolutize_url( $image );
521
-
522
- $extn = pathinfo( parse_url( $image, PHP_URL_PATH ), PATHINFO_EXTENSION );
523
- $allowed = apply_filters( 'aioseop_allowed_image_extensions', self::$image_extensions );
524
- // Bail if image does not refer to an image file otherwise google webmaster tools might reject the sitemap.
525
- if ( ! in_array( $extn, $allowed, true ) ) {
526
- return false;
527
- }
528
-
529
- $image_host = parse_url( $image, PHP_URL_HOST );
530
- $host = parse_url( home_url(), PHP_URL_HOST );
531
-
532
- if ( $image_host !== $host ) {
533
- // Allowed hosts will be provided in a wildcard format i.e. img.yahoo.* or *.akamai.*.
534
- // And we will convert that into a regular expression for matching.
535
- $whitelist = apply_filters( 'aioseop_images_allowed_from_hosts', array() );
536
- $allowed = false;
537
- if ( $whitelist ) {
538
- foreach ( $whitelist as $pattern ) {
539
- if ( preg_match( '/' . str_replace( '*', '.*', $pattern ) . '/', $image_host ) === 1 ) {
540
- $allowed = true;
541
- break;
542
- }
543
- }
544
- }
545
- return $allowed;
546
-
547
- }
548
- return true;
549
- }
550
-
551
  /**
552
  * Check whether a url is valid.
553
  *
14
  class aiosp_common {
15
  // @codingStandardsIgnoreEnd
16
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  /**
18
  * aiosp_common constructor.
19
  *
159
  return $url;
160
  }
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  /**
163
  * Check whether a url is valid.
164
  *
js/modules/aioseop_module.js CHANGED
@@ -52,11 +52,13 @@ function toggleVisibility( id ) {
52
  * @summary Counts characters.
53
  *
54
  * @since 1.0.0
 
 
55
  * @param Object $field.
56
  * @param Object $cntfield.
57
  * @return Mixed.
58
  */
59
- function countChars( field, cntfield ) {
60
  var extra = 0;
61
  var field_size;
62
  if ( ( field.attr('name') == 'aiosp_title' )
@@ -864,9 +866,9 @@ function aiospinitSocialMetaInPosts($) {
864
  function aiospinitCounting(){
865
  /* count them characters */
866
  jQuery( '.aioseop_count_chars' ).on('keyup keydown', function(){
867
- countChars( jQuery(this).eq(0), jQuery(this).parent().find('[name="' + jQuery(this).attr('data-length-field') + '"]').eq(0));
868
  });
869
  jQuery( '.aioseop_count_chars' ).each(function(){
870
- countChars( jQuery(this).eq(0), jQuery(this).parent().find('[name="' + jQuery(this).attr('data-length-field') + '"]').eq(0));
871
  });
872
  }
52
  * @summary Counts characters.
53
  *
54
  * @since 1.0.0
55
+ * @since 2.9.1 Fix JS conflict with LearnDash and function name.
56
+ *
57
  * @param Object $field.
58
  * @param Object $cntfield.
59
  * @return Mixed.
60
  */
61
+ function aioseopCountChars( field, cntfield ) {
62
  var extra = 0;
63
  var field_size;
64
  if ( ( field.attr('name') == 'aiosp_title' )
866
  function aiospinitCounting(){
867
  /* count them characters */
868
  jQuery( '.aioseop_count_chars' ).on('keyup keydown', function(){
869
+ aioseopCountChars( jQuery(this).eq(0), jQuery(this).parent().find('[name="' + jQuery(this).attr('data-length-field') + '"]').eq(0));
870
  });
871
  jQuery( '.aioseop_count_chars' ).each(function(){
872
+ aioseopCountChars( jQuery(this).eq(0), jQuery(this).parent().find('[name="' + jQuery(this).attr('data-length-field') + '"]').eq(0));
873
  });
874
  }
modules/aioseop_opengraph.php CHANGED
@@ -185,7 +185,7 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Opengraph' ) ) {
185
  add_action( 'wp', array( $this, 'type_setup' ) );
186
  }
187
 
188
- if ( ! is_admin() || defined( 'DOING_AJAX' ) || ( defined( 'AIOSEOP_UNIT_TESTING' ) && AIOSEOP_UNIT_TESTING ) ) {
189
  $this->do_opengraph();
190
  }
191
  // Set variables after WordPress load.
@@ -971,12 +971,7 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Opengraph' ) ) {
971
  function add_meta() {
972
  global $post, $aiosp, $aioseop_options, $wp_query;
973
  $metabox = $this->get_current_options( array(), 'settings' );
974
-
975
- // we have to introduce this because, for some reason, $this->options is not being populated at all while testing.
976
- if ( defined( 'AIOSEOP_UNIT_TESTING' ) && AIOSEOP_UNIT_TESTING ) {
977
- $this->options = $aioseop_options['modules']['aiosp_opengraph_options'];
978
- }
979
-
980
  $key = $this->options['aiosp_opengraph_key'];
981
  $dimg = $this->options['aiosp_opengraph_dimg'];
982
  $current_post_type = get_post_type();
185
  add_action( 'wp', array( $this, 'type_setup' ) );
186
  }
187
 
188
+ if ( ! is_admin() || defined( 'DOING_AJAX' ) ) {
189
  $this->do_opengraph();
190
  }
191
  // Set variables after WordPress load.
971
  function add_meta() {
972
  global $post, $aiosp, $aioseop_options, $wp_query;
973
  $metabox = $this->get_current_options( array(), 'settings' );
974
+ $key = $this->options['aiosp_opengraph_key'];
 
 
 
 
 
975
  $key = $this->options['aiosp_opengraph_key'];
976
  $dimg = $this->options['aiosp_opengraph_dimg'];
977
  $current_post_type = get_post_type();
modules/aioseop_sitemap.php CHANGED
@@ -27,6 +27,18 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
27
  var $extra_sitemaps;
28
  var $excludes = array();
29
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  /**
31
  * All_in_One_SEO_Pack_Sitemap constructor.
32
  */
@@ -3013,9 +3025,10 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3013
  if ( $thumbnail_id ) {
3014
  $image = wp_get_attachment_url( $thumbnail_id );
3015
  if ( $image ) {
3016
- $image = aiosp_common::get_image_src_for_url( $image, 'full' );
3017
  $images['image:image'] = array(
3018
- 'image:loc' => $image,
 
 
3019
  );
3020
  }
3021
  }
@@ -3054,12 +3067,12 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3054
  // Ignore all attachments except images.
3055
  return null;
3056
  }
3057
- $attributes = wp_get_attachment_image_src( $post->ID, 'full' );
3058
  if ( $attributes ) {
3059
  $images[] = array(
3060
- 'image:loc' => aiosp_common::clean_url( $attributes[0] ),
3061
  'image:caption' => wp_get_attachment_caption( $post->ID ),
3062
- 'image:title' => get_the_title( $post->ID ),
3063
  );
3064
  }
3065
 
@@ -3068,6 +3081,8 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3068
 
3069
  /**
3070
  * Static attachment cache, 1 query vs. n posts.
 
 
3071
  */
3072
  static $post_thumbnails;
3073
 
@@ -3085,7 +3100,7 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3085
  }
3086
 
3087
  if ( isset( $post_thumbnails[ $post->ID ] ) ) {
3088
- $attachment_url = wp_get_attachment_image_url( $post_thumbnails[ $post->ID ], 'full' );
3089
  if ( $attachment_url ) {
3090
  $images[] = $attachment_url;
3091
  }
@@ -3094,7 +3109,10 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3094
  $content = '';
3095
  $content = $post->post_content;
3096
 
3097
- $images = array_merge( $images, aiosp_common::parse_content_for_images( $post ) );
 
 
 
3098
 
3099
  if ( $images ) {
3100
  $tmp = $images;
@@ -3103,14 +3121,13 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3103
  $tmp = array_unique( $images );
3104
  }
3105
  // remove any invalid/empty images.
3106
- $tmp = array_filter( $images, array( 'aiosp_common', 'is_image_valid' ) );
3107
  $images = array();
3108
  foreach ( $tmp as $image ) {
3109
- $image = aiosp_common::get_image_src_for_url( $image, 'full' );
3110
- $image_attributes = aiosp_common::get_image_attributes( $image );
3111
  $images[] = array_merge(
3112
  array(
3113
- 'image:loc' => aiosp_common::clean_url( $image ),
3114
  ),
3115
  $image_attributes
3116
  );
@@ -3120,6 +3137,145 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3120
  return $images;
3121
  }
3122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3123
 
3124
  /**
3125
  * Cleans the URL so that its acceptable in the sitemap.
@@ -3140,6 +3296,112 @@ if ( ! class_exists( 'All_in_One_SEO_Pack_Sitemap' ) ) {
3140
  return apply_filters( 'aioseop_clean_url', $url );
3141
  }
3142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3143
  /**
3144
  * Return excluded categories for taxonomy queries.
3145
  *
27
  var $extra_sitemaps;
28
  var $excludes = array();
29
 
30
+ /**
31
+ * The allowed image extensions.
32
+ *
33
+ * @var array $image_extensions The allowed image extensions.
34
+ */
35
+ private static $image_extensions = array(
36
+ 'jpg',
37
+ 'jpeg',
38
+ 'png',
39
+ 'gif',
40
+ );
41
+
42
  /**
43
  * All_in_One_SEO_Pack_Sitemap constructor.
44
  */
3025
  if ( $thumbnail_id ) {
3026
  $image = wp_get_attachment_url( $thumbnail_id );
3027
  if ( $image ) {
 
3028
  $images['image:image'] = array(
3029
+ 'image:loc' => $image,
3030
+ 'image:caption' => wp_get_attachment_caption( $thumbnail_id ),
3031
+ 'image:title' => get_the_title( $thumbnail_id ),
3032
  );
3033
  }
3034
  }
3067
  // Ignore all attachments except images.
3068
  return null;
3069
  }
3070
+ $attributes = wp_get_attachment_image_src( $post->ID );
3071
  if ( $attributes ) {
3072
  $images[] = array(
3073
+ 'image:loc' => $this->clean_url( $attributes[0] ),
3074
  'image:caption' => wp_get_attachment_caption( $post->ID ),
3075
+ 'image:title' => get_the_title( $post->ID ),
3076
  );
3077
  }
3078
 
3081
 
3082
  /**
3083
  * Static attachment cache, 1 query vs. n posts.
3084
+ *
3085
+ * Concepts like this should be followed; although this could possibly be improved (maybe as a wrapped function) but is still good code.
3086
  */
3087
  static $post_thumbnails;
3088
 
3100
  }
3101
 
3102
  if ( isset( $post_thumbnails[ $post->ID ] ) ) {
3103
+ $attachment_url = wp_get_attachment_image_url( $post_thumbnails[ $post->ID ], 'post-thumbnail' );
3104
  if ( $attachment_url ) {
3105
  $images[] = $attachment_url;
3106
  }
3109
  $content = '';
3110
  $content = $post->post_content;
3111
 
3112
+ $this->get_gallery_images( $post, $images );
3113
+
3114
+ $content .= $this->get_content_from_galleries( $content );
3115
+ $this->parse_content_for_images( $content, $images );
3116
 
3117
  if ( $images ) {
3118
  $tmp = $images;
3121
  $tmp = array_unique( $images );
3122
  }
3123
  // remove any invalid/empty images.
3124
+ $tmp = array_filter( $images, array( $this, 'is_image_valid' ) );
3125
  $images = array();
3126
  foreach ( $tmp as $image ) {
3127
+ $image_attributes = $this->get_image_attributes( $image );
 
3128
  $images[] = array_merge(
3129
  array(
3130
+ 'image:loc' => $this->clean_url( $image ),
3131
  ),
3132
  $image_attributes
3133
  );
3137
  return $images;
3138
  }
3139
 
3140
+ /**
3141
+ * Fetch image attributes such as title and caption given the image URL.
3142
+ *
3143
+ * @param string $url The image URL.
3144
+ */
3145
+ private function get_image_attributes( $url ) {
3146
+ $attributes = array();
3147
+ global $wpdb;
3148
+ $attachment = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $url ) );
3149
+ if ( $attachment && is_array( $attachment ) && is_numeric( $attachment[0] ) ) {
3150
+ $attributes = array(
3151
+ 'image:caption' => wp_get_attachment_caption( $attachment[0] ),
3152
+ 'image:title' => get_the_title( $attachment[0] ),
3153
+ );
3154
+ }
3155
+ return $attributes;
3156
+ }
3157
+
3158
+ /**
3159
+ * Fetch images from WP, Jetpack and WooCommerce galleries.
3160
+ *
3161
+ * @param string $post The post.
3162
+ * @param array $images the array of images.
3163
+ *
3164
+ * @since 2.4.2
3165
+ */
3166
+ private function get_gallery_images( $post, &$images ) {
3167
+ if ( false === apply_filters( 'aioseo_include_images_in_wp_gallery', true ) ) {
3168
+ return;
3169
+ }
3170
+
3171
+ // Check images galleries in the content. DO NOT run the_content filter here as it might cause issues with other shortcodes.
3172
+ if ( has_shortcode( $post->post_content, 'gallery' ) ) {
3173
+ // Get the jetpack gallery images.
3174
+ if ( class_exists( 'Jetpack_PostImages' ) ) {
3175
+ $jetpack = Jetpack_PostImages::get_images( $post->ID );
3176
+ if ( $jetpack ) {
3177
+ foreach ( $jetpack as $jetpack_image ) {
3178
+ $images[] = $jetpack_image['src'];
3179
+ }
3180
+ }
3181
+ }
3182
+
3183
+ // Get the default WP gallery images.
3184
+ $galleries = get_post_galleries( $post, false );
3185
+ if ( $galleries ) {
3186
+ foreach ( $galleries as $gallery ) {
3187
+ $images = array_merge( $images, $gallery['src'] );
3188
+ }
3189
+ }
3190
+ }
3191
+
3192
+ // Check WooCommerce product gallery.
3193
+ if ( class_exists( 'WooCommerce' ) ) {
3194
+ $woo_images = get_post_meta( $post->ID, '_product_image_gallery', true );
3195
+ if ( ! empty( $woo_images ) ) {
3196
+ $woo_images = array_filter( explode( ',', $woo_images ) );
3197
+ if ( is_array( $woo_images ) ) {
3198
+ foreach ( $woo_images as $id ) {
3199
+ $images[] = wp_get_attachment_url( $id );
3200
+ }
3201
+ }
3202
+ }
3203
+ }
3204
+
3205
+ $images = array_unique( $images );
3206
+ }
3207
+
3208
+ /**
3209
+ * Parses the content to find out if specified images galleries exist and if they do, parse them for images.
3210
+ * Supports NextGen.
3211
+ *
3212
+ * @param string $content The post content.
3213
+ *
3214
+ * @since 2.4.2
3215
+ *
3216
+ * @return string
3217
+ */
3218
+ private function get_content_from_galleries( $content ) {
3219
+ // Support for NextGen Gallery.
3220
+ static $gallery_types = array( 'ngg_images' );
3221
+ $types = apply_filters( 'aioseop_gallery_shortcodes', $gallery_types );
3222
+
3223
+ $gallery_content = '';
3224
+
3225
+ if ( ! $types ) {
3226
+ return $gallery_content;
3227
+ }
3228
+
3229
+ $found = array();
3230
+ if ( $types ) {
3231
+ foreach ( $types as $type ) {
3232
+ if ( has_shortcode( $content, $type ) ) {
3233
+ $found[] = $type;
3234
+ }
3235
+ }
3236
+ }
3237
+
3238
+ // If none of the shortcodes-of-interest are found, bail.
3239
+ if ( empty( $found ) ) {
3240
+ return $gallery_content;
3241
+ }
3242
+
3243
+ $galleries = array();
3244
+
3245
+ if ( ! preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) ) {
3246
+ return $gallery_content;
3247
+ }
3248
+
3249
+ // Collect the shortcodes and their attributes.
3250
+ foreach ( $found as $type ) {
3251
+ foreach ( $matches as $shortcode ) {
3252
+ if ( $type === $shortcode[2] ) {
3253
+
3254
+ $attributes = shortcode_parse_atts( $shortcode[3] );
3255
+
3256
+ if ( '' === $attributes ) { // Valid shortcode without any attributes.
3257
+ $attributes = array();
3258
+ }
3259
+
3260
+ $galleries[ $shortcode[2] ] = $attributes;
3261
+ }
3262
+ }
3263
+ }
3264
+
3265
+ // Recreate the shortcodes and then render them to get the HTML content.
3266
+ if ( $galleries ) {
3267
+ foreach ( $galleries as $shortcode => $attributes ) {
3268
+ $code = '[' . $shortcode;
3269
+ foreach ( $attributes as $key => $value ) {
3270
+ $code .= " $key=$value";
3271
+ }
3272
+ $code .= ']';
3273
+ $gallery_content .= do_shortcode( $code );
3274
+ }
3275
+ }
3276
+
3277
+ return $gallery_content;
3278
+ }
3279
 
3280
  /**
3281
  * Cleans the URL so that its acceptable in the sitemap.
3296
  return apply_filters( 'aioseop_clean_url', $url );
3297
  }
3298
 
3299
+ /**
3300
+ * Validate the image.
3301
+ * NOTE: We will use parse_url here instead of wp_parse_url as we will correct the URLs beforehand and
3302
+ * this saves us the need to check PHP version support.
3303
+ *
3304
+ * @param string $image The image src.
3305
+ *
3306
+ * @since 2.4.1
3307
+ * @since 2.4.3 Compatibility with Pre v4.7 wp_parse_url().
3308
+ *
3309
+ * @return bool
3310
+ */
3311
+ function is_image_valid( $image ) {
3312
+ global $wp_version;
3313
+
3314
+ // Bail if empty image.
3315
+ if ( empty( $image ) ) {
3316
+ return false;
3317
+ }
3318
+
3319
+ global $wp_version;
3320
+ if ( version_compare( $wp_version, '4.4', '<' ) ) {
3321
+ $p_url = parse_url( $image );
3322
+ $url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
3323
+ } elseif ( version_compare( $wp_version, '4.7', '<' ) ) {
3324
+ // Compatability for older WP version that don't have 4.7 changes.
3325
+ // @link https://core.trac.wordpress.org/changeset/38726
3326
+ $p_url = wp_parse_url( $image );
3327
+ $url = $p_url['scheme'] . $p_url['host'] . $p_url['path'];
3328
+ } else {
3329
+ $component = PHP_URL_PATH;
3330
+ $url = wp_parse_url( $image, $component );
3331
+ }
3332
+
3333
+ // make the url absolute, if its relative.
3334
+ $image = aiosp_common::absolutize_url( $image );
3335
+
3336
+ $extn = pathinfo( parse_url( $image, PHP_URL_PATH ), PATHINFO_EXTENSION );
3337
+ $allowed = apply_filters( 'aioseop_allowed_image_extensions', self::$image_extensions );
3338
+ // Bail if image does not refer to an image file otherwise google webmaster tools might reject the sitemap.
3339
+ if ( ! in_array( $extn, $allowed, true ) ) {
3340
+ return false;
3341
+ }
3342
+
3343
+ $image_host = parse_url( $image, PHP_URL_HOST );
3344
+ $host = parse_url( home_url(), PHP_URL_HOST );
3345
+
3346
+ if ( $image_host !== $host ) {
3347
+ // Allowed hosts will be provided in a wildcard format i.e. img.yahoo.* or *.akamai.*.
3348
+ // And we will convert that into a regular expression for matching.
3349
+ $whitelist = apply_filters( 'aioseop_images_allowed_from_hosts', array() );
3350
+ $allowed = false;
3351
+ if ( $whitelist ) {
3352
+ foreach ( $whitelist as $pattern ) {
3353
+ if ( preg_match( '/' . str_replace( '*', '.*', $pattern ) . '/', $image_host ) === 1 ) {
3354
+ $allowed = true;
3355
+ break;
3356
+ }
3357
+ }
3358
+ }
3359
+ return $allowed;
3360
+
3361
+ }
3362
+ return true;
3363
+ }
3364
+
3365
+ /**
3366
+ * Parse the post for images.
3367
+ *
3368
+ * @param string $content the post content.
3369
+ * @param array $images the array of images.
3370
+ */
3371
+ function parse_content_for_images( $content, &$images ) {
3372
+ // These tags should be WITHOUT trailing space because some plugins such as the nextgen gallery put newlines immediately after <img.
3373
+ $total = substr_count( $content, '<img' ) + substr_count( $content, '<IMG' );
3374
+ // no images found.
3375
+ if ( 0 === $total ) {
3376
+ return;
3377
+ }
3378
+
3379
+ if ( class_exists( 'DOMDocument' ) ) {
3380
+ $dom = new domDocument();
3381
+ // Non-compliant HTML might give errors, so ignore them.
3382
+ libxml_use_internal_errors( true );
3383
+ $dom->loadHTML( $content );
3384
+ libxml_clear_errors();
3385
+ $dom->preserveWhiteSpace = false;
3386
+ $matches = $dom->getElementsByTagName( 'img' );
3387
+ foreach ( $matches as $match ) {
3388
+ $images[] = $match->getAttribute( 'src' );
3389
+ }
3390
+ } else {
3391
+ // Fall back to regex, but also report an error.
3392
+ global $img_err_msg;
3393
+ if ( ! isset( $img_err_msg ) ) {
3394
+ // we will log this error message only once, not per post.
3395
+ $img_err_msg = true;
3396
+ $this->debug_message( 'DOMDocument not found; using REGEX' );
3397
+ }
3398
+ preg_match_all( '/<img.*src=([\'"])?(.*?)\\1/', $content, $matches );
3399
+ if ( $matches && isset( $matches[2] ) ) {
3400
+ $images = array_merge( $images, $matches[2] );
3401
+ }
3402
+ }
3403
+ }
3404
+
3405
  /**
3406
  * Return excluded categories for taxonomy queries.
3407
  *
readme.txt CHANGED
@@ -4,15 +4,15 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mrtor
4
  Tags: seo, all in one seo, google, twitter, page, image seo, social, search engine optimization, sitemap, WordPress SEO, meta, meta description, xml sitemap, google sitemap, sitemaps, robots meta, yahoo, bing, news sitemaps, multisite, canonical, nofollow, noindex, keywords, description, webmaster tools, google webmaster tools, google analytics
5
  Requires at least: 4.4
6
  Tested up to: 4.9
7
- Stable tag: 2.9
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
- The original WordPress SEO plugin, downloaded over 45,000,000 times since 2007.
12
 
13
  == Description ==
14
 
15
- ###The original WordPress SEO plugin, downloaded over 45,000,000 times since 2007.
16
 
17
  Use **All in One SEO Pack** to optimize your WordPress site for SEO. It's easy and works out of the box for beginners, and has advanced features and an API for developers.
18
 
4
  Tags: seo, all in one seo, google, twitter, page, image seo, social, search engine optimization, sitemap, WordPress SEO, meta, meta description, xml sitemap, google sitemap, sitemaps, robots meta, yahoo, bing, news sitemaps, multisite, canonical, nofollow, noindex, keywords, description, webmaster tools, google webmaster tools, google analytics
5
  Requires at least: 4.4
6
  Tested up to: 4.9
7
+ Stable tag: 2.9.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
+ The original WordPress SEO plugin, downloaded over 50,000,000 times since 2007.
12
 
13
  == Description ==
14
 
15
+ ###The original WordPress SEO plugin, downloaded over 50,000,000 times since 2007.
16
 
17
  Use **All in One SEO Pack** to optimize your WordPress site for SEO. It's easy and works out of the box for beginners, and has advanced features and an API for developers.
18