Polylang - Version 2.8.3

Version Description

(2020-10-13) =

  • Honor install_languages capability to download language packs
  • Pro: Fix integrations not loaded (with The Events Calendar, CPTUI, Content blocks)
  • Pro: Fix fatal error with ACF if a flexible content includes a repeater and a relationship
  • Pro: Fix terms sharing their slug impossible to update without changing the slug
  • When available, use wpcom_vip_get_page_by_path() instead of get_page_by_path()
  • Fix queries filtered when editing a post that was declared untranslatable after it got a language
  • Fix issues with Yoast SEO 14.0+ (breadcrumbs, canonical, title and description)
Download this release

Release Info

Developer Chouby
Plugin Icon 128x128 Polylang
Version 2.8.3
Comparing to
See all releases

Code changes from version 2.8.2 to 2.8.3

admin/admin-base.php CHANGED
@@ -261,20 +261,19 @@ class PLL_Admin_Base extends PLL_Base {
261
  // Edit Post
262
  if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
263
  $this->curlang = $lang;
264
- } elseif ( 'post.php' === $GLOBALS['pagenow'] && isset( $_GET['post'] ) && $lang = $this->model->post->get_language( (int) $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
265
  $this->curlang = $lang;
266
  } elseif ( 'post-new.php' === $GLOBALS['pagenow'] && ( empty( $_GET['post_type'] ) || $this->model->is_translated_post_type( sanitize_key( $_GET['post_type'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
267
  $this->curlang = empty( $_GET['new_lang'] ) ? $this->pref_lang : $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
268
  }
269
 
270
  // Edit Term
271
- // FIXME 'edit-tags.php' for backward compatibility with WP < 4.5
272
- elseif ( in_array( $GLOBALS['pagenow'], array( 'edit-tags.php', 'term.php' ) ) && isset( $_GET['tag_ID'] ) && $lang = $this->model->term->get_language( (int) $_GET['tag_ID'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
273
  $this->curlang = $lang;
274
- } elseif ( isset( $_REQUEST['pll_term_id'] ) && $lang = $this->model->term->get_language( (int) $_REQUEST['pll_term_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
275
- $this->curlang = $lang;
276
- } elseif ( 'edit-tags.php' === $GLOBALS['pagenow'] && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( sanitize_key( $_GET['taxonomy'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
277
- if ( ! empty( $_GET['new_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
278
  $this->curlang = $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
279
  } elseif ( empty( $this->curlang ) ) {
280
  $this->curlang = $this->pref_lang;
261
  // Edit Post
262
  if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
263
  $this->curlang = $lang;
264
+ } elseif ( 'post.php' === $GLOBALS['pagenow'] && isset( $_GET['post'] ) && $this->model->is_translated_post_type( get_post_type( (int) $_GET['post'] ) ) && $lang = $this->model->post->get_language( (int) $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
265
  $this->curlang = $lang;
266
  } elseif ( 'post-new.php' === $GLOBALS['pagenow'] && ( empty( $_GET['post_type'] ) || $this->model->is_translated_post_type( sanitize_key( $_GET['post_type'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
267
  $this->curlang = empty( $_GET['new_lang'] ) ? $this->pref_lang : $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
268
  }
269
 
270
  // Edit Term
271
+ elseif ( isset( $_REQUEST['pll_term_id'] ) && $lang = $this->model->term->get_language( (int) $_REQUEST['pll_term_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
 
272
  $this->curlang = $lang;
273
+ } elseif ( in_array( $GLOBALS['pagenow'], array( 'edit-tags.php', 'term.php' ) ) && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( sanitize_key( $_GET['taxonomy'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
274
+ if ( isset( $_GET['tag_ID'] ) && $lang = $this->model->term->get_language( (int) $_GET['tag_ID'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
275
+ $this->curlang = $lang;
276
+ } elseif ( ! empty( $_GET['new_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
277
  $this->curlang = $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
278
  } elseif ( empty( $this->curlang ) ) {
279
  $this->curlang = $this->pref_lang;
include/functions.php CHANGED
@@ -25,6 +25,23 @@ if ( ! function_exists( 'wpcom_vip_get_page_by_title' ) ) {
25
  }
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  if ( ! function_exists( 'wp_doing_ajax' ) ) {
29
  /**
30
  * Determines whether the current request is a WordPress Ajax request.
25
  }
26
  }
27
 
28
+ if ( ! function_exists( 'wpcom_vip_get_page_by_path' ) ) {
29
+ /**
30
+ * Retrieves a page given its path.
31
+ *
32
+ * @since 2.8.3
33
+ *
34
+ * @param string $page_path Page path.
35
+ * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
36
+ * a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
37
+ * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
38
+ * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
39
+ */
40
+ function wpcom_vip_get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
41
+ return get_page_by_path( $page_path, $output, $post_type ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.get_page_by_path_get_page_by_path
42
+ }
43
+ }
44
+
45
  if ( ! function_exists( 'wp_doing_ajax' ) ) {
46
  /**
47
  * Determines whether the current request is a WordPress Ajax request.
integrations/wpseo/wpseo.php CHANGED
@@ -45,6 +45,7 @@ class PLL_WPSEO {
45
  }
46
  add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) );
47
  add_filter( 'wpseo_frontend_presentation', array( $this, 'frontend_presentation' ) );
 
48
  } else {
49
  add_action( 'admin_init', array( $this, 'wpseo_register_strings' ) );
50
 
@@ -296,7 +297,7 @@ class PLL_WPSEO {
296
  // Exclude cases where a post type archive is attached to a page (ex: WooCommerce).
297
  $slug = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive;
298
 
299
- if ( ! get_page_by_path( $slug ) ) {
300
  // The post type archive in the current language is already added by WPSEO.
301
  $languages = wp_list_filter( $languages, array( 'slug' => pll_current_language() ), 'NOT' );
302
 
@@ -402,28 +403,59 @@ class PLL_WPSEO {
402
  * @return object
403
  */
404
  public function frontend_presentation( $presentation ) {
405
- if ( is_front_page() ) {
406
- $presentation->model->permalink = pll_home_url();
407
- }
408
-
409
- if ( is_post_type_archive() ) {
410
- $presentation->model->permalink = get_post_type_archive_link( get_post_type() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  }
412
 
413
- $strings = array(
414
- 'title',
415
- 'description',
416
- 'breadcrumb_title',
417
- );
418
 
419
- foreach ( $strings as $string ) {
420
- $presentation->model->$string = pll__( $presentation->model->$string );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  }
422
 
423
- return $presentation;
424
  }
425
 
426
-
427
  /**
428
  * Helper function to register strings for custom post types and custom taxonomies titles and meta descriptions
429
  *
45
  }
46
  add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) );
47
  add_filter( 'wpseo_frontend_presentation', array( $this, 'frontend_presentation' ) );
48
+ add_filter( 'wpseo_breadcrumb_indexables', array( $this, 'breadcrumb_indexables' ) );
49
  } else {
50
  add_action( 'admin_init', array( $this, 'wpseo_register_strings' ) );
51
 
297
  // Exclude cases where a post type archive is attached to a page (ex: WooCommerce).
298
  $slug = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive;
299
 
300
+ if ( ! wpcom_vip_get_page_by_path( $slug ) ) {
301
  // The post type archive in the current language is already added by WPSEO.
302
  $languages = wp_list_filter( $languages, array( 'slug' => pll_current_language() ), 'NOT' );
303
 
403
  * @return object
404
  */
405
  public function frontend_presentation( $presentation ) {
406
+ switch ( $presentation->model->object_type ) {
407
+ case 'home-page':
408
+ $presentation->model->permalink = pll_home_url();
409
+ $presentation->model->title = WPSEO_Options::get( 'title-home-wpseo' );
410
+ $presentation->model->description = WPSEO_Options::get( 'title-home-wpseo' );
411
+ break;
412
+
413
+ case 'post-type-archive':
414
+ $presentation->model->permalink = get_post_type_archive_link( $presentation->model->object_sub_type );
415
+ $presentation->model->title = WPSEO_Options::get( 'title-ptarchive-' . $presentation->model->object_sub_type );
416
+ $presentation->model->description = WPSEO_Options::get( 'metadesc-ptarchive-' . $presentation->model->object_sub_type );
417
+ break;
418
+
419
+ case 'user':
420
+ $presentation->model->permalink = get_author_posts_url( $presentation->model->object_id );
421
+ break;
422
+
423
+ case 'system-page':
424
+ if ( '404' === $presentation->model->object_sub_type ) {
425
+ $presentation->model->title = WPSEO_Options::get( 'title-404-wpseo' );
426
+ }
427
+ break;
428
  }
429
 
430
+ return $presentation;
431
+ }
 
 
 
432
 
433
+ /**
434
+ * Fixes the breadcrumb links and strings stored in the indexable table since Yoast SEO 14.0
435
+ *
436
+ * @since 2.8.3
437
+ *
438
+ * @param array $indexables An array of Indexable objects.
439
+ * @return object
440
+ */
441
+ public function breadcrumb_indexables( $indexables ) {
442
+ foreach ( $indexables as &$indexable ) {
443
+ switch ( $indexable->object_type ) {
444
+ case 'home-page':
445
+ $indexable->permalink = pll_home_url();
446
+ $indexable->breadcrumb_title = pll__( WPSEO_Options::get( 'breadcrumbs-home' ) );
447
+ break;
448
+
449
+ case 'post-type-archive':
450
+ $indexable->permalink = get_post_type_archive_link( $indexable->object_sub_type );
451
+ $indexable->breadcrumb_title = pll__( WPSEO_Options::get( 'bctitle-ptarchive-' . $indexable->object_sub_type ) );
452
+ break;
453
+ }
454
  }
455
 
456
+ return $indexables;
457
  }
458
 
 
459
  /**
460
  * Helper function to register strings for custom post types and custom taxonomies titles and meta descriptions
461
  *
modules/sitemaps/sitemaps.php CHANGED
@@ -129,7 +129,7 @@ class PLL_Sitemaps {
129
  }
130
 
131
  foreach ( $rules as $key => $rule ) {
132
- if ( false !== strpos( $rule, 'sitemap=$matches[1]' ) ) {
133
  $newrules[ str_replace( '^wp-sitemap', $slug . 'wp-sitemap', $key ) ] = str_replace(
134
  array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
135
  array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
129
  }
130
 
131
  foreach ( $rules as $key => $rule ) {
132
+ if ( isset( $slug ) && false !== strpos( $rule, 'sitemap=$matches[1]' ) ) {
133
  $newrules[ str_replace( '^wp-sitemap', $slug . 'wp-sitemap', $key ) ] = str_replace(
134
  array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ),
135
  array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ),
modules/wizard/wizard.php CHANGED
@@ -539,7 +539,8 @@ class PLL_Wizard {
539
  );
540
  exit;
541
  }
542
- if ( 'en_US' !== $locale ) {
 
543
  wp_download_language_pack( $locale );
544
  }
545
  }
539
  );
540
  exit;
541
  }
542
+
543
+ if ( 'en_US' !== $locale && current_user_can( 'install_languages' ) ) {
544
  wp_download_language_pack( $locale );
545
  }
546
  }
polylang.php CHANGED
@@ -10,7 +10,7 @@
10
  * Plugin Name: Polylang
11
  * Plugin URI: https://polylang.pro
12
  * Description: Adds multilingual capability to WordPress
13
- * Version: 2.8.2
14
  * Requires at least: 4.9
15
  * Requires PHP: 5.6
16
  * Author: WP SYNTEX
@@ -53,7 +53,7 @@ if ( defined( 'POLYLANG_VERSION' ) ) {
53
  }
54
  } else {
55
  // Go on loading the plugin
56
- define( 'POLYLANG_VERSION', '2.8.2' );
57
  define( 'PLL_MIN_WP_VERSION', '4.9' );
58
  define( 'PLL_MIN_PHP_VERSION', '5.6' );
59
 
10
  * Plugin Name: Polylang
11
  * Plugin URI: https://polylang.pro
12
  * Description: Adds multilingual capability to WordPress
13
+ * Version: 2.8.3
14
  * Requires at least: 4.9
15
  * Requires PHP: 5.6
16
  * Author: WP SYNTEX
53
  }
54
  } else {
55
  // Go on loading the plugin
56
+ define( 'POLYLANG_VERSION', '2.8.3' );
57
  define( 'PLL_MIN_WP_VERSION', '4.9' );
58
  define( 'PLL_MIN_PHP_VERSION', '5.6' );
59
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: multilingual, bilingual, translate, translation, language, multilanguage,
5
  Requires at least: 4.9
6
  Tested up to: 5.5
7
  Requires PHP: 5.6
8
- Stable tag: 2.8.2
9
  License: GPLv3 or later
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
11
 
@@ -78,6 +78,16 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
78
 
79
  == Changelog ==
80
 
 
 
 
 
 
 
 
 
 
 
81
  = 2.8.2 (2020-09-08) =
82
 
83
  * Pro: Fix posts sharing the same slug displayed on the same page
5
  Requires at least: 4.9
6
  Tested up to: 5.5
7
  Requires PHP: 5.6
8
+ Stable tag: 2.8.3
9
  License: GPLv3 or later
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
11
 
78
 
79
  == Changelog ==
80
 
81
+ = 2.8.3 (2020-10-13) =
82
+
83
+ * Honor install_languages capability to download language packs
84
+ * Pro: Fix integrations not loaded (with The Events Calendar, CPTUI, Content blocks)
85
+ * Pro: Fix fatal error with ACF if a flexible content includes a repeater and a relationship
86
+ * Pro: Fix terms sharing their slug impossible to update without changing the slug
87
+ * When available, use wpcom_vip_get_page_by_path() instead of get_page_by_path()
88
+ * Fix queries filtered when editing a post that was declared untranslatable after it got a language
89
+ * Fix issues with Yoast SEO 14.0+ (breadcrumbs, canonical, title and description)
90
+
91
  = 2.8.2 (2020-09-08) =
92
 
93
  * Pro: Fix posts sharing the same slug displayed on the same page
settings/settings.php CHANGED
@@ -184,7 +184,7 @@ class PLL_Settings extends PLL_Admin_Base {
184
  add_settings_error( 'general', 'pll_languages_created', __( 'Language added.', 'polylang' ), 'updated' );
185
  $locale = sanitize_text_field( wp_unslash( $_POST['locale'] ) ); // phpcs:ignore WordPress.Security
186
 
187
- if ( 'en_US' !== $locale ) {
188
  // Attempts to install the language pack
189
  require_once ABSPATH . 'wp-admin/includes/translation-install.php';
190
  if ( ! wp_download_language_pack( $locale ) ) {
184
  add_settings_error( 'general', 'pll_languages_created', __( 'Language added.', 'polylang' ), 'updated' );
185
  $locale = sanitize_text_field( wp_unslash( $_POST['locale'] ) ); // phpcs:ignore WordPress.Security
186
 
187
+ if ( 'en_US' !== $locale && current_user_can( 'install_languages' ) ) {
188
  // Attempts to install the language pack
189
  require_once ABSPATH . 'wp-admin/includes/translation-install.php';
190
  if ( ! wp_download_language_pack( $locale ) ) {
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit11d7052b4ec8b12ab4b47a47ddfbd476::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit90bd76dc7672e476bcd63c4a62ea320a::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit11d7052b4ec8b12ab4b47a47ddfbd476
6
  {
7
  private static $loader;
8
 
@@ -22,15 +22,15 @@ class ComposerAutoloaderInit11d7052b4ec8b12ab4b47a47ddfbd476
22
  return self::$loader;
23
  }
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit11d7052b4ec8b12ab4b47a47ddfbd476', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
- spl_autoload_unregister(array('ComposerAutoloaderInit11d7052b4ec8b12ab4b47a47ddfbd476', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
- call_user_func(\Composer\Autoload\ComposerStaticInit11d7052b4ec8b12ab4b47a47ddfbd476::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit90bd76dc7672e476bcd63c4a62ea320a
6
  {
7
  private static $loader;
8
 
22
  return self::$loader;
23
  }
24
 
25
+ spl_autoload_register(array('ComposerAutoloaderInit90bd76dc7672e476bcd63c4a62ea320a', 'loadClassLoader'), true, true);
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
27
+ spl_autoload_unregister(array('ComposerAutoloaderInit90bd76dc7672e476bcd63c4a62ea320a', 'loadClassLoader'));
28
 
29
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
30
  if ($useStaticLoader) {
31
  require_once __DIR__ . '/autoload_static.php';
32
 
33
+ call_user_func(\Composer\Autoload\ComposerStaticInit90bd76dc7672e476bcd63c4a62ea320a::getInitializer($loader));
34
  } else {
35
  $map = require __DIR__ . '/autoload_namespaces.php';
36
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit11d7052b4ec8b12ab4b47a47ddfbd476
8
  {
9
  public static $classMap = array (
10
  'PLL_AS3CF' => __DIR__ . '/../..' . '/integrations/wp-offload-media/as3cf.php',
@@ -123,7 +123,7 @@ class ComposerStaticInit11d7052b4ec8b12ab4b47a47ddfbd476
123
  public static function getInitializer(ClassLoader $loader)
124
  {
125
  return \Closure::bind(function () use ($loader) {
126
- $loader->classMap = ComposerStaticInit11d7052b4ec8b12ab4b47a47ddfbd476::$classMap;
127
 
128
  }, null, ClassLoader::class);
129
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit90bd76dc7672e476bcd63c4a62ea320a
8
  {
9
  public static $classMap = array (
10
  'PLL_AS3CF' => __DIR__ . '/../..' . '/integrations/wp-offload-media/as3cf.php',
123
  public static function getInitializer(ClassLoader $loader)
124
  {
125
  return \Closure::bind(function () use ($loader) {
126
+ $loader->classMap = ComposerStaticInit90bd76dc7672e476bcd63c4a62ea320a::$classMap;
127
 
128
  }, null, ClassLoader::class);
129
  }