PluginProbe
Polylang / 2.0.12
Polylang v2.0.12
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
← All changes | modules/plugins/plugins-compat.php +593 -166 2.7.42.0.12 View file →
@@ -6,9 +6,9 @@
6 6 *
7 7 * @since 1.0
8 8 */
9 9 class PLL_Plugins_Compat {
10 - protected static $instance; // for singleton
10 + static protected $instance; // for singleton
11 11
12 12 /**
13 13 * Constructor
14 14 *
@@ -14,11 +14,8 @@
14 14 *
15 15 * @since 1.0
16 16 */
17 17 protected function __construct() {
18 - add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 0 );
19 - add_action( 'after_setup_theme', array( $this, 'after_setup_theme' ) );
20 -
21 18 // WordPress Importer
22 19 add_action( 'init', array( $this, 'maybe_wordpress_importer' ) );
23 20 add_filter( 'wp_import_terms', array( $this, 'wp_import_terms' ) );
24 21
@@ -24,8 +21,11 @@
24 21
25 22 // YARPP
26 23 add_action( 'init', array( $this, 'yarpp_init' ) ); // after Polylang has registered its taxonomy in setup_theme
27 24
25 + // Yoast SEO
26 + add_action( 'pll_language_defined', array( $this, 'wpseo_init' ) );
27 +
28 28 // Custom field template
29 29 add_action( 'add_meta_boxes', array( $this, 'cft_copy' ), 10, 2 );
30 30
31 31 // Aqua Resizer
@@ -30,35 +30,33 @@
30 30
31 31 // Aqua Resizer
32 32 add_filter( 'pll_home_url_black_list', array( $this, 'aq_home_url_black_list' ) );
33 33
34 + // Twenty Fourteen
35 + if ( 'twentyfourteen' == get_template() ) {
36 + add_filter( 'transient_featured_content_ids', array( $this, 'twenty_fourteen_featured_content_ids' ) );
37 + add_filter( 'option_featured-content', array( $this, 'twenty_fourteen_option_featured_content' ) );
38 + }
39 +
34 40 // Duplicate post
35 - add_filter( 'option_duplicate_post_taxonomies_blacklist', array( $this, 'duplicate_post_taxonomies_blacklist' ) );
41 + add_filter( 'option_duplicate_post_taxonomies_blacklist' , array( $this, 'duplicate_post_taxonomies_blacklist' ) );
36 42
37 - // Jetpack
38 - $this->jetpack = new PLL_Jetpack(); // Must be loaded before the plugin is active
39 - add_action( 'pll_init', array( $this->featured_content = new PLL_Featured_Content(), 'init' ) );
43 + // Jetpack 3
44 + add_action( 'jetpack_widget_get_top_posts', array( $this, 'jetpack_widget_get_top_posts' ), 10, 3 );
45 + add_filter( 'grunion_contact_form_field_html', array( $this, 'grunion_contact_form_field_html_filter' ), 10, 3 );
46 + add_filter( 'jetpack_open_graph_tags', array( $this, 'jetpack_ogp' ) );
47 + add_filter( 'jetpack_relatedposts_filter_filters', array( $this, 'jetpack_relatedposts_filter_filters' ), 10, 2 );
40 48
49 + // Jetpack infinite scroll
50 + if ( ! defined( 'PLL_AJAX_ON_FRONT' ) && isset( $_GET['infinity'], $_POST['action'] ) && 'infinite_scroll' == $_POST['action'] ) {
51 + define( 'PLL_AJAX_ON_FRONT', true );
52 + }
53 +
41 54 // WP Sweep
42 55 add_filter( 'wp_sweep_excluded_taxonomies', array( $this, 'wp_sweep_excluded_taxonomies' ) );
43 56
44 57 // Twenty Seventeen
45 58 add_action( 'init', array( $this, 'twenty_seventeen_init' ) );
46 -
47 - // No category base (works for Yoast SEO too)
48 - add_filter( 'get_terms_args', array( $this, 'no_category_base_get_terms_args' ), 5 ); // Before adding cache domain
49 -
50 - // WordPress MU Domain Mapping
51 - if ( function_exists( 'redirect_to_mapped_domain' ) ) {
52 - if ( ! defined( 'PLL_CACHE_HOME_URL' ) && ( $options = get_option( 'polylang' ) ) && $options['force_lang'] < 2 ) {
53 - define( 'PLL_CACHE_HOME_URL', false );
54 - }
55 -
56 - if ( ! get_site_option( 'dm_no_primary_domain' ) ) {
57 - remove_action( 'template_redirect', 'redirect_to_mapped_domain' );
58 - add_action( 'template_redirect', array( $this, 'dm_redirect_to_mapped_domain' ) );
59 - }
60 - }
61 59 }
62 60
63 61 /**
64 62 * Access to the single instance of the class
@@ -66,9 +64,9 @@
66 64 * @since 1.7
67 65 *
68 66 * @return object
69 67 */
70 - public static function instance() {
68 + static public function instance() {
71 69 if ( empty( self::$instance ) ) {
72 70 self::$instance = new self();
73 71 }
74 72
@@ -75,130 +73,349 @@
75 73 return self::$instance;
76 74 }
77 75
78 76 /**
79 - * Look for active plugins and load compatibility layer if needed
77 + * WordPress Importer
78 + * If WordPress Importer is active, replace the wordpress_importer_init function
80 79 *
81 - * @since 2.3
80 + * @since 1.2
82 81 */
83 - public function plugins_loaded() {
84 - // Yoast SEO
85 - if ( defined( 'WPSEO_VERSION' ) ) {
86 - add_action( 'pll_init', array( $this->wpseo = new PLL_WPSEO(), 'init' ) );
82 + function maybe_wordpress_importer() {
83 + if ( defined( 'WP_LOAD_IMPORTERS' ) && class_exists( 'WP_Import' ) ) {
84 + remove_action( 'admin_init', 'wordpress_importer_init' );
85 + add_action( 'admin_init', array( $this, 'wordpress_importer_init' ) );
87 86 }
87 + }
88 88
89 - if ( pll_is_cache_active() ) {
90 - add_action( 'pll_init', array( $this->cache_compat = new PLL_Cache_Compat(), 'init' ) );
89 + /**
90 + * WordPress Importer
91 + * Loads our child class PLL_WP_Import instead of WP_Import
92 + *
93 + * @since 1.2
94 + */
95 + function wordpress_importer_init() {
96 + $class = new ReflectionClass( 'WP_Import' );
97 + load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
98 +
99 + $GLOBALS['wp_import'] = new PLL_WP_Import();
100 + register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer' ), array( $GLOBALS['wp_import'], 'dispatch' ) );
101 + }
102 +
103 + /**
104 + * WordPress Importer
105 + * Backward Compatibility Polylang < 1.8
106 + * Sets the flag when importing a language and the file has been exported with Polylang < 1.8
107 + *
108 + * @since 1.8
109 + *
110 + * @param array $terms an array of arrays containing terms information form the WXR file
111 + * @return array
112 + */
113 + function wp_import_terms( $terms ) {
114 + include( PLL_SETTINGS_INC . '/languages.php' );
115 +
116 + foreach ( $terms as $key => $term ) {
117 + if ( 'language' === $term['term_taxonomy'] ) {
118 + $description = maybe_unserialize( $term['term_description'] );
119 + if ( empty( $description['flag_code'] ) && isset( $languages[ $description['locale'] ] ) ) {
120 + $description['flag_code'] = $languages[ $description['locale'] ][4];
121 + $terms[ $key ]['term_description'] = serialize( $description );
122 + }
123 + }
91 124 }
125 + return $terms;
126 + }
92 127
93 - // Custom Post Type UI
94 - if ( defined( 'CPTUI_VERSION' ) && class_exists( 'PLL_CPTUI' ) ) {
95 - add_action( 'pll_init', array( $this->cptui = new PLL_CPTUI(), 'init' ) );
128 + /**
129 + * YARPP
130 + * Just makes YARPP aware of the language taxonomy ( after Polylang registered it )
131 + *
132 + * @since 1.0
133 + */
134 + public function yarpp_init() {
135 + $GLOBALS['wp_taxonomies']['language']->yarpp_support = 1;
136 + }
137 +
138 + /**
139 + * Yoast SEO
140 + * Translate options and add specific filters and actions
141 + *
142 + * @since 1.6.4
143 + */
144 + public function wpseo_init() {
145 + if ( ! defined( 'WPSEO_VERSION' ) ) {
146 + return;
96 147 }
97 148
98 - // The Event Calendar
99 - if ( defined( 'TRIBE_EVENTS_FILE' ) && class_exists( 'PLL_TEC' ) ) {
100 - add_action( 'pll_init', array( $this->tec = new PLL_TEC(), 'init' ) );
149 + if ( ! PLL() instanceof PLL_Frontend ) {
150 + add_action( 'admin_init', array( $this, 'wpseo_register_strings' ) );
151 + return;
101 152 }
102 153
103 - // Beaver Builder
104 - if ( class_exists( 'FLBuilderLoader' ) && class_exists( 'PLL_FLBuilder' ) ) {
105 - $this->flbuilder = new PLL_FLBuilder();
154 + add_filter( 'option_wpseo_titles', array( $this, 'wpseo_translate_titles' ) );
155 +
156 + // Reloads options once the language has been defined to enable translations
157 + // Useful only when the language is set from content
158 + if ( did_action( 'wp_loaded' ) ) {
159 + if ( version_compare( WPSEO_VERSION, '1.7.2', '<' ) ) {
160 + global $wpseo_front;
161 + } else {
162 + $wpseo_front = WPSEO_Frontend::get_instance();
163 + }
164 +
165 + $options = version_compare( WPSEO_VERSION, '1.5', '<' ) ? get_wpseo_options_arr() : WPSEO_Options::get_option_names();
166 + foreach ( $options as $opt ) {
167 + $wpseo_front->options = array_merge( $wpseo_front->options, (array) get_option( $opt ) );
168 + }
106 169 }
107 170
108 - // Divi Builder
109 - if ( ( 'Divi' === get_template() || defined( 'ET_BUILDER_PLUGIN_VERSION' ) ) && class_exists( 'PLL_Divi_Builder' ) ) {
110 - $this->divi_builder = new PLL_Divi_Builder();
171 + // Filters sitemap queries to remove inactive language or to get
172 + // one sitemap per language when using multiple domains or subdomains
173 + // because WPSEO does not accept several domains or subdomains in one sitemap
174 + add_filter( 'wpseo_posts_join', array( $this, 'wpseo_posts_join' ), 10, 2 );
175 + add_filter( 'wpseo_posts_where', array( $this, 'wpseo_posts_where' ), 10, 2 );
176 + add_filter( 'wpseo_typecount_join', array( $this, 'wpseo_posts_join' ), 10, 2 );
177 + add_filter( 'wpseo_typecount_where', array( $this, 'wpseo_posts_where' ), 10, 2 );
178 +
179 + if ( PLL()->options['force_lang'] > 1 ) {
180 + add_filter( 'wpseo_enable_xml_sitemap_transient_caching', '__return_false' ); // Disable cache! otherwise WPSEO keeps only one domain (thanks to Junaid Bhura)
181 + add_filter( 'home_url', array( $this, 'wpseo_home_url' ) , 10, 2 ); // Fix home_url
182 + } else {
183 + // Get all terms in all languages when the language is set from the content or directory name
184 + add_filter( 'get_terms_args', array( $this, 'wpseo_remove_terms_filter' ) );
185 +
186 + // Add the homepages for all languages to the sitemap when the front page displays posts
187 + if ( ! get_option( 'page_on_front' ) ) {
188 + add_filter( 'wpseo_sitemap_post_content', array( $this, 'add_language_home_urls' ) );
189 + }
111 190 }
112 191
113 - // WP Offload Media Lite
114 - if ( function_exists( 'as3cf_init' ) && class_exists( 'PLL_AS3CF' ) ) {
115 - add_action( 'pll_init', array( $this->as3cf = new PLL_AS3CF(), 'init' ) );
192 + add_filter( 'pll_home_url_white_list', array( $this, 'wpseo_home_url_white_list' ) );
193 + add_action( 'wpseo_opengraph', array( $this, 'wpseo_ogp' ), 2 );
194 + add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) );
195 + }
196 +
197 + /**
198 + * Yoast SEO
199 + * Registers strings for custom post types and custom taxonomies titles and meta descriptions
200 + *
201 + * @since 2.0
202 + */
203 + function wpseo_register_strings() {
204 + $options = get_option( 'wpseo_titles' );
205 + foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
206 + if ( pll_is_translated_post_type( $t ) && ! empty( $options[ 'title-' . $t ] ) ) {
207 + pll_register_string( 'title-' . $t, $options[ 'title-' . $t ], 'wordpress-seo' );
208 + pll_register_string( 'metadesc-' . $t, $options[ 'metadesc-' . $t ], 'wordpress-seo' );
209 + }
116 210 }
211 + foreach ( get_post_types( array( 'has_archive' => true, '_builtin' => false ) ) as $t ) {
212 + if ( pll_is_translated_post_type( $t ) && ! empty( $options[ 'title-ptarchive-' . $t ] ) ) {
213 + pll_register_string( 'title-ptarchive-' . $t, $options[ 'title-ptarchive-' . $t ], 'wordpress-seo' );
214 + pll_register_string( 'metadesc-ptarchive-' . $t, $options[ 'metadesc-ptarchive-' . $t ], 'wordpress-seo' );
215 + }
216 + }
217 + foreach ( get_taxonomies( array( 'public' => true, '_builtin' => false ) ) as $t ) {
218 + if ( pll_is_translated_taxonomy( $t ) && ! empty( $options[ 'title-tax-' . $t ] ) ) {
219 + pll_register_string( 'title-tax-' . $t, $options[ 'title-tax-' . $t ], 'wordpress-seo' );
220 + pll_register_string( 'metadesc-tax-' . $t, $options[ 'metadesc-tax-' . $t ], 'wordpress-seo' );
221 + }
222 + }
223 + }
117 224
118 - // Content Blocks (Custom Post Widget)
119 - if ( function_exists( 'custom_post_widget_plugin_init' ) && class_exists( 'PLL_Content_Blocks' ) ) {
120 - add_action( 'pll_init', array( $this->content_blocks = new PLL_Content_Blocks(), 'init' ) );
225 + /**
226 + * Yoast SEO
227 + * Translates strings for custom post types and custom taxonomies titles and meta descriptions
228 + *
229 + * @since 2.0
230 + *
231 + * @param array $options
232 + * @return array
233 + */
234 + function wpseo_translate_titles( $options ) {
235 + if ( PLL() instanceof PLL_Frontend ) {
236 + foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
237 + if ( pll_is_translated_post_type( $t ) && ! empty( $options[ 'title-' . $t ] ) ) {
238 + $options[ 'title-' . $t ] = pll__( $options[ 'title-' . $t ] );
239 + $options[ 'metadesc-' . $t ] = pll__( $options[ 'metadesc-' . $t ] );
240 + }
241 + }
242 + foreach ( get_post_types( array( 'has_archive' => true, '_builtin' => false ) ) as $t ) {
243 + if ( pll_is_translated_post_type( $t ) && ! empty( $options[ 'title-ptarchive-' . $t ] ) ) {
244 + $options[ 'title-ptarchive-' . $t ] = pll__( $options[ 'title-ptarchive-' . $t ] );
245 + $options[ 'metadesc-ptarchive-' . $t ] = pll__( $options[ 'metadesc-ptarchive-' . $t ] );
246 + }
247 + }
248 + foreach ( get_taxonomies( array( 'public' => true, '_builtin' => false ) ) as $t ) {
249 + if ( pll_is_translated_taxonomy( $t ) && ! empty( $options[ 'title-tax-' . $t ] ) ) {
250 + $options[ 'title-tax-' . $t ] = pll__( $options[ 'title-tax-' . $t ] );
251 + $options[ 'metadesc-tax-' . $t ] = pll__( $options[ 'metadesc-tax-' . $t ] );
252 + }
253 + }
121 254 }
255 + return $options;
122 256 }
123 257
124 258 /**
125 - * Look for active plugins and load compatibility layer after the theme has been setup
259 + * Yoast SEO
260 + * Fixes the home url as well as the stylesheet url
261 + * Only when using multiple domains or subdomains
126 262 *
127 - * @since 2.3.8
263 + * @since 1.6.4
264 + *
265 + * @param string $url
266 + * @return $url
128 267 */
129 - public function after_setup_theme() {
130 - // Advanced Custom Fields Pro
131 - if ( defined( 'ACF_VERSION' ) && version_compare( ACF_VERSION, '5.7.11', '>=' ) && class_exists( 'PLL_ACF' ) ) {
132 - add_action( 'init', array( $this->acf = new PLL_ACF(), 'init' ) );
268 + public function wpseo_home_url( $url, $path ) {
269 + $uri = empty( $path ) ? ltrim( $_SERVER['REQUEST_URI'], '/' ) : $path;
270 +
271 + if ( 'sitemap_index.xml' === $uri || preg_match( '#([^/]+?)-sitemap([0-9]+)?\.xml|([a-z]+)?-?sitemap\.xsl#', $uri ) ) {
272 + $url = PLL()->links_model->switch_language_in_link( $url, PLL()->curlang );
133 273 }
134 274
135 - // Admin Columns & Admin Columns Pro
136 - if ( did_action( 'pll_init' ) && ( defined( 'AC_FILE' ) || defined( 'ACP_FILE' ) ) && class_exists( 'PLL_CPAC' ) ) {
137 - add_action( 'admin_init', array( $this->cpac = new PLL_CPAC(), 'init' ) );
275 + return $url;
276 + }
277 +
278 + /**
279 + * Yoast SEO
280 + * Get active languages for the sitemaps
281 + *
282 + * @since 2.0
283 + *
284 + * @return array list of active language slugs, empty if all languages are active
285 + */
286 + protected function wpseo_get_active_languages() {
287 + $languages = PLL()->model->get_languages_list();
288 + if ( wp_list_filter( $languages, array( 'active' => false ) ) ) {
289 + return wp_list_pluck( wp_list_filter( $languages, array( 'active' => false ), 'NOT' ), 'slug' );
138 290 }
291 + return array();
139 292 }
140 293
141 294 /**
142 - * WordPress Importer
143 - * If WordPress Importer is active, replace the wordpress_importer_init function
295 + * Yoast SEO
296 + * Modifies the sql request for posts sitemaps
297 + * Only when using multiple domains or subdomains or if some languages are not active
144 298 *
145 - * @since 1.2
299 + * @since 1.6.4
300 + *
301 + * @param string $sql JOIN clause
302 + * @param string $post_type
303 + * @return string
146 304 */
147 - public function maybe_wordpress_importer() {
148 - if ( defined( 'WP_LOAD_IMPORTERS' ) && class_exists( 'WP_Import' ) ) {
149 - remove_action( 'admin_init', 'wordpress_importer_init' );
150 - add_action( 'admin_init', array( $this, 'wordpress_importer_init' ) );
305 + public function wpseo_posts_join( $sql, $post_type ) {
306 + return pll_is_translated_post_type( $post_type ) && ( PLL()->options['force_lang'] > 1 || $this->wpseo_get_active_languages() ) ? $sql. PLL()->model->post->join_clause() : $sql;
307 + }
308 +
309 + /**
310 + * Yoast SEO
311 + * Modifies the sql request for posts sitemaps
312 + * Only when using multiple domains or subdomains or if some languages are not active
313 + *
314 + * @since 1.6.4
315 + *
316 + * @param string $sql WHERE clause
317 + * @param string $post_type
318 + * @return string
319 + */
320 + public function wpseo_posts_where( $sql, $post_type ) {
321 + if ( pll_is_translated_post_type( $post_type ) ) {
322 + if ( PLL()->options['force_lang'] > 1 ) {
323 + return $sql . PLL()->model->post->where_clause( PLL()->curlang );
324 + }
325 +
326 + if ( $languages = $this->wpseo_get_active_languages() ) {
327 + return $sql . PLL()->model->post->where_clause( $languages );
328 + }
151 329 }
330 + return $sql;
152 331 }
153 332
154 333 /**
155 - * WordPress Importer
156 - * Loads our child class PLL_WP_Import instead of WP_Import
334 + * Yoast SEO
335 + * Removes the language filter (and remove inactive languages) for the taxonomy sitemaps
336 + * Only when the language is set from the content or directory name
157 337 *
158 - * @since 1.2
338 + * @since 1.0.3
339 + *
340 + * @param array $args get_terms arguments
341 + * @return array modified list of arguments
159 342 */
160 - public function wordpress_importer_init() {
161 - $class = new ReflectionClass( 'WP_Import' );
162 - load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
343 + public function wpseo_remove_terms_filter( $args ) {
344 + if ( isset( $GLOBALS['wp_query']->query['sitemap'] ) ) {
345 + $args['lang'] = implode( ',', $this->wpseo_get_active_languages() );
346 + }
347 + return $args;
348 + }
163 349
164 - $GLOBALS['wp_import'] = new PLL_WP_Import();
165 - register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'polylang' ), array( $GLOBALS['wp_import'], 'dispatch' ) ); // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled
350 + /**
351 + * Yoast SEO
352 + * Adds the home urls for all (active) languages to the sitemap
353 + *
354 + * @since 1.9
355 + *
356 + * @param string $str additional urls to sitemap post
357 + * @return string
358 + */
359 + public function add_language_home_urls( $str ) {
360 + global $wpseo_sitemaps;
361 +
362 + $languages = wp_list_pluck( wp_list_filter( PLL()->model->get_languages_list() , array( 'active' => false ), 'NOT' ), 'slug' );
363 +
364 + foreach ( $languages as $lang ) {
365 + if ( empty( PLL()->options['hide_default'] ) || pll_default_language() !== $lang ) {
366 + $str .= $wpseo_sitemaps->sitemap_url( array(
367 + 'loc' => pll_home_url( $lang ),
368 + 'pri' => 1,
369 + 'chf' => apply_filters( 'wpseo_sitemap_homepage_change_freq', 'daily', pll_home_url( $lang ) ),
370 + ) );
371 + }
372 + }
373 + return $str;
166 374 }
167 375
168 376 /**
169 - * WordPress Importer
170 - * Backward Compatibility Polylang < 1.8
171 - * Sets the flag when importing a language and the file has been exported with Polylang < 1.8
377 + * Yoast SEO
172 378 *
173 - * @since 1.8
379 + * @since 1.1.2
174 380 *
175 - * @param array $terms an array of arrays containing terms information form the WXR file
381 + * @param array $arr
176 382 * @return array
177 383 */
178 - public function wp_import_terms( $terms ) {
179 - $languages = include PLL_SETTINGS_INC . '/languages.php';
384 + public function wpseo_home_url_white_list( $arr ) {
385 + return array_merge( $arr, array( array( 'file' => 'wordpress-seo' ) ) );
386 + }
180 387
181 - foreach ( $terms as $key => $term ) {
182 - if ( 'language' === $term['term_taxonomy'] ) {
183 - $description = maybe_unserialize( $term['term_description'] );
184 - if ( empty( $description['flag_code'] ) && isset( $languages[ $description['locale'] ] ) ) {
185 - $description['flag_code'] = $languages[ $description['locale'] ]['flag'];
186 - $terms[ $key ]['term_description'] = maybe_serialize( $description );
388 + /**
389 + * Yoast SEO
390 + * Adds opengraph support for translations
391 + *
392 + * @since 1.6
393 + */
394 + public function wpseo_ogp() {
395 + global $wpseo_og;
396 +
397 + // WPSEO already deals with the locale
398 + if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
399 + foreach ( PLL()->model->get_languages_list() as $language ) {
400 + if ( $language->slug != PLL()->curlang->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
401 + $wpseo_og->og_tag( 'og:locale:alternate', $fb_locale );
187 402 }
188 403 }
189 404 }
190 - return $terms;
191 405 }
192 406
193 407 /**
194 - * YARPP
195 - * Just makes YARPP aware of the language taxonomy ( after Polylang registered it )
408 + * Yoast SEO
409 + * Fixes the canonical front page url as unlike WP, WPSEO does not add a trailing slash to the canonical front page url
196 410 *
197 - * @since 1.0
411 + * @since 1.7.10
412 + *
413 + * @param string $url
414 + * @return $url
198 415 */
199 - public function yarpp_init() {
200 - $GLOBALS['wp_taxonomies']['language']->yarpp_support = 1;
416 + public function wpseo_canonical( $url ) {
417 + return is_front_page( $url ) && get_option( 'permalink_structure' ) ? trailingslashit( $url ) : $url;
201 418 }
202 419
203 420 /**
204 421 * Aqua Resizer
@@ -222,32 +439,166 @@
222 439 * @param object $post current post object
223 440 */
224 441 public function cft_copy( $post_type, $post ) {
225 442 global $custom_field_template;
226 - if ( isset( $custom_field_template, $_REQUEST['from_post'], $_REQUEST['new_lang'] ) && ! empty( $post ) ) { // phpcs:ignore WordPress.Security.NonceVerification
443 + if ( isset( $custom_field_template, $_REQUEST['from_post'], $_REQUEST['new_lang'] ) && ! empty( $post ) ) {
227 444 $_REQUEST['post'] = $post->ID;
228 445 }
229 446 }
230 447
231 448 /**
449 + * Twenty Fourteen
450 + * Rewrites the function Featured_Content::get_featured_post_ids()
451 + *
452 + * @since 1.4
453 + *
454 + * @param array $ids featured posts ids
455 + * @return array modified featured posts ids ( include all languages )
456 + */
457 + public function twenty_fourteen_featured_content_ids( $featured_ids ) {
458 + if ( ! did_action( 'pll_init' ) || false !== $featured_ids ) {
459 + return $featured_ids;
460 + }
461 +
462 + $settings = Featured_Content::get_setting();
463 +
464 + if ( ! $term = wpcom_vip_get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) {
465 + return $featured_ids;
466 + }
467 +
468 + // Get featured tag translations
469 + $tags = PLL()->model->term->get_translations( $term->term_id );
470 + $ids = array();
471 +
472 + // Query for featured posts in all languages
473 + // One query per language to get the correct number of posts per language
474 + foreach ( $tags as $tag ) {
475 + $_ids = get_posts( array(
476 + 'lang' => 0, // avoid language filters
477 + 'fields' => 'ids',
478 + 'numberposts' => Featured_Content::$max_posts,
479 + 'tax_query' => array( array(
480 + 'taxonomy' => 'post_tag',
481 + 'terms' => (int) $tag,
482 + ) ),
483 + ) );
484 +
485 + $ids = array_merge( $ids, $_ids );
486 + }
487 +
488 + $ids = array_map( 'absint', $ids );
489 + set_transient( 'featured_content_ids', $ids );
490 +
491 + return $ids;
492 + }
493 +
494 + /**
495 + * Twenty Fourteen
496 + * Translates the featured tag id in featured content settings
497 + * Mainly to allow hiding it when requested in featured content options
498 + * Acts only on frontend
499 + *
500 + * @since 1.4
501 + *
502 + * @param array $settings featured content settings
503 + * @return array modified $settings
504 + */
505 + public function twenty_fourteen_option_featured_content( $settings ) {
506 + if ( PLL() instanceof PLL_Frontend && $settings['tag-id'] && $tr = pll_get_term( $settings['tag-id'] ) ) {
507 + $settings['tag-id'] = $tr;
508 + }
509 +
510 + return $settings;
511 + }
512 +
513 + /**
232 514 * Duplicate Post
233 515 * Avoid duplicating the 'post_translations' taxonomy
234 516 *
235 517 * @since 1.8
236 518 *
237 - * @param array|string $taxonomies
519 + * @param array $taxonomies
238 520 * @return array
239 521 */
240 - public function duplicate_post_taxonomies_blacklist( $taxonomies ) {
241 - if ( empty( $taxonomies ) ) {
242 - $taxonomies = array(); // As we get an empty string when there is no taxonomy
522 + function duplicate_post_taxonomies_blacklist( $taxonomies ) {
523 + $taxonomies[] = 'post_translations';
524 + return $taxonomies;
525 + }
526 +
527 + /**
528 + * Jetpack
529 + * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
530 + *
531 + * @since 1.5.4
532 + */
533 + public function jetpack_widget_get_top_posts( $posts, $post_ids, $count ) {
534 + foreach ( $posts as $k => $post ) {
535 + if ( pll_current_language() !== pll_get_post_language( $post['post_id'] ) ) {
536 + unset( $posts[ $k ] );
537 + }
243 538 }
244 539
245 - $taxonomies[] = 'post_translations';
246 - return $taxonomies;
540 + return $posts;
247 541 }
248 542
249 543 /**
544 + * Jetpack
545 + * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php
546 + * Keeps using 'icl_translate' as the function registers the string
547 + *
548 + * @since 1.5.4
549 + */
550 + public function grunion_contact_form_field_html_filter( $r, $field_label, $id ) {
551 + if ( function_exists( 'icl_translate' ) ) {
552 + if ( pll_current_language() !== pll_default_language() ) {
553 + $label_translation = icl_translate( 'jetpack ', $field_label . '_label', $field_label );
554 + $r = str_replace( $field_label, $label_translation, $r );
555 + }
556 + }
557 +
558 + return $r;
559 + }
560 +
561 + /**
562 + * Jetpack
563 + * Adds opengraph support for locale and translations
564 + *
565 + * @since 1.6
566 + *
567 + * @param array $tags opengraph tags to output
568 + * @return array
569 + */
570 + public function jetpack_ogp( $tags ) {
571 + if ( did_action( 'pll_init' ) ) {
572 + foreach ( PLL()->model->get_languages_list() as $language ) {
573 + if ( $language->slug != PLL()->curlang->slug && PLL()->links->get_translation_url( $language ) && $fb_locale = self::get_fb_locale( $language ) ) {
574 + $tags['og:locale:alternate'][] = $fb_locale;
575 + }
576 + if ( $language->slug == PLL()->curlang->slug && $fb_locale = self::get_fb_locale( $language ) ) {
577 + $tags['og:locale'] = $fb_locale;
578 + }
579 + }
580 + }
581 + return $tags;
582 + }
583 +
584 + /**
585 + * Jetpack
586 + * Allows to make sure that related posts are in the correct language
587 + *
588 + * @since 1.8
589 + *
590 + * @param array $filters Array of ElasticSearch filters based on the post_id and args.
591 + * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
592 + * @return array
593 + */
594 + function jetpack_relatedposts_filter_filters( $filters, $post_id ) {
595 + $slug = sanitize_title( pll_get_post_language( $post_id, 'name' ) );
596 + $filters[] = array( 'term' => array( 'taxonomy.language.slug' => $slug ) );
597 + return $filters;
598 + }
599 +
600 + /**
250 601 * WP Sweep
251 602 * Add 'term_language' and 'term_translations' to excluded taxonomies otherwise terms loose their language and translation group
252 603 *
253 604 * @since 2.0
@@ -265,81 +616,157 @@
265 616 *
266 617 * @since 2.0.10
267 618 */
268 619 public function twenty_seventeen_init() {
269 - if ( 'twentyseventeen' === get_template() && did_action( 'pll_init' ) ) {
270 - if ( function_exists( 'twentyseventeen_panel_count' ) && PLL() instanceof PLL_Frontend ) {
271 - $num_sections = twentyseventeen_panel_count();
272 - for ( $i = 1; $i < ( 1 + $num_sections ); $i++ ) {
273 - add_filter( 'theme_mod_panel_' . $i, 'pll_get_post' );
274 - }
620 + if ( 'twentyseventeen' === get_template() && did_action( 'pll_init' ) && PLL() instanceof PLL_Frontend ) {
621 + $num_sections = twentyseventeen_panel_count();
622 + for ( $i = 1; $i < ( 1 + $num_sections ); $i++ ) {
623 + add_filter( 'theme_mod_panel_' . $i, 'pll_get_post' );
275 624 }
276 -
277 - if ( PLL() instanceof PLL_Frontend ) {
278 - add_filter( 'theme_mod_external_header_video', 'pll__' );
279 - } else {
280 - pll_register_string( __( 'Header video', 'polylang' ), get_theme_mod( 'external_header_video' ), 'Twenty Seventeen', false );
281 - }
282 625 }
283 626 }
284 627
285 628 /**
286 - * Make sure No category base plugins (including Yoast SEO) get all categories when flushing rules
629 + * Correspondance between WordPress locales and Facebook locales
630 + * @see https://translate.wordpress.org/
631 + * @see https://www.facebook.com/translations/FacebookLocales.xml
287 632 *
288 - * @since 2.1
633 + * @since 1.8.1 Update the list of locales
634 + * @since 1.6
289 635 *
290 - * @param array $args
291 - * @return array
636 + * @param object $language
637 + * @return bool|string Facebook locale, false if no correspondance found
292 638 */
293 - public function no_category_base_get_terms_args( $args ) {
294 - if ( doing_filter( 'category_rewrite_rules' ) ) {
295 - $args['lang'] = '';
296 - }
297 - return $args;
298 - }
639 + static public function get_fb_locale( $language ) {
640 + static $facebook_locales = array(
641 + 'af' => 'af_ZA',
642 + 'ak' => 'ak_GH',
643 + 'am' => 'am_ET',
644 + 'ar' => 'ar_AR',
645 + 'arq' => 'ar_AR',
646 + 'ary' => 'ar_AR',
647 + 'as' => 'as_IN',
648 + 'az' => 'az_AZ',
649 + 'bel' => 'be_BY',
650 + 'bg_BG' => 'bg_BG',
651 + 'bn_BD' => 'bn_IN',
652 + 'bre' => 'br_FR',
653 + 'bs_BA' => 'bs_BA',
654 + 'ca' => 'ca_ES',
655 + 'ceb' => 'cx_PH',
656 + 'ckb' => 'cb_IQ',
657 + 'co' => 'co_FR',
658 + 'cs_CZ' => 'cs_CZ',
659 + 'cy' => 'cy_GB',
660 + 'da_DK' => 'da_DK',
661 + 'de_CH' => 'de_DE',
662 + 'de_DE' => 'de_DE',
663 + 'de_DE_formal' => 'de_DE',
664 + 'el' => 'el_GR',
665 + 'en_AU' => 'en_US',
666 + 'en_CA' => 'en_US',
667 + 'en_GB' => 'en_GB',
668 + 'en_NZ' => 'en_US',
669 + 'en_US' => 'en_US',
670 + 'en_ZA' => 'en_US',
671 + 'eo' => 'eo_EO',
672 + 'es_AR' => 'es_LA',
673 + 'es_CL' => 'es_CL',
674 + 'es_CO' => 'es_CO',
675 + 'es_MX' => 'es_MX',
676 + 'es_PE' => 'es_LA',
677 + 'es_ES' => 'es_ES',
678 + 'es_VE' => 'es_VE',
679 + 'et' => 'et_EE',
680 + 'eu' => 'eu_ES',
681 + 'fa_IR' => 'fa_IR',
682 + 'fi' => 'fi_FI',
683 + 'fo' => 'fo_FO',
684 + 'fr_CA' => 'fr_CA',
685 + 'fr_FR' => 'fr_FR',
686 + 'fuc' => 'ff_NG',
687 + 'fy' => 'fy_NL',
688 + 'ga' => 'ga_IE',
689 + 'gl_ES' => 'gl_ES',
690 + 'gn' => 'gn_PY',
691 + 'gu' => 'gu_IN',
692 + 'he_IL' => 'he_IL',
693 + 'hi_IN' => 'hi_IN',
694 + 'hr' => 'hr_HR',
695 + 'hu_HU' => 'hu_HU',
696 + 'hy' => 'hy_AM',
697 + 'id_ID' => 'id_ID',
698 + 'is_IS' => 'is_IS',
699 + 'it_IT' => 'it_IT',
700 + 'ja' => 'ja_JP',
701 + 'jv_ID' => 'jv_ID',
702 + 'ka_GE' => 'ka_GE',
703 + 'kin' => 'rw_RW',
704 + 'kk' => 'kk_KZ',
705 + 'km' => 'km_kH',
706 + 'kn' => 'kn_IN',
707 + 'ko_KR' => 'ko_KR',
708 + 'ku' => 'ku_TR',
709 + 'ky_KY' => 'ky_KG',
710 + 'la' => 'la_Va',
711 + 'li' => 'li_NL',
712 + 'lin' => 'ln_CD',
713 + 'lo' => 'lo_LA',
714 + 'lt_LT' => 'lt_LT',
715 + 'lv' => 'lv_LV',
716 + 'mg_MG' => 'mg_MG',
717 + 'mk_MK' => 'mk_MK',
718 + 'ml_IN' => 'ml_IN',
719 + 'mn' => 'mn_MN',
720 + 'mr' => 'mr_IN',
721 + 'mri' => 'mi_NZ',
722 + 'ms_MY' => 'ms_MY',
723 + 'my_MM' => 'my_MM',
724 + 'ne_NP' => 'ne_NP',
725 + 'nb_NO' => 'nb_NO',
726 + 'nl_BE' => 'nl_BE',
727 + 'nl_NL' => 'nl_NL',
728 + 'nn_NO' => 'nn_NO',
729 + 'ory' => 'or_IN',
730 + 'pa_IN' => 'pa_IN',
731 + 'pl_PL' => 'pl_PL',
732 + 'ps' => 'ps_AF',
733 + 'pt_BR' => 'pt_BR',
734 + 'pt_PT' => 'pt_PT',
735 + 'ps' => 'ps_AF',
736 + 'ro_RO' => 'ro_RO',
737 + 'roh' => 'rm_CH',
738 + 'ru_RU' => 'ru_RU',
739 + 'sa_IN' => 'sa_IN',
740 + 'si_LK' => 'si_LK',
741 + 'sk_SK' => 'sk_SK',
742 + 'sl_SI' => 'sl_SI',
743 + 'so_SO' => 'so_SO',
744 + 'sq' => 'sq_AL',
745 + 'sr_RS' => 'sr_RS',
746 + 'srd' => 'sc_IT',
747 + 'sv_SE' => 'sv_SE',
748 + 'sw' => 'sw_KE',
749 + 'szl' => 'sz_PL',
750 + 'ta_LK' => 'ta_IN',
751 + 'ta_IN' => 'ta_IN',
752 + 'te' => 'te_IN',
753 + 'tg' => 'tg_TJ',
754 + 'th' => 'th_TH',
755 + 'tl' => 'tl_PH',
756 + 'tuk' => 'tk_TM',
757 + 'tr_TR' => 'tr_TR',
758 + 'tt_RU' => 'tt_RU',
759 + 'tzm' => 'tz_MA',
760 + 'uk' => 'uk_UA',
761 + 'ur' => 'ur_PK',
762 + 'uz_UZ' => 'uz_UZ',
763 + 'vi' => 'vi_VN',
764 + 'yor' => 'yo_NG',
765 + 'zh_CN' => 'zh_CN',
766 + 'zh_HK' => 'zh_HK',
767 + 'zh_TW' => 'zh_TW',
768 + );
299 769
300 - /**
301 - * WordPress MU Domain Mapping
302 - * Fix primary domain check which forces only one domain per blog
303 - * Accept only known domains/subdomains for the current blog
304 - *
305 - * @since 2.2
306 - */
307 - public function dm_redirect_to_mapped_domain() {
308 - $options = get_option( 'polylang' );
309 -
310 - // The language is set from the subdomain or domain name
311 - if ( $options['force_lang'] > 1 ) {
312 - // Don't redirect the main site
313 - if ( is_main_site() ) {
314 - return;
315 - }
316 -
317 - // Don't redirect post previews
318 - if ( isset( $_GET['preview'] ) && 'true' === $_GET['preview'] ) { // phpcs:ignore WordPress.Security.NonceVerification
319 - return;
320 - }
321 -
322 - // Don't redirect theme customizer
323 - if ( isset( $_POST['customize'] ) && isset( $_POST['theme'] ) && 'on' === $_POST['customize'] ) { // phpcs:ignore WordPress.Security.NonceVerification
324 - return;
325 - }
326 -
327 - // If we can't associate the requested domain to a language, redirect to the default domain
328 - $requested_url = pll_get_requested_url();
329 - $requested_host = wp_parse_url( $requested_url, PHP_URL_HOST );
330 -
331 - $hosts = PLL()->links_model->get_hosts();
332 - $lang = array_search( $requested_host, $hosts );
333 -
334 - if ( empty( $lang ) ) {
335 - $status = get_site_option( 'dm_301_redirect' ) ? '301' : '302'; // Honor status redirect option
336 - $redirect = str_replace( '://' . $requested_host, '://' . $hosts[ $options['default_lang'] ], $requested_url );
337 - wp_safe_redirect( $redirect, $status );
338 - exit;
339 - }
340 - } else {
341 - // Otherwise rely on MU Domain Mapping
342 - redirect_to_mapped_domain();
343 - }
770 + return isset( $facebook_locales[ $language->locale ] ) ? $facebook_locales[ $language->locale ] : false;
344 771 }
345 772 }