Version Description
(2022-04-12) =
- Requires WP 5.6 as minimum version
- Pro: Add compatibility with the full site editing introduced in WP 5.9
- Pro: Add a language switcher block for the navigation block introduced in WP 5.9
- Pro: Add compatibility with the new gallery block introduced in WP 5.9
- Pro: Make the language switcher block available in the widget section of the customizer
- Pro: Fix wrong category when translating the latest block
- Pro: Fix the language switcher block when using the dropdown option
- Pro: Fix some edge cases with locale fallback
- Pro: Fix post template replacing the post content when duplicating a post
- Pro: Fix synchronization groups not correctly cleaned up when a language is deleted
- Pro: Fix incorrect sticky property when duplicating / synchronizing posts
- Pro: Fix "Page for posts" label after the page has been bulk translated
- Pro: Fix translated slug when the url includes a query string
- Pro: Synchronize ACF layout fields if a child field is synchronized or translatable
- Pro: Fix wrong field group translation displayed when using object cache with ACF
- Update plugin updater to 1.9.1
- Add compatibility with the block site title introduced in WP 5.9
- Add the list of wpml-config.xml files in the site health information
- Improve the performance of the get_pages() filter #980
- Improve the compatibility of 'wpml_object_id' with the original filter #972
- Prevent term_exists to be filtered by language in WP 6.0
- Fix some PHP 8.1 deprecations #949 #985
- Fix a fatal error in PHP 8.1 #987
- Fix category feed not redirected when the langage code is wrong #887
- Fix default category not created for secondary languages (introduced in 3.1) #997
- Fix parent page when the parent post type is not translatable #1001
- Fix the Yoast SEO breadcrumb when it includes a non-synchronized taxonomy #1005
- Fix a PHP Notice when adding a new language and Yoast SEO is active #979
- Fix a PHP warning in Yoast SEO compatibility #954
Download this release
Release Info
Developer | Chouby |
Plugin | Polylang |
Version | 3.2 |
Comparing to | |
See all releases |
Code changes from version 3.1.4 to 3.2
- admin/admin-base.php +43 -3
- admin/admin-filters-post.php +1 -1
- admin/admin-model.php +34 -3
- admin/admin-static-pages.php +3 -3
- css/build/dialog.min.css +1 -1
- css/build/selectmenu.min.css +1 -1
- frontend/choose-lang-url.php +1 -1
- frontend/frontend-filters-links.php +37 -15
- frontend/frontend.php +24 -0
- include/base.php +26 -0
- include/class-polylang.php +3 -3
- include/crud-posts.php +3 -1
- include/db-tools.php +47 -0
- include/filters-links.php +3 -1
- include/filters.php +70 -24
- include/license.php +8 -8
- include/links-directory.php +2 -2
- include/model.php +12 -8
- include/olt-manager.php +1 -1
- include/rest-request.php +39 -18
- include/switcher.php +5 -7
- include/translated-object.php +267 -146
- include/translated-post.php +43 -9
- include/translated-term.php +42 -21
- include/walker-dropdown.php +3 -3
- include/widget-languages.php +1 -1
- install/plugin-updater.php +257 -233
- integrations/integrations.php +1 -1
- integrations/wp-importer/wp-import.php +7 -8
- integrations/wpseo/wpseo.php +22 -30
- modules/site-health/admin-site-health.php +43 -5
- modules/sync/sync-metas.php +0 -3
- modules/sync/sync-post-metas.php +7 -5
- modules/sync/sync-tax.php +2 -1
- modules/wpml/wpml-api.php +17 -6
- modules/wpml/wpml-config.php +21 -24
- modules/wpml/wpml-legacy-api.php +41 -14
- polylang.php +4 -4
- readme.txt +77 -26
- settings/settings-module.php +3 -2
- settings/settings.php +2 -1
- settings/table-languages.php +6 -6
- settings/table-string.php +4 -4
- settings/view-tab-strings.php +1 -1
- vendor/composer/autoload_classmap.php +1 -0
- vendor/composer/autoload_static.php +1 -0
admin/admin-base.php
CHANGED
@@ -68,6 +68,8 @@ abstract class PLL_Admin_Base extends PLL_Base {
|
|
68 |
// Adds the link to the languages panel in the WordPress admin menu
|
69 |
add_action( 'admin_menu', array( $this, 'add_menus' ) );
|
70 |
|
|
|
|
|
71 |
// Setup js scripts and css styles
|
72 |
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
73 |
add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
|
@@ -86,6 +88,9 @@ abstract class PLL_Admin_Base extends PLL_Base {
|
|
86 |
|
87 |
$this->notices = new PLL_Admin_Notices( $this );
|
88 |
|
|
|
|
|
|
|
89 |
if ( ! $this->model->get_languages_list() ) {
|
90 |
return;
|
91 |
}
|
@@ -93,8 +98,6 @@ abstract class PLL_Admin_Base extends PLL_Base {
|
|
93 |
$this->links = new PLL_Admin_Links( $this ); // FIXME needed here ?
|
94 |
$this->static_pages = new PLL_Admin_Static_Pages( $this ); // FIXME needed here ?
|
95 |
$this->filters_links = new PLL_Filters_Links( $this ); // FIXME needed here ?
|
96 |
-
$this->default_term = new PLL_Admin_Default_Term( $this );
|
97 |
-
$this->default_term->add_hooks();
|
98 |
|
99 |
// Filter admin language for users
|
100 |
// We must not call user info before WordPress defines user roles in wp-settings.php
|
@@ -366,8 +369,18 @@ abstract class PLL_Admin_Base extends PLL_Base {
|
|
366 |
$this->curlang = $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
|
367 |
}
|
368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
369 |
// Inform that the admin language has been set.
|
370 |
-
if ( $this->curlang ) {
|
371 |
/** This action is documented in frontend/choose-lang.php */
|
372 |
do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang );
|
373 |
} else {
|
@@ -497,4 +510,31 @@ abstract class PLL_Admin_Base extends PLL_Base {
|
|
497 |
);
|
498 |
}
|
499 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
500 |
}
|
68 |
// Adds the link to the languages panel in the WordPress admin menu
|
69 |
add_action( 'admin_menu', array( $this, 'add_menus' ) );
|
70 |
|
71 |
+
add_action( 'admin_menu', array( $this, 'remove_customize_submenu' ) );
|
72 |
+
|
73 |
// Setup js scripts and css styles
|
74 |
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
75 |
add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
|
88 |
|
89 |
$this->notices = new PLL_Admin_Notices( $this );
|
90 |
|
91 |
+
$this->default_term = new PLL_Admin_Default_Term( $this );
|
92 |
+
$this->default_term->add_hooks();
|
93 |
+
|
94 |
if ( ! $this->model->get_languages_list() ) {
|
95 |
return;
|
96 |
}
|
98 |
$this->links = new PLL_Admin_Links( $this ); // FIXME needed here ?
|
99 |
$this->static_pages = new PLL_Admin_Static_Pages( $this ); // FIXME needed here ?
|
100 |
$this->filters_links = new PLL_Filters_Links( $this ); // FIXME needed here ?
|
|
|
|
|
101 |
|
102 |
// Filter admin language for users
|
103 |
// We must not call user info before WordPress defines user roles in wp-settings.php
|
369 |
$this->curlang = $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
|
370 |
}
|
371 |
|
372 |
+
/**
|
373 |
+
* Filters the current language used by Polylang in the admin context.
|
374 |
+
*
|
375 |
+
* @since 3.2
|
376 |
+
*
|
377 |
+
* @param PLL_Language|false|null $curlang Instance of the current language.
|
378 |
+
* @param PLL_Admin_Base $polylang Instance of the main Polylang's object.
|
379 |
+
*/
|
380 |
+
$this->curlang = apply_filters( 'pll_admin_current_language', $this->curlang, $this );
|
381 |
+
|
382 |
// Inform that the admin language has been set.
|
383 |
+
if ( $this->curlang instanceof PLL_Language ) {
|
384 |
/** This action is documented in frontend/choose-lang.php */
|
385 |
do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang );
|
386 |
} else {
|
510 |
);
|
511 |
}
|
512 |
}
|
513 |
+
|
514 |
+
/**
|
515 |
+
* Remove the customize submenu when using a block theme.
|
516 |
+
*
|
517 |
+
* WordPress removes the Customizer menu if a block theme is activated and no other plugins interact with it.
|
518 |
+
* As Polylang interacts with the Customizer, we have to delete this menu ourselves in the case of a block theme,
|
519 |
+
* unless another plugin than Polylang interacts with the Customizer.
|
520 |
+
*
|
521 |
+
* @since 3.2
|
522 |
+
*
|
523 |
+
* @return void
|
524 |
+
*/
|
525 |
+
public function remove_customize_submenu() {
|
526 |
+
if ( ! $this->should_customize_menu_be_removed() ) {
|
527 |
+
return;
|
528 |
+
}
|
529 |
+
|
530 |
+
global $submenu;
|
531 |
+
|
532 |
+
if ( ! empty( $submenu['themes.php'] ) ) {
|
533 |
+
foreach ( $submenu['themes.php'] as $submenu_item ) {
|
534 |
+
if ( 'customize' === $submenu_item[1] ) {
|
535 |
+
remove_submenu_page( 'themes.php', $submenu_item[2] );
|
536 |
+
}
|
537 |
+
}
|
538 |
+
}
|
539 |
+
}
|
540 |
}
|
admin/admin-filters-post.php
CHANGED
@@ -59,7 +59,7 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
|
|
59 |
}
|
60 |
|
61 |
// Hierarchical taxonomies
|
62 |
-
if ( 'edit' == $screen->base && $taxonomies = get_object_taxonomies( $screen->post_type, '
|
63 |
// Get translated hierarchical taxonomies
|
64 |
$hierarchical_taxonomies = array();
|
65 |
foreach ( $taxonomies as $taxonomy ) {
|
59 |
}
|
60 |
|
61 |
// Hierarchical taxonomies
|
62 |
+
if ( 'edit' == $screen->base && $taxonomies = get_object_taxonomies( $screen->post_type, 'objects' ) ) {
|
63 |
// Get translated hierarchical taxonomies
|
64 |
$hierarchical_taxonomies = array();
|
65 |
foreach ( $taxonomies as $taxonomy ) {
|
admin/admin-model.php
CHANGED
@@ -238,13 +238,25 @@ class PLL_Admin_Model extends PLL_Model {
|
|
238 |
}
|
239 |
|
240 |
/**
|
241 |
-
* Fires
|
242 |
*
|
243 |
* @since 1.9
|
|
|
244 |
*
|
245 |
-
* @param array $args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
*/
|
247 |
-
do_action( 'pll_update_language', $args );
|
248 |
|
249 |
$this->clean_languages_cache();
|
250 |
flush_rewrite_rules(); // Refresh rewrite rules
|
@@ -454,6 +466,25 @@ class PLL_Admin_Model extends PLL_Model {
|
|
454 |
foreach ( $terms as $term ) {
|
455 |
$term_ids[ $term->taxonomy ][] = $term->term_id;
|
456 |
$tr = maybe_unserialize( $term->description );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
457 |
if ( ! empty( $tr[ $old_slug ] ) ) {
|
458 |
if ( $new_slug ) {
|
459 |
$tr[ $new_slug ] = $tr[ $old_slug ]; // Suppress this for delete
|
238 |
}
|
239 |
|
240 |
/**
|
241 |
+
* Fires after a language is updated.
|
242 |
*
|
243 |
* @since 1.9
|
244 |
+
* @since 3.2 Added $lang parameter.
|
245 |
*
|
246 |
+
* @param array<mixed> $args {
|
247 |
+
* Arguments used to modify the language. @see PLL_Admin_Model::update_language().
|
248 |
+
*
|
249 |
+
* @type string $name Language name (used only for display).
|
250 |
+
* @type string $slug Language code (ideally 2-letters ISO 639-1 language code).
|
251 |
+
* @type string $locale WordPress locale.
|
252 |
+
* @type int $rtl 1 if rtl language, 0 otherwise.
|
253 |
+
* @type int $term_group Language order when displayed.
|
254 |
+
* @type string $no_default_cat Optional, if set, no default category has been created for this language.
|
255 |
+
* @type string $flag Optional, country code, @see flags.php.
|
256 |
+
* }
|
257 |
+
* @param PLL_Language $lang Previous value of the language beeing edited.
|
258 |
*/
|
259 |
+
do_action( 'pll_update_language', $args, $lang );
|
260 |
|
261 |
$this->clean_languages_cache();
|
262 |
flush_rewrite_rules(); // Refresh rewrite rules
|
466 |
foreach ( $terms as $term ) {
|
467 |
$term_ids[ $term->taxonomy ][] = $term->term_id;
|
468 |
$tr = maybe_unserialize( $term->description );
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Filters the unserialized translation group description before it is
|
472 |
+
* updated when a language is deleted or a language slug is changed.
|
473 |
+
*
|
474 |
+
* @since 3.2
|
475 |
+
*
|
476 |
+
* @param array<int|array<string>> $tr {
|
477 |
+
* List of translations with lang codes as array keys and IDs as array values.
|
478 |
+
* Also in this array:
|
479 |
+
*
|
480 |
+
* @type array<string> $sync List of synchronized translations with lang codes as array keys and array values.
|
481 |
+
* }
|
482 |
+
* @param string $old_slug The old language slug.
|
483 |
+
* @param string $new_slug The new language slug.
|
484 |
+
* @param WP_Term $term The term containing the post or term translation group.
|
485 |
+
*/
|
486 |
+
$tr = apply_filters( 'update_translation_group', $tr, $old_slug, $new_slug, $term );
|
487 |
+
|
488 |
if ( ! empty( $tr[ $old_slug ] ) ) {
|
489 |
if ( $new_slug ) {
|
490 |
$tr[ $new_slug ] = $tr[ $old_slug ]; // Suppress this for delete
|
admin/admin-static-pages.php
CHANGED
@@ -33,7 +33,7 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
|
|
33 |
// Add post state for translations of the front page and posts page
|
34 |
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
|
35 |
|
36 |
-
//
|
37 |
add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
|
38 |
|
39 |
// Prevents WP resetting the option
|
@@ -106,7 +106,7 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
|
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
-
* Refreshes the language cache when a static front page has been translated.
|
110 |
*
|
111 |
* @since 1.8
|
112 |
*
|
@@ -116,7 +116,7 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
|
|
116 |
* @return void
|
117 |
*/
|
118 |
public function pll_save_post( $post_id, $post, $translations ) {
|
119 |
-
if ( in_array( $this->page_on_front, $translations ) ) {
|
120 |
$this->model->clean_languages_cache();
|
121 |
}
|
122 |
}
|
33 |
// Add post state for translations of the front page and posts page
|
34 |
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
|
35 |
|
36 |
+
// Refreshes the language cache when a static front page or page for for posts has been translated.
|
37 |
add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
|
38 |
|
39 |
// Prevents WP resetting the option
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
+
* Refreshes the language cache when a static front page or page for for posts has been translated.
|
110 |
*
|
111 |
* @since 1.8
|
112 |
*
|
116 |
* @return void
|
117 |
*/
|
118 |
public function pll_save_post( $post_id, $post, $translations ) {
|
119 |
+
if ( in_array( $this->page_on_front, $translations ) || in_array( $this->page_for_posts, $translations ) ) {
|
120 |
$this->model->clean_languages_cache();
|
121 |
}
|
122 |
}
|
css/build/dialog.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.pll-confirmation-modal.ui-widget,.pll-confirmation-modal
|
1 |
+
.pll-confirmation-modal .ui-widget,.pll-confirmation-modal.ui-widget,.pll-confirmation-modal.ui-widget .ui-widget{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.pll-confirmation-modal.ui-dialog{background:#fff;border:0;border-radius:0;color:#444;padding:0;z-index:100102}.ui-dialog.pll-confirmation-modal .ui-dialog-titlebar{background:#fcfcfc;border:0;border-bottom:1px solid #dfdfdf;border-radius:0;color:#444;font-size:18px;font-weight:600;height:36px;line-height:2;padding:0 36px 0 16px;position:static}.ui-dialog.pll-confirmation-modal .ui-dialog-title{float:none;margin:0;width:auto}.pll-confirmation-modal .ui-widget-header .ui-icon{background:none;position:static}.pll-confirmation-modal .ui-button.ui-dialog-titlebar-close{background:none;border:0;height:36px;margin:0;padding:0;right:0;top:0;width:36px}.ui-dialog.pll-confirmation-modal .ui-dialog-content{border:0;box-sizing:border-box;color:#444;padding:16px;position:static}.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane{background:#fcfcfc;border:0;border-top:1px solid #dfdfdf;margin:0;padding:16px}.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane .ui-button{background:#f7f7f7;border:1px solid #ccc;border-radius:3px;line-height:2;margin:0 0 0 16px;padding:0 10px 1px;position:static;vertical-align:top}.ui-dialog.pll-confirmation-modal .ui-button:focus,.ui-dialog.pll-confirmation-modal .ui-button:hover{background:#fafafa;border-color:#999;color:#23282d}.pll-confirmation-modal+.ui-widget-overlay{background:#000;opacity:.7;z-index:100101}
|
css/build/selectmenu.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.ui-widget-overlay{height:100%;left:0;position:fixed;top:0;width:100%}.ui-menu{display:block;list-style:none;margin:0;outline:none;padding:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{cursor:pointer;list-style-image:url(
|
1 |
+
.ui-widget-overlay{height:100%;left:0;position:fixed;top:0;width:100%}.ui-menu{display:block;list-style:none;margin:0;outline:none;padding:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{cursor:pointer;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);margin:0;min-height:0;padding:3px 1em 3px .4em;position:relative}.ui-menu .ui-menu-item:not([role]){padding:0}.ui-menu-item-wrapper{padding:3px 1em 3px 2em}.rtl .ui-menu .ui-menu-item{text-align:right}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item[role]{padding-left:2em}.rtl .ui-menu-icons .ui-menu-item[role],.rtl .ui-menu-item-wrapper{padding-left:1em;padding-right:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{bottom:0;left:.3em;margin:auto 0;position:absolute;top:0}.rtl .ui-menu .ui-icon,.rtl .ui-selectmenu-text .ui-icon{left:auto;right:.3em}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{display:none;left:0;margin:0;padding:0;position:absolute;top:0}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{border:0;font-size:1em;font-weight:700;height:auto;line-height:23px;margin:.5em 0 0;padding:2px .4em}.ui-selectmenu-open{display:block}.ui-selectmenu-button,.ui-selectmenu-button.ui-button{box-sizing:border-box;display:inline-block;height:28px;line-height:normal;overflow:hidden;padding:0;position:relative;text-align:left;text-decoration:none;vertical-align:top;white-space:nowrap}.ui-selectmenu-button span.ui-icon{background:none;height:16px;left:auto;position:absolute;right:.5em;text-indent:0;top:26%;width:16px}.rtl .ui-selectmenu-button span.ui-icon{left:.5em;right:auto}.ui-selectmenu-button span.ui-selectmenu-text,.ui-selectmenu-button.ui-widget span.ui-selectmenu-text{display:block;line-height:23px;margin:0;overflow:hidden;padding:.1em 2.1em .2em 2em;text-align:left;text-overflow:ellipsis;white-space:nowrap}.rtl .ui-selectmenu-button span.ui-selectmenu-text{padding:.2em 2em .2em 2.1em;text-align:right}.ui-button.ui-selectmenu-button-closed,.ui-button.ui-selectmenu-button-open,.ui-selectmenu-button.ui-state-default,.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);color:#32373c}.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-closed,.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-open,.toplevel_page_mlang .ui-selectmenu-button.ui-state-default{border:1px solid #7e8993;border-radius:4px;box-shadow:0 0 0 transparent}.pll-selectmenu-button.ui-widget,.pll-selectmenu-menu .ui-widget{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.toplevel_page_mlang .ui-button.ui-selectmenu-button:focus{background:#fff;border-color:#007cba;box-shadow:0 0 0 1px #007cba;color:#016087;outline:2px solid transparent}.toplevel_page_mlang .ui-menu-item,.toplevel_page_mlang .ui-widget-content .ui-state-active,.toplevel_page_mlang .ui-widget-content .ui-state-focus,.toplevel_page_mlang .ui-widget-content .ui-state-hover{color:#016087;margin:0}.pll-selectmenu-menu .ui-widget-content .ui-state-active,.pll-selectmenu-menu .ui-widget-content .ui-state-focus,.pll-selectmenu-menu .ui-widget-content .ui-state-hover,.ui-selectmenu-open .ui-widget-content .ui-state-active,.ui-selectmenu-open .ui-widget-content .ui-state-focus,.ui-selectmenu-open .ui-widget-content .ui-state-hover{background:#d5d5d5;border:0}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 0 top 55%;background-size:16px 16px;box-sizing:border-box;content:"";height:16px;position:absolute;width:16px}.pll-selectmenu-button.ui-button:hover,.pll-wizard .ui-button:focus,.pll-wizard .ui-button:hover{background:#fff}.ui-widget-content{box-shadow:0 2px 6px hsla(0,0%,39%,.3);max-height:231px}
|
frontend/choose-lang-url.php
CHANGED
@@ -50,7 +50,7 @@ class PLL_Choose_Lang_Url extends PLL_Choose_Lang {
|
|
50 |
|
51 |
$requested_url = pll_get_requested_url();
|
52 |
$requested_host = str_replace( 'www.', '', wp_parse_url( $requested_url, PHP_URL_HOST ) ); // Remove www. for the comparison
|
53 |
-
$requested_path = rtrim( str_replace( $this->index, '', wp_parse_url( $requested_url, PHP_URL_PATH ) ), '/' ); // Some PHP setups turn requests for / into /index.php in REQUEST_URI
|
54 |
$requested_query = wp_parse_url( $requested_url, PHP_URL_QUERY );
|
55 |
|
56 |
// Home is requested
|
50 |
|
51 |
$requested_url = pll_get_requested_url();
|
52 |
$requested_host = str_replace( 'www.', '', wp_parse_url( $requested_url, PHP_URL_HOST ) ); // Remove www. for the comparison
|
53 |
+
$requested_path = rtrim( str_replace( $this->index, '', (string) wp_parse_url( $requested_url, PHP_URL_PATH ) ), '/' ); // Some PHP setups turn requests for / into /index.php in REQUEST_URI
|
54 |
$requested_query = wp_parse_url( $requested_url, PHP_URL_QUERY );
|
55 |
|
56 |
// Home is requested
|
frontend/frontend-filters-links.php
CHANGED
@@ -291,6 +291,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
|
|
291 |
array( 'function' => 'wp_nav_menu' ),
|
292 |
array( 'function' => 'login_footer' ),
|
293 |
array( 'function' => 'get_custom_logo' ),
|
|
|
294 |
)
|
295 |
);
|
296 |
}
|
@@ -392,29 +393,35 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
|
|
392 |
}
|
393 |
}
|
394 |
|
395 |
-
elseif (
|
396 |
-
// When we receive a plain permaling with a cat query var, we need to redirect to the pretty permalink.
|
397 |
if ( $this->model->is_translated_taxonomy( $this->get_queried_taxonomy( $this->wp_query()->tax_query ) ) ) {
|
398 |
-
$
|
399 |
-
|
400 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
401 |
}
|
402 |
-
}
|
403 |
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
if ( ! empty( $obj ) && $this->model->is_translated_taxonomy( $obj->taxonomy ) ) {
|
408 |
-
$language = $this->model->term->get_language( (int) $obj->term_id );
|
409 |
}
|
410 |
}
|
411 |
|
412 |
elseif ( is_404() && ! empty( $this->wp_query()->tax_query ) ) {
|
413 |
// When a wrong language is passed through a pretty permalink, we just need to switch the language.
|
414 |
-
|
415 |
-
$term_id = $this->get_queried_term_id( $this->wp_query()->tax_query );
|
416 |
-
$language = $this->model->term->get_language( $term_id );
|
417 |
-
}
|
418 |
}
|
419 |
|
420 |
elseif ( $this->links_model->using_permalinks && $this->wp_query()->is_posts_page && ! empty( $this->wp_query()->query['page_id'] ) && $id = get_query_var( 'page_id' ) ) {
|
@@ -554,4 +561,19 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
|
|
554 |
protected function wp_query() {
|
555 |
return $GLOBALS['wp_query'];
|
556 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
}
|
291 |
array( 'function' => 'wp_nav_menu' ),
|
292 |
array( 'function' => 'login_footer' ),
|
293 |
array( 'function' => 'get_custom_logo' ),
|
294 |
+
array( 'function' => 'render_block_core_site_title' ),
|
295 |
)
|
296 |
);
|
297 |
}
|
393 |
}
|
394 |
}
|
395 |
|
396 |
+
elseif ( is_category() || is_tag() || is_tax() ) {
|
|
|
397 |
if ( $this->model->is_translated_taxonomy( $this->get_queried_taxonomy( $this->wp_query()->tax_query ) ) ) {
|
398 |
+
if ( $this->links_model->using_permalinks && ( ! empty( $this->wp_query()->query['cat'] ) || ! empty( $this->wp_query()->query['tag'] ) ) ) {
|
399 |
+
// When we receive a plain permalink with a cat or tag query var, we need to redirect to the pretty permalink.
|
400 |
+
$term_id = $this->get_queried_term_id( $this->wp_query()->tax_query );
|
401 |
+
if ( is_feed() ) {
|
402 |
+
$redirect_url = $this->maybe_add_page_to_redirect_url( get_term_feed_link( $term_id, '' ) );
|
403 |
+
} else {
|
404 |
+
$redirect_url = $this->maybe_add_page_to_redirect_url( get_term_link( $term_id ) );
|
405 |
+
}
|
406 |
+
$language = $this->get_queried_term_language();
|
407 |
+
} else {
|
408 |
+
// We need to switch the language when there is no language provided in a pretty permalink.
|
409 |
+
$obj = get_queried_object();
|
410 |
+
if ( ! empty( $obj ) && $this->model->is_translated_taxonomy( $obj->taxonomy ) ) {
|
411 |
+
$language = $this->model->term->get_language( (int) $obj->term_id );
|
412 |
+
}
|
413 |
+
}
|
414 |
}
|
|
|
415 |
|
416 |
+
if ( is_feed() && empty( $obj ) ) {
|
417 |
+
// Allows to replace the language correctly in a category feed query.
|
418 |
+
$language = $this->get_queried_term_language();
|
|
|
|
|
419 |
}
|
420 |
}
|
421 |
|
422 |
elseif ( is_404() && ! empty( $this->wp_query()->tax_query ) ) {
|
423 |
// When a wrong language is passed through a pretty permalink, we just need to switch the language.
|
424 |
+
$language = $this->get_queried_term_language();
|
|
|
|
|
|
|
425 |
}
|
426 |
|
427 |
elseif ( $this->links_model->using_permalinks && $this->wp_query()->is_posts_page && ! empty( $this->wp_query()->query['page_id'] ) && $id = get_query_var( 'page_id' ) ) {
|
561 |
protected function wp_query() {
|
562 |
return $GLOBALS['wp_query'];
|
563 |
}
|
564 |
+
|
565 |
+
/**
|
566 |
+
* Get the language corresponding to the queried term.
|
567 |
+
*
|
568 |
+
* @since 3.2
|
569 |
+
*
|
570 |
+
* @return PLL_Language|false The language object or false.
|
571 |
+
*/
|
572 |
+
public function get_queried_term_language() {
|
573 |
+
if ( $this->model->is_translated_taxonomy( $this->get_queried_taxonomy( $this->wp_query()->tax_query ) ) ) {
|
574 |
+
$term_id = $this->get_queried_term_id( $this->wp_query()->tax_query );
|
575 |
+
return $this->model->term->get_language( $term_id );
|
576 |
+
}
|
577 |
+
return false;
|
578 |
+
}
|
579 |
}
|
frontend/frontend.php
CHANGED
@@ -85,6 +85,8 @@ class PLL_Frontend extends PLL_Base {
|
|
85 |
if ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) {
|
86 |
add_action( 'template_redirect', array( $this, 'auto_translate' ), 7 );
|
87 |
}
|
|
|
|
|
88 |
}
|
89 |
|
90 |
/**
|
@@ -233,4 +235,26 @@ class PLL_Frontend extends PLL_Base {
|
|
233 |
$this->load_strings_translations();
|
234 |
}
|
235 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
}
|
85 |
if ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) {
|
86 |
add_action( 'template_redirect', array( $this, 'auto_translate' ), 7 );
|
87 |
}
|
88 |
+
|
89 |
+
add_action( 'admin_bar_menu', array( $this, 'remove_customize_admin_bar' ), 41 ); // After WP_Admin_Bar::add_menus
|
90 |
}
|
91 |
|
92 |
/**
|
235 |
$this->load_strings_translations();
|
236 |
}
|
237 |
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Remove the customize admin bar on front-end when using a block theme.
|
241 |
+
*
|
242 |
+
* WordPress removes the Customizer menu if a block theme is activated and no other plugins interact with it.
|
243 |
+
* As Polylang interacts with the Customizer, we have to delete this menu ourselves in the case of a block theme,
|
244 |
+
* unless another plugin than Polylang interacts with the Customizer.
|
245 |
+
*
|
246 |
+
* @since 3.2
|
247 |
+
*
|
248 |
+
* @return void
|
249 |
+
*/
|
250 |
+
public function remove_customize_admin_bar() {
|
251 |
+
if ( ! $this->should_customize_menu_be_removed() ) {
|
252 |
+
return;
|
253 |
+
}
|
254 |
+
|
255 |
+
global $wp_admin_bar;
|
256 |
+
|
257 |
+
remove_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' ); // To avoid the script launch.
|
258 |
+
$wp_admin_bar->remove_menu( 'customize' );
|
259 |
+
}
|
260 |
}
|
include/base.php
CHANGED
@@ -167,4 +167,30 @@ abstract class PLL_Base {
|
|
167 |
*/
|
168 |
return $new_blog_id !== $prev_blog_id && in_array( POLYLANG_BASENAME, $plugins ) && get_option( 'polylang' );
|
169 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
}
|
167 |
*/
|
168 |
return $new_blog_id !== $prev_blog_id && in_array( POLYLANG_BASENAME, $plugins ) && get_option( 'polylang' );
|
169 |
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Check if the customize menu should be removed or not.
|
173 |
+
*
|
174 |
+
* @since 3.2
|
175 |
+
*
|
176 |
+
* @return bool True if it should be removed, false otherwise.
|
177 |
+
*/
|
178 |
+
public function should_customize_menu_be_removed() {
|
179 |
+
// Exit if a block theme isn't activated.
|
180 |
+
if ( ! function_exists( 'wp_is_block_theme' ) || ! wp_is_block_theme() ) {
|
181 |
+
return false;
|
182 |
+
}
|
183 |
+
|
184 |
+
global $wp_filter;
|
185 |
+
if ( empty( $wp_filter['customize_register'] ) ) {
|
186 |
+
return false;
|
187 |
+
}
|
188 |
+
|
189 |
+
$customize_register_hooks = count( array_merge( ...array_values( $wp_filter['customize_register']->callbacks ) ) );
|
190 |
+
if ( $customize_register_hooks > 1 ) {
|
191 |
+
return false;
|
192 |
+
}
|
193 |
+
|
194 |
+
return true;
|
195 |
+
}
|
196 |
}
|
include/class-polylang.php
CHANGED
@@ -95,10 +95,10 @@ class Polylang {
|
|
95 |
*/
|
96 |
public static function is_rest_request() {
|
97 |
// Handle pretty permalinks.
|
98 |
-
$home_path = trim( wp_parse_url( home_url(), PHP_URL_PATH ), '/' );
|
99 |
$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
|
100 |
|
101 |
-
$req_uri = trim( wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' );
|
102 |
$req_uri = preg_replace( $home_path_regex, '', $req_uri );
|
103 |
$req_uri = trim( $req_uri, '/' );
|
104 |
$req_uri = str_replace( 'index.php', '', $req_uri );
|
@@ -106,7 +106,7 @@ class Polylang {
|
|
106 |
|
107 |
// And also test rest_route query string parameter is not empty for plain permalinks.
|
108 |
$query_string = array();
|
109 |
-
wp_parse_str( wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY ), $query_string );
|
110 |
$rest_route = isset( $query_string['rest_route'] ) ? trim( $query_string['rest_route'], '/' ) : false;
|
111 |
|
112 |
return 0 === strpos( $req_uri, rest_get_url_prefix() . '/' ) || ! empty( $rest_route );
|
95 |
*/
|
96 |
public static function is_rest_request() {
|
97 |
// Handle pretty permalinks.
|
98 |
+
$home_path = trim( (string) wp_parse_url( home_url(), PHP_URL_PATH ), '/' );
|
99 |
$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
|
100 |
|
101 |
+
$req_uri = trim( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' );
|
102 |
$req_uri = preg_replace( $home_path_regex, '', $req_uri );
|
103 |
$req_uri = trim( $req_uri, '/' );
|
104 |
$req_uri = str_replace( 'index.php', '', $req_uri );
|
106 |
|
107 |
// And also test rest_route query string parameter is not empty for plain permalinks.
|
108 |
$query_string = array();
|
109 |
+
wp_parse_str( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_QUERY ), $query_string );
|
110 |
$rest_route = isset( $query_string['rest_route'] ) ? trim( $query_string['rest_route'], '/' ) : false;
|
111 |
|
112 |
return 0 === strpos( $req_uri, rest_get_url_prefix() . '/' ) || ! empty( $rest_route );
|
include/crud-posts.php
CHANGED
@@ -197,10 +197,12 @@ class PLL_CRUD_Posts {
|
|
197 |
*/
|
198 |
public function wp_insert_post_parent( $post_parent, $post_id ) {
|
199 |
$lang = $this->model->post->get_language( $post_id );
|
|
|
200 |
// Dont break the hierarchy in case the post has no language
|
201 |
-
if ( ! empty( $lang ) ) {
|
202 |
$post_parent = $this->model->post->get_translation( $post_parent, $lang );
|
203 |
}
|
|
|
204 |
return $post_parent;
|
205 |
}
|
206 |
|
197 |
*/
|
198 |
public function wp_insert_post_parent( $post_parent, $post_id ) {
|
199 |
$lang = $this->model->post->get_language( $post_id );
|
200 |
+
$parent_post_type = $post_parent > 0 ? get_post_type( $post_parent ) : null;
|
201 |
// Dont break the hierarchy in case the post has no language
|
202 |
+
if ( ! empty( $lang ) && ! empty( $parent_post_type ) && $this->model->is_translated_post_type( $parent_post_type ) ) {
|
203 |
$post_parent = $this->model->post->get_translation( $post_parent, $lang );
|
204 |
}
|
205 |
+
|
206 |
return $post_parent;
|
207 |
}
|
208 |
|
include/db-tools.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @package Polylang
|
4 |
+
*/
|
5 |
+
|
6 |
+
defined( 'ABSPATH' ) || exit; // @phpstan-ignore-line
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Small set of tools to work with the database.
|
10 |
+
*
|
11 |
+
* @since 3.2
|
12 |
+
*/
|
13 |
+
class PLL_Db_Tools {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Changes an array of values into a comma separated list, ready to be used in a `IN ()` clause.
|
17 |
+
* Only string and integers and supported for now.
|
18 |
+
*
|
19 |
+
* @since 3.2
|
20 |
+
*
|
21 |
+
* @param array<int|string> $values An array of values.
|
22 |
+
* @return string A comma separated list of values.
|
23 |
+
*/
|
24 |
+
public static function prepare_values_list( $values ) {
|
25 |
+
$values = array_map( array( __CLASS__, 'prepare_value' ), (array) $values );
|
26 |
+
|
27 |
+
return implode( ',', $values );
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Wraps a value in escaped double quotes or casts as an integer.
|
32 |
+
* Only string and integers and supported for now.
|
33 |
+
*
|
34 |
+
* @since 3.2
|
35 |
+
* @global wpdb $wpdb
|
36 |
+
*
|
37 |
+
* @param int|string $value A value.
|
38 |
+
* @return int|string
|
39 |
+
*/
|
40 |
+
public static function prepare_value( $value ) {
|
41 |
+
if ( ! is_numeric( $value ) ) {
|
42 |
+
return $GLOBALS['wpdb']->prepare( '%s', $value );
|
43 |
+
}
|
44 |
+
|
45 |
+
return (int) $value;
|
46 |
+
}
|
47 |
+
}
|
include/filters-links.php
CHANGED
@@ -163,7 +163,9 @@ class PLL_Filters_Links {
|
|
163 |
// In case someone calls get_term_link for the 'language' taxonomy.
|
164 |
if ( 'language' === $tax ) {
|
165 |
$lang = $this->model->get_language( $term->term_id );
|
166 |
-
|
|
|
|
|
167 |
}
|
168 |
|
169 |
return $link;
|
163 |
// In case someone calls get_term_link for the 'language' taxonomy.
|
164 |
if ( 'language' === $tax ) {
|
165 |
$lang = $this->model->get_language( $term->term_id );
|
166 |
+
if ( $lang ) {
|
167 |
+
return $this->links_model->home_url( $lang );
|
168 |
+
}
|
169 |
}
|
170 |
|
171 |
return $link;
|
include/filters.php
CHANGED
@@ -79,6 +79,9 @@ class PLL_Filters {
|
|
79 |
|
80 |
// Personal data exporter
|
81 |
add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'register_personal_data_exporter' ), 0 ); // Since WP 4.9.6
|
|
|
|
|
|
|
82 |
}
|
83 |
|
84 |
/**
|
@@ -200,36 +203,20 @@ class PLL_Filters {
|
|
200 |
|
201 |
static $once = false;
|
202 |
|
203 |
-
// Obliged to redo the get_pages query if we want to get the right number
|
204 |
if ( ! empty( $args['number'] ) && ! $once ) {
|
205 |
-
|
206 |
-
|
207 |
-
$r = array(
|
208 |
-
'lang' => 0, // So this query is not filtered
|
209 |
-
'numberposts' => -1,
|
210 |
-
'nopaging' => true,
|
211 |
-
'post_type' => $args['post_type'],
|
212 |
-
'fields' => 'ids',
|
213 |
-
'tax_query' => array(
|
214 |
-
array(
|
215 |
-
'taxonomy' => 'language',
|
216 |
-
'field' => 'term_taxonomy_id', // Since WP 3.5
|
217 |
-
'terms' => $language->term_taxonomy_id,
|
218 |
-
'operator' => 'NOT IN',
|
219 |
-
),
|
220 |
-
),
|
221 |
-
);
|
222 |
|
223 |
// Take care that 'exclude' argument accepts integer or strings too.
|
224 |
-
$args['exclude'] = array_merge( wp_parse_id_list( $args['exclude'] ),
|
225 |
$pages = get_pages( $args );
|
226 |
}
|
227 |
|
228 |
$ids = wp_list_pluck( $pages, 'ID' );
|
229 |
|
230 |
-
// Filters the queried list of pages by language
|
231 |
if ( ! $once ) {
|
232 |
-
|
|
|
233 |
|
234 |
foreach ( $pages as $key => $page ) {
|
235 |
if ( ! in_array( $page->ID, $ids ) ) {
|
@@ -237,16 +224,47 @@ class PLL_Filters {
|
|
237 |
}
|
238 |
}
|
239 |
|
240 |
-
$pages = array_values( $pages ); // In case 3rd parties suppose the existence of $pages[0]
|
241 |
}
|
242 |
|
243 |
-
// Not done by WP but extremely useful for performance when manipulating taxonomies
|
244 |
update_object_term_cache( $ids, $args['post_type'] );
|
245 |
|
246 |
-
$once = false; // In case get_pages is called another time
|
247 |
return $pages;
|
248 |
}
|
249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
/**
|
251 |
* Modifies the sql request for get_adjacent_post to filter by the current language.
|
252 |
*
|
@@ -399,4 +417,32 @@ class PLL_Filters {
|
|
399 |
'done' => true,
|
400 |
);
|
401 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 |
}
|
79 |
|
80 |
// Personal data exporter
|
81 |
add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'register_personal_data_exporter' ), 0 ); // Since WP 4.9.6
|
82 |
+
|
83 |
+
// Fix for `term_exists()`.
|
84 |
+
add_filter( 'term_exists_default_query_args', array( $this, 'term_exists_default_query_args' ), 0, 3 ); // Since WP 6.0.0.
|
85 |
}
|
86 |
|
87 |
/**
|
203 |
|
204 |
static $once = false;
|
205 |
|
|
|
206 |
if ( ! empty( $args['number'] ) && ! $once ) {
|
207 |
+
// We are obliged to redo the get_pages() query if we want to get the right number.
|
208 |
+
$once = true; // Avoid infinite loop.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
|
210 |
// Take care that 'exclude' argument accepts integer or strings too.
|
211 |
+
$args['exclude'] = array_merge( wp_parse_id_list( $args['exclude'] ), $this->get_related_page_ids( $language, 'NOT IN', $args ) ); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude
|
212 |
$pages = get_pages( $args );
|
213 |
}
|
214 |
|
215 |
$ids = wp_list_pluck( $pages, 'ID' );
|
216 |
|
|
|
217 |
if ( ! $once ) {
|
218 |
+
// Filters the queried list of pages by language.
|
219 |
+
$ids = array_intersect( $ids, $this->get_related_page_ids( $language, 'IN', $args ) );
|
220 |
|
221 |
foreach ( $pages as $key => $page ) {
|
222 |
if ( ! in_array( $page->ID, $ids ) ) {
|
224 |
}
|
225 |
}
|
226 |
|
227 |
+
$pages = array_values( $pages ); // In case 3rd parties suppose the existence of $pages[0].
|
228 |
}
|
229 |
|
230 |
+
// Not done by WP but extremely useful for performance when manipulating taxonomies.
|
231 |
update_object_term_cache( $ids, $args['post_type'] );
|
232 |
|
233 |
+
$once = false; // In case get_pages() is called another time.
|
234 |
return $pages;
|
235 |
}
|
236 |
|
237 |
+
/**
|
238 |
+
* Get page ids related to a get_pages() in or not in a given language.
|
239 |
+
*
|
240 |
+
* @since 3.2
|
241 |
+
*
|
242 |
+
* @param PLL_Language $language The language to use in the relationship
|
243 |
+
* @param string $relation 'IN' or 'NOT IN'.
|
244 |
+
* @param array $args Array of get_pages() arguments.
|
245 |
+
* @return int[]
|
246 |
+
*/
|
247 |
+
protected function get_related_page_ids( $language, $relation, $args ) {
|
248 |
+
$r = array(
|
249 |
+
'lang' => '', // Ensure this query is not filtered.
|
250 |
+
'numberposts' => -1,
|
251 |
+
'nopaging' => true,
|
252 |
+
'post_type' => $args['post_type'],
|
253 |
+
'post_status' => $args['post_status'],
|
254 |
+
'fields' => 'ids',
|
255 |
+
'tax_query' => array(
|
256 |
+
array(
|
257 |
+
'taxonomy' => 'language',
|
258 |
+
'field' => 'term_taxonomy_id', // Since WP 3.5.
|
259 |
+
'terms' => $language->term_taxonomy_id,
|
260 |
+
'operator' => $relation,
|
261 |
+
),
|
262 |
+
),
|
263 |
+
);
|
264 |
+
|
265 |
+
return get_posts( $r );
|
266 |
+
}
|
267 |
+
|
268 |
/**
|
269 |
* Modifies the sql request for get_adjacent_post to filter by the current language.
|
270 |
*
|
417 |
'done' => true,
|
418 |
);
|
419 |
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Filters default query arguments for checking if a term exists.
|
423 |
+
* In `term_exists()`, WP 6.0 uses `get_terms()`, which is filtered by language by Polylang.
|
424 |
+
* This filter prevents `term_exists()` to be filtered by language.
|
425 |
+
*
|
426 |
+
* @since 3.2
|
427 |
+
*
|
428 |
+
* @param array<mixed> $defaults An array of arguments passed to get_terms().
|
429 |
+
* @param int|string $term The term to check. Accepts term ID, slug, or name.
|
430 |
+
* @param string $taxonomy The taxonomy name to use. An empty string indicates the search is against all taxonomies.
|
431 |
+
* @return array<mixed>
|
432 |
+
*/
|
433 |
+
public function term_exists_default_query_args( $defaults, $term, $taxonomy ) {
|
434 |
+
if ( ! empty( $taxonomy ) && ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
|
435 |
+
return $defaults;
|
436 |
+
}
|
437 |
+
|
438 |
+
if ( ! is_array( $defaults ) ) {
|
439 |
+
$defaults = array();
|
440 |
+
}
|
441 |
+
|
442 |
+
if ( ! isset( $defaults['lang'] ) ) {
|
443 |
+
$defaults['lang'] = '';
|
444 |
+
}
|
445 |
+
|
446 |
+
return $defaults;
|
447 |
+
}
|
448 |
}
|
include/license.php
CHANGED
@@ -138,12 +138,12 @@ class PLL_License {
|
|
138 |
}
|
139 |
|
140 |
/**
|
141 |
-
*
|
142 |
*
|
143 |
* @since 1.9
|
144 |
*
|
145 |
-
* @param string $license_key
|
146 |
-
* @return
|
147 |
*/
|
148 |
public function activate_license( $license_key ) {
|
149 |
$this->license_key = $license_key;
|
@@ -156,11 +156,11 @@ class PLL_License {
|
|
156 |
|
157 |
|
158 |
/**
|
159 |
-
*
|
160 |
*
|
161 |
* @since 1.9
|
162 |
*
|
163 |
-
* @return
|
164 |
*/
|
165 |
public function deactivate_license() {
|
166 |
$this->api_request( 'deactivate_license' );
|
@@ -168,11 +168,11 @@ class PLL_License {
|
|
168 |
}
|
169 |
|
170 |
/**
|
171 |
-
*
|
172 |
*
|
173 |
* @since 1.9
|
174 |
*
|
175 |
-
* @return
|
176 |
*/
|
177 |
public function check_license() {
|
178 |
$this->api_request( 'check_license' );
|
@@ -331,7 +331,7 @@ class PLL_License {
|
|
331 |
$class = 'notice-warning notice-alt';
|
332 |
$message = sprintf(
|
333 |
/* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
|
334 |
-
esc_html__( 'Your license key will expire soon! Precisely, it will expire on %1$s. %2$sRenew your license key today!%3$s
|
335 |
esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
|
336 |
sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
|
337 |
'</a>'
|
138 |
}
|
139 |
|
140 |
/**
|
141 |
+
* Activates the license key.
|
142 |
*
|
143 |
* @since 1.9
|
144 |
*
|
145 |
+
* @param string $license_key Activation key.
|
146 |
+
* @return PLL_License Updated PLL_License object.
|
147 |
*/
|
148 |
public function activate_license( $license_key ) {
|
149 |
$this->license_key = $license_key;
|
156 |
|
157 |
|
158 |
/**
|
159 |
+
* Deactivates the license key.
|
160 |
*
|
161 |
* @since 1.9
|
162 |
*
|
163 |
+
* @return PLL_License Updated PLL_License object.
|
164 |
*/
|
165 |
public function deactivate_license() {
|
166 |
$this->api_request( 'deactivate_license' );
|
168 |
}
|
169 |
|
170 |
/**
|
171 |
+
* Checks if the license key is valid.
|
172 |
*
|
173 |
* @since 1.9
|
174 |
*
|
175 |
+
* @return PLL_License Updated PLL_License object.
|
176 |
*/
|
177 |
public function check_license() {
|
178 |
$this->api_request( 'check_license' );
|
331 |
$class = 'notice-warning notice-alt';
|
332 |
$message = sprintf(
|
333 |
/* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
|
334 |
+
esc_html__( 'Your license key will expire soon! Precisely, it will expire on %1$s. %2$sRenew your license key today!%3$s', 'polylang' ),
|
335 |
esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
|
336 |
sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
|
337 |
'</a>'
|
include/links-directory.php
CHANGED
@@ -123,10 +123,10 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
|
|
123 |
$url = pll_get_requested_url();
|
124 |
}
|
125 |
|
126 |
-
$path = wp_parse_url( $url, PHP_URL_PATH );
|
127 |
$root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root;
|
128 |
|
129 |
-
$pattern = wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
|
130 |
$pattern = preg_quote( $pattern, '#' );
|
131 |
$pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(/|$)#';
|
132 |
return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
|
123 |
$url = pll_get_requested_url();
|
124 |
}
|
125 |
|
126 |
+
$path = (string) wp_parse_url( $url, PHP_URL_PATH );
|
127 |
$root = ( false === strpos( $url, '://' ) ) ? $this->home_relative . $this->root : $this->home . '/' . $this->root;
|
128 |
|
129 |
+
$pattern = (string) wp_parse_url( $root . ( $this->options['rewrite'] ? '' : 'language/' ), PHP_URL_PATH );
|
130 |
$pattern = preg_quote( $pattern, '#' );
|
131 |
$pattern = '#^' . $pattern . '(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')(/|$)#';
|
132 |
return preg_match( $pattern, trailingslashit( $path ), $matches ) ? $matches[1] : ''; // $matches[1] is the slug of the requested language
|
include/model.php
CHANGED
@@ -80,19 +80,24 @@ class PLL_Model {
|
|
80 |
*/
|
81 |
public function get_languages_list( $args = array() ) {
|
82 |
if ( false === $languages = $this->cache->get( 'languages' ) ) {
|
|
|
83 |
|
84 |
// Create the languages from taxonomies.
|
85 |
if ( ( defined( 'PLL_CACHE_LANGUAGES' ) && ! PLL_CACHE_LANGUAGES ) || false === ( $languages = get_transient( 'pll_languages_list' ) ) ) {
|
86 |
-
$languages =
|
87 |
-
|
|
|
|
|
88 |
|
89 |
$term_languages = get_terms( 'term_language', array( 'hide_empty' => false ) );
|
90 |
$term_languages = empty( $term_languages ) || is_wp_error( $term_languages ) ?
|
91 |
array() : array_combine( wp_list_pluck( $term_languages, 'slug' ), $term_languages );
|
92 |
|
93 |
-
if ( ! empty( $
|
94 |
-
foreach ( $
|
95 |
-
|
|
|
|
|
96 |
}
|
97 |
|
98 |
// We will need the languages list to allow its access in the filter below.
|
@@ -116,9 +121,6 @@ class PLL_Model {
|
|
116 |
*/
|
117 |
set_transient( 'pll_languages_list', array_map( 'get_object_vars', $languages ) );
|
118 |
}
|
119 |
-
else {
|
120 |
-
$languages = array(); // In case something went wrong.
|
121 |
-
}
|
122 |
}
|
123 |
|
124 |
// Create the languages directly from arrays stored in transients.
|
@@ -508,6 +510,8 @@ class PLL_Model {
|
|
508 |
$counts = wp_cache_get( $cache_key, 'counts' );
|
509 |
|
510 |
if ( false === $counts ) {
|
|
|
|
|
511 |
$select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
|
512 |
$join = $this->post->join_clause();
|
513 |
$where = sprintf( " WHERE post_status = '%s'", esc_sql( $q['post_status'] ) );
|
80 |
*/
|
81 |
public function get_languages_list( $args = array() ) {
|
82 |
if ( false === $languages = $this->cache->get( 'languages' ) ) {
|
83 |
+
$languages = array();
|
84 |
|
85 |
// Create the languages from taxonomies.
|
86 |
if ( ( defined( 'PLL_CACHE_LANGUAGES' ) && ! PLL_CACHE_LANGUAGES ) || false === ( $languages = get_transient( 'pll_languages_list' ) ) ) {
|
87 |
+
$languages = array();
|
88 |
+
|
89 |
+
$post_languages = get_terms( 'language', array( 'hide_empty' => false, 'orderby' => 'term_group' ) );
|
90 |
+
$post_languages = empty( $post_languages ) || is_wp_error( $post_languages ) ? array() : $post_languages;
|
91 |
|
92 |
$term_languages = get_terms( 'term_language', array( 'hide_empty' => false ) );
|
93 |
$term_languages = empty( $term_languages ) || is_wp_error( $term_languages ) ?
|
94 |
array() : array_combine( wp_list_pluck( $term_languages, 'slug' ), $term_languages );
|
95 |
|
96 |
+
if ( ! empty( $post_languages ) && ! empty( $term_languages ) ) {
|
97 |
+
foreach ( $post_languages as $k => $v ) {
|
98 |
+
if ( isset( $term_languages[ 'pll_' . $v->slug ] ) ) {
|
99 |
+
$languages[ $k ] = new PLL_Language( $v, $term_languages[ 'pll_' . $v->slug ] );
|
100 |
+
}
|
101 |
}
|
102 |
|
103 |
// We will need the languages list to allow its access in the filter below.
|
121 |
*/
|
122 |
set_transient( 'pll_languages_list', array_map( 'get_object_vars', $languages ) );
|
123 |
}
|
|
|
|
|
|
|
124 |
}
|
125 |
|
126 |
// Create the languages directly from arrays stored in transients.
|
510 |
$counts = wp_cache_get( $cache_key, 'counts' );
|
511 |
|
512 |
if ( false === $counts ) {
|
513 |
+
$counts = array();
|
514 |
+
|
515 |
$select = "SELECT pll_tr.term_taxonomy_id, COUNT( * ) AS num_posts FROM {$wpdb->posts}";
|
516 |
$join = $this->post->join_clause();
|
517 |
$where = sprintf( " WHERE post_status = '%s'", esc_sql( $q['post_status'] ) );
|
include/olt-manager.php
CHANGED
@@ -74,7 +74,7 @@ class PLL_OLT_Manager {
|
|
74 |
*
|
75 |
* @since 1.7
|
76 |
*
|
77 |
-
* @return
|
78 |
*/
|
79 |
public static function instance() {
|
80 |
if ( empty( self::$instance ) ) {
|
74 |
*
|
75 |
* @since 1.7
|
76 |
*
|
77 |
+
* @return PLL_OLT_Manager
|
78 |
*/
|
79 |
public static function instance() {
|
80 |
if ( empty( self::$instance ) ) {
|
include/rest-request.php
CHANGED
@@ -9,34 +9,39 @@
|
|
9 |
* @since 2.6
|
10 |
*/
|
11 |
class PLL_REST_Request extends PLL_Base {
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
/**
|
14 |
-
* @var PLL_Filters
|
15 |
*/
|
16 |
public $filters;
|
17 |
|
18 |
/**
|
19 |
-
* @var PLL_Filters_Links
|
20 |
*/
|
21 |
public $filters_links;
|
22 |
|
23 |
/**
|
24 |
-
* @var PLL_Admin_Links
|
25 |
*/
|
26 |
public $links;
|
27 |
|
28 |
/**
|
29 |
-
* @var PLL_Nav_Menu
|
30 |
*/
|
31 |
public $nav_menu;
|
32 |
|
33 |
/**
|
34 |
-
* @var PLL_Static_Pages
|
35 |
*/
|
36 |
public $static_pages;
|
37 |
|
38 |
/**
|
39 |
-
* @var PLL_Filters_Widgets_Options
|
40 |
*/
|
41 |
public $filters_widgets_options;
|
42 |
|
@@ -50,23 +55,39 @@ class PLL_REST_Request extends PLL_Base {
|
|
50 |
public function init() {
|
51 |
parent::init();
|
52 |
|
53 |
-
if ( $this->model->get_languages_list() ) {
|
54 |
-
|
55 |
-
|
56 |
-
do_action( 'pll_no_language_defined' ); // To load overridden textdomains.
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
$this->
|
65 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
|
67 |
-
|
|
|
|
|
68 |
|
69 |
-
|
|
|
|
|
70 |
}
|
|
|
|
|
|
|
71 |
}
|
72 |
}
|
9 |
* @since 2.6
|
10 |
*/
|
11 |
class PLL_REST_Request extends PLL_Base {
|
12 |
+
/**
|
13 |
+
* @var PLL_Language|false|null A `PLL_Language` when defined, `false` otherwise. `null` until the language
|
14 |
+
* definition process runs.
|
15 |
+
*/
|
16 |
+
public $curlang;
|
17 |
|
18 |
/**
|
19 |
+
* @var PLL_Filters|null
|
20 |
*/
|
21 |
public $filters;
|
22 |
|
23 |
/**
|
24 |
+
* @var PLL_Filters_Links|null
|
25 |
*/
|
26 |
public $filters_links;
|
27 |
|
28 |
/**
|
29 |
+
* @var PLL_Admin_Links|null
|
30 |
*/
|
31 |
public $links;
|
32 |
|
33 |
/**
|
34 |
+
* @var PLL_Nav_Menu|null
|
35 |
*/
|
36 |
public $nav_menu;
|
37 |
|
38 |
/**
|
39 |
+
* @var PLL_Static_Pages|null
|
40 |
*/
|
41 |
public $static_pages;
|
42 |
|
43 |
/**
|
44 |
+
* @var PLL_Filters_Widgets_Options|null
|
45 |
*/
|
46 |
public $filters_widgets_options;
|
47 |
|
55 |
public function init() {
|
56 |
parent::init();
|
57 |
|
58 |
+
if ( ! $this->model->get_languages_list() ) {
|
59 |
+
return;
|
60 |
+
}
|
|
|
61 |
|
62 |
+
if ( ! empty( $_REQUEST['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
63 |
+
if ( is_string( $_REQUEST['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
64 |
+
$this->curlang = $this->model->get_language( sanitize_key( $_REQUEST['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
|
65 |
+
}
|
66 |
|
67 |
+
if ( empty( $this->curlang ) && ! empty( $this->options['default_lang'] ) && is_string( $this->options['default_lang'] ) ) {
|
68 |
+
// A lang has been requested but it is invalid, let's fall back to the default one.
|
69 |
+
$this->curlang = $this->model->get_language( sanitize_key( $this->options['default_lang'] ) );
|
70 |
}
|
71 |
+
}
|
72 |
+
|
73 |
+
if ( ! empty( $this->curlang ) ) {
|
74 |
+
/** This action is documented in frontend/choose-lang.php */
|
75 |
+
do_action( 'pll_language_defined', $this->curlang->slug, $this->curlang );
|
76 |
+
} else {
|
77 |
+
/** This action is documented in include/class-polylang.php */
|
78 |
+
do_action( 'pll_no_language_defined' ); // To load overridden textdomains.
|
79 |
+
}
|
80 |
|
81 |
+
$this->filters_links = new PLL_Filters_Links( $this );
|
82 |
+
$this->filters = new PLL_Filters( $this );
|
83 |
+
$this->filters_widgets_options = new PLL_Filters_Widgets_Options( $this );
|
84 |
|
85 |
+
// Static front page and page for posts.
|
86 |
+
if ( 'page' === get_option( 'show_on_front' ) ) {
|
87 |
+
$this->static_pages = new PLL_Static_Pages( $this );
|
88 |
}
|
89 |
+
|
90 |
+
$this->links = new PLL_Admin_Links( $this );
|
91 |
+
$this->nav_menu = new PLL_Nav_Menu( $this ); // For auto added pages to menu.
|
92 |
}
|
93 |
}
|
include/switcher.php
CHANGED
@@ -212,6 +212,7 @@ class PLL_Switcher {
|
|
212 |
* @return string|array either the html markup of the switcher or the raw elements to build a custom language switcher
|
213 |
*/
|
214 |
public function the_languages( $links, $args = array() ) {
|
|
|
215 |
$this->links = $links;
|
216 |
$args = wp_parse_args( $args, self::DEFAULTS );
|
217 |
|
@@ -242,8 +243,10 @@ class PLL_Switcher {
|
|
242 |
|
243 |
if ( $args['dropdown'] ) {
|
244 |
$args['name'] = 'lang_choice_' . $args['dropdown'];
|
|
|
|
|
|
|
245 |
$walker = new PLL_Walker_Dropdown();
|
246 |
-
$args['selected'] = $this->get_current_language( $args );
|
247 |
} else {
|
248 |
$walker = new PLL_Walker_List();
|
249 |
}
|
@@ -264,14 +267,9 @@ class PLL_Switcher {
|
|
264 |
$out .= sprintf(
|
265 |
'<script type="text/javascript">
|
266 |
//<![CDATA[
|
267 |
-
|
268 |
-
document.getElementById( "%3$s" ).onchange = function() {
|
269 |
-
location.href = %1$s[this.value];
|
270 |
-
}
|
271 |
//]]>
|
272 |
</script>',
|
273 |
-
'urls_' . preg_replace( '#[^a-zA-Z0-9]#', '', $args['dropdown'] ),
|
274 |
-
wp_json_encode( wp_list_pluck( $elements, 'url' ) ),
|
275 |
esc_js( $args['name'] )
|
276 |
);
|
277 |
}
|
212 |
* @return string|array either the html markup of the switcher or the raw elements to build a custom language switcher
|
213 |
*/
|
214 |
public function the_languages( $links, $args = array() ) {
|
215 |
+
|
216 |
$this->links = $links;
|
217 |
$args = wp_parse_args( $args, self::DEFAULTS );
|
218 |
|
243 |
|
244 |
if ( $args['dropdown'] ) {
|
245 |
$args['name'] = 'lang_choice_' . $args['dropdown'];
|
246 |
+
$args['class'] = 'pll-switcher-select';
|
247 |
+
$args['value'] = 'url';
|
248 |
+
$args['selected'] = $this->get_link( $this->links->model->get_language( $this->get_current_language( $args ) ), $args );
|
249 |
$walker = new PLL_Walker_Dropdown();
|
|
|
250 |
} else {
|
251 |
$walker = new PLL_Walker_List();
|
252 |
}
|
267 |
$out .= sprintf(
|
268 |
'<script type="text/javascript">
|
269 |
//<![CDATA[
|
270 |
+
document.getElementById( "%1$s" ).addEventListener( "change", function ( event ) { location.href = event.currentTarget.value; } )
|
|
|
|
|
|
|
271 |
//]]>
|
272 |
</script>',
|
|
|
|
|
273 |
esc_js( $args['name'] )
|
274 |
);
|
275 |
}
|
include/translated-object.php
CHANGED
@@ -101,7 +101,9 @@ abstract class PLL_Translated_Object {
|
|
101 |
* @return void
|
102 |
*/
|
103 |
public function update_language( $id, $lang ) {
|
104 |
-
|
|
|
|
|
105 |
return;
|
106 |
}
|
107 |
|
@@ -117,8 +119,8 @@ abstract class PLL_Translated_Object {
|
|
117 |
}
|
118 |
|
119 |
/**
|
120 |
-
*
|
121 |
-
*
|
122 |
*
|
123 |
* @since 1.2
|
124 |
*
|
@@ -127,44 +129,68 @@ abstract class PLL_Translated_Object {
|
|
127 |
* @return WP_Term|false The term associated to the object in the requested taxonomy if it exists, false otherwise.
|
128 |
*/
|
129 |
public function get_object_term( $object_id, $taxonomy ) {
|
130 |
-
|
|
|
|
|
131 |
return false;
|
132 |
}
|
133 |
|
134 |
-
$
|
135 |
|
136 |
-
if ( $
|
137 |
-
return false;
|
138 |
}
|
139 |
|
140 |
-
|
|
|
141 |
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
$
|
152 |
-
if ( $t->taxonomy == $taxonomy ) {
|
153 |
-
$term = $t;
|
154 |
-
}
|
155 |
}
|
156 |
}
|
|
|
157 |
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
-
|
164 |
-
|
|
|
|
|
|
|
165 |
}
|
166 |
|
167 |
-
|
|
|
|
|
|
|
168 |
}
|
169 |
|
170 |
/**
|
@@ -173,13 +199,14 @@ abstract class PLL_Translated_Object {
|
|
173 |
* @since 2.3
|
174 |
*
|
175 |
* @param int $id Object id ( typically a post_id or term_id ).
|
176 |
-
* @param int[] $translations An associative array of translations with language code as key and translation id as
|
|
|
177 |
* @return bool
|
178 |
*/
|
179 |
protected function should_update_translation_group( $id, $translations ) {
|
180 |
// Don't do anything if no translations have been added to the group.
|
181 |
$old_translations = $this->get_translations( $id ); // Includes at least $id itself.
|
182 |
-
return
|
183 |
}
|
184 |
|
185 |
/**
|
@@ -189,79 +216,72 @@ abstract class PLL_Translated_Object {
|
|
189 |
*
|
190 |
* @param int $id Object id ( typically a post_id or term_id ).
|
191 |
* @param int[] $translations An associative array of translations with language code as key and translation id as value.
|
192 |
-
*
|
193 |
-
* @return int[] An associative array with language codes as key and post ids as values.
|
194 |
*/
|
195 |
public function save_translations( $id, $translations ) {
|
196 |
-
$
|
197 |
|
198 |
-
$id
|
|
|
|
|
199 |
|
200 |
-
|
201 |
-
// Sanitize the translations array.
|
202 |
-
$translations = array_map( 'intval', $translations );
|
203 |
-
$translations = array_merge( array( $lang->slug => $id ), $translations ); // Make sure this object is in translations.
|
204 |
-
$translations = array_diff( $translations, array( 0 ) ); // Don't keep non translated languages.
|
205 |
-
$translations = array_intersect_key( $translations, array_flip( $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ); // Keep only valid languages slugs as keys.
|
206 |
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
$this->delete_translation( $object_id );
|
211 |
-
}
|
212 |
|
213 |
-
|
214 |
-
|
215 |
-
$terms = wp_get_object_terms( $translations, $this->tax_translations );
|
216 |
-
$term = reset( $terms );
|
217 |
-
|
218 |
-
// Create a new term if necessary.
|
219 |
-
if ( empty( $term ) ) {
|
220 |
-
wp_insert_term( $group = uniqid( 'pll_' ), $this->tax_translations, array( 'description' => maybe_serialize( $translations ) ) );
|
221 |
-
} else {
|
222 |
-
// Take care not to overwrite extra data stored in the description field, if any.
|
223 |
-
$d = maybe_unserialize( $term->description );
|
224 |
-
$d = is_array( $d ) ? array_diff_key( $d, $old_translations ) : array(); // Remove old translations.
|
225 |
-
$d = array_merge( $d, $translations ); // Add new one.
|
226 |
-
wp_update_term( $group = (int) $term->term_id, $this->tax_translations, array( 'description' => maybe_serialize( $d ) ) );
|
227 |
-
}
|
228 |
|
229 |
-
|
230 |
-
|
231 |
-
wp_set_object_terms( $p, $group, $this->tax_translations );
|
232 |
-
}
|
233 |
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
}
|
241 |
-
}
|
242 |
return $translations;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
} else {
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
245 |
}
|
246 |
-
}
|
247 |
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
*
|
253 |
-
* @param int[] $translations An associative array of translations with language code as key and translation id as value.
|
254 |
-
*
|
255 |
-
* @return int[]
|
256 |
-
*/
|
257 |
-
public function validate_translations( $translations ) {
|
258 |
-
$valid_translations = array();
|
259 |
|
260 |
-
|
261 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
}
|
263 |
|
264 |
-
return $
|
265 |
}
|
266 |
|
267 |
/**
|
@@ -273,22 +293,33 @@ abstract class PLL_Translated_Object {
|
|
273 |
* @return void
|
274 |
*/
|
275 |
public function delete_translation( $id ) {
|
276 |
-
$id = (
|
|
|
|
|
|
|
|
|
|
|
277 |
$term = $this->get_object_term( $id, $this->tax_translations );
|
278 |
|
279 |
-
if (
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
}
|
285 |
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
|
|
290 |
}
|
291 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
}
|
293 |
|
294 |
/**
|
@@ -300,20 +331,16 @@ abstract class PLL_Translated_Object {
|
|
300 |
* @return int[] An associative array of translations with language code as key and translation id as value.
|
301 |
*/
|
302 |
public function get_translations( $id ) {
|
303 |
-
$
|
304 |
-
$translations = empty( $term ) ? array() : maybe_unserialize( $term->description );
|
305 |
|
306 |
-
|
307 |
-
|
308 |
-
$translations = array_intersect_key( $translations, array_flip( $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) );
|
309 |
}
|
310 |
|
311 |
-
|
312 |
-
|
313 |
-
$translations = array( $lang->slug => $id );
|
314 |
-
}
|
315 |
|
316 |
-
return $translations;
|
317 |
}
|
318 |
|
319 |
/**
|
@@ -326,7 +353,9 @@ abstract class PLL_Translated_Object {
|
|
326 |
* @return int|false Object id of the translation, false if there is none.
|
327 |
*/
|
328 |
public function get_translation( $id, $lang ) {
|
329 |
-
|
|
|
|
|
330 |
return false;
|
331 |
}
|
332 |
|
@@ -345,14 +374,25 @@ abstract class PLL_Translated_Object {
|
|
345 |
* @return int|false The translation object id if exists, otherwise the passed id, false if the passed object has no language.
|
346 |
*/
|
347 |
public function get( $id, $lang ) {
|
348 |
-
$id = (
|
|
|
|
|
|
|
|
|
|
|
349 |
$lang = $this->model->get_language( $lang );
|
|
|
|
|
|
|
|
|
|
|
350 |
$obj_lang = $this->get_language( $id );
|
351 |
-
|
|
|
352 |
return false;
|
353 |
}
|
354 |
|
355 |
-
return $obj_lang->term_id
|
356 |
}
|
357 |
|
358 |
/**
|
@@ -398,38 +438,7 @@ abstract class PLL_Translated_Object {
|
|
398 |
}
|
399 |
|
400 |
/**
|
401 |
-
*
|
402 |
-
* It is faster than get_objects_in_term() as it avoids a JOIN.
|
403 |
-
*
|
404 |
-
* @since 1.4
|
405 |
-
*
|
406 |
-
* @param PLL_Language $lang PLL_Language object.
|
407 |
-
* @return int[] Object ids.
|
408 |
-
*/
|
409 |
-
public function get_objects_in_language( $lang ) {
|
410 |
-
global $wpdb;
|
411 |
-
$tt_id = $this->tax_tt;
|
412 |
-
|
413 |
-
$last_changed = wp_cache_get_last_changed( 'terms' );
|
414 |
-
$cache_key = "polylang:get_objects_in_language:{$lang->$tt_id}:{$last_changed}";
|
415 |
-
$cache = wp_cache_get( $cache_key, 'terms' );
|
416 |
-
|
417 |
-
if ( false === $cache ) {
|
418 |
-
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $lang->$tt_id ) );
|
419 |
-
wp_cache_set( $cache_key, $object_ids, 'terms' );
|
420 |
-
} else {
|
421 |
-
$object_ids = (array) $cache;
|
422 |
-
}
|
423 |
-
|
424 |
-
if ( ! $object_ids ) {
|
425 |
-
return array();
|
426 |
-
}
|
427 |
-
|
428 |
-
return $object_ids;
|
429 |
-
}
|
430 |
-
|
431 |
-
/**
|
432 |
-
* Check if a user can synchronize translations.
|
433 |
*
|
434 |
* @since 2.6
|
435 |
*
|
@@ -437,6 +446,12 @@ abstract class PLL_Translated_Object {
|
|
437 |
* @return bool
|
438 |
*/
|
439 |
public function current_user_can_synchronize( $id ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
440 |
/**
|
441 |
* Filters whether a synchronization capability check should take place.
|
442 |
*
|
@@ -449,8 +464,9 @@ abstract class PLL_Translated_Object {
|
|
449 |
* @param int $id The synchronization source object id.
|
450 |
*/
|
451 |
$check = apply_filters( "pll_pre_current_user_can_synchronize_{$this->type}", true, $id );
|
|
|
452 |
if ( null !== $check ) {
|
453 |
-
return $check;
|
454 |
}
|
455 |
|
456 |
if ( ! current_user_can( "edit_{$this->type}", $id ) ) {
|
@@ -465,4 +481,109 @@ abstract class PLL_Translated_Object {
|
|
465 |
|
466 |
return true;
|
467 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
468 |
}
|
101 |
* @return void
|
102 |
*/
|
103 |
public function update_language( $id, $lang ) {
|
104 |
+
$id = $this->sanitize_int_id( $id );
|
105 |
+
|
106 |
+
if ( empty( $id ) || $this->get_language( $id ) === $lang ) {
|
107 |
return;
|
108 |
}
|
109 |
|
119 |
}
|
120 |
|
121 |
/**
|
122 |
+
* Wraps wp_get_object_terms() to cache it and return only one object.
|
123 |
+
* Inspired by the WordPress function get_the_terms().
|
124 |
*
|
125 |
* @since 1.2
|
126 |
*
|
129 |
* @return WP_Term|false The term associated to the object in the requested taxonomy if it exists, false otherwise.
|
130 |
*/
|
131 |
public function get_object_term( $object_id, $taxonomy ) {
|
132 |
+
$object_id = $this->sanitize_int_id( $object_id );
|
133 |
+
|
134 |
+
if ( empty( $object_id ) ) {
|
135 |
return false;
|
136 |
}
|
137 |
|
138 |
+
$term = get_object_term_cache( $object_id, $taxonomy );
|
139 |
|
140 |
+
if ( is_array( $term ) ) {
|
141 |
+
return ! empty( $term ) ? reset( $term ) : false;
|
142 |
}
|
143 |
|
144 |
+
// Query language and translations at the same time.
|
145 |
+
$taxonomies = array( $this->tax_language, $this->tax_translations );
|
146 |
|
147 |
+
// Query terms.
|
148 |
+
$terms = array();
|
149 |
+
$term = false;
|
150 |
+
$object_terms = wp_get_object_terms( $object_id, $taxonomies, array( 'update_term_meta_cache' => false ) );
|
151 |
+
|
152 |
+
if ( is_array( $object_terms ) ) {
|
153 |
+
foreach ( $object_terms as $t ) {
|
154 |
+
$terms[ $t->taxonomy ] = $t;
|
155 |
+
if ( $t->taxonomy === $taxonomy ) {
|
156 |
+
$term = $t;
|
|
|
|
|
|
|
157 |
}
|
158 |
}
|
159 |
+
}
|
160 |
|
161 |
+
// Stores it the way WP expects it. Set an empty cache if no term was found in the taxonomy.
|
162 |
+
foreach ( $taxonomies as $tax ) {
|
163 |
+
wp_cache_add( $object_id, empty( $terms[ $tax ] ) ? array() : array( $terms[ $tax ] ), $tax . '_relationships' );
|
164 |
+
}
|
165 |
+
|
166 |
+
return $term;
|
167 |
+
}
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Returns a list of post translations, given a `tax_translations` term ID.
|
171 |
+
*
|
172 |
+
* @since 3.2
|
173 |
+
*
|
174 |
+
* @param int $term_id Term ID.
|
175 |
+
* @return array<int> An associative array of translations with language code as key and translation id as value.
|
176 |
+
*/
|
177 |
+
public function get_translations_from_term_id( $term_id ) {
|
178 |
+
$term_id = $this->sanitize_int_id( $term_id );
|
179 |
+
|
180 |
+
if ( empty( $term_id ) ) {
|
181 |
+
return array();
|
182 |
}
|
183 |
+
|
184 |
+
$translations_term = get_term( $term_id, $this->tax_translations );
|
185 |
+
|
186 |
+
if ( ! $translations_term instanceof WP_Term || empty( $translations_term->description ) ) {
|
187 |
+
return array();
|
188 |
}
|
189 |
|
190 |
+
// Lang slugs as array keys, template IDs as array values.
|
191 |
+
$translations = maybe_unserialize( $translations_term->description );
|
192 |
+
|
193 |
+
return $this->validate_translations( $translations, 0, 'display' );
|
194 |
}
|
195 |
|
196 |
/**
|
199 |
* @since 2.3
|
200 |
*
|
201 |
* @param int $id Object id ( typically a post_id or term_id ).
|
202 |
+
* @param int[] $translations An associative array of translations with language code as key and translation id as
|
203 |
+
* value. Make sure to sanitize this.
|
204 |
* @return bool
|
205 |
*/
|
206 |
protected function should_update_translation_group( $id, $translations ) {
|
207 |
// Don't do anything if no translations have been added to the group.
|
208 |
$old_translations = $this->get_translations( $id ); // Includes at least $id itself.
|
209 |
+
return ! empty( array_diff_assoc( $translations, $old_translations ) );
|
210 |
}
|
211 |
|
212 |
/**
|
216 |
*
|
217 |
* @param int $id Object id ( typically a post_id or term_id ).
|
218 |
* @param int[] $translations An associative array of translations with language code as key and translation id as value.
|
219 |
+
* @return int[] An associative array with language codes as key and post ids as values.
|
|
|
220 |
*/
|
221 |
public function save_translations( $id, $translations ) {
|
222 |
+
$id = $this->sanitize_int_id( $id );
|
223 |
|
224 |
+
if ( empty( $id ) ) {
|
225 |
+
return array();
|
226 |
+
}
|
227 |
|
228 |
+
$lang = $this->get_language( $id );
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
+
if ( empty( $lang ) ) {
|
231 |
+
return array();
|
232 |
+
}
|
|
|
|
|
233 |
|
234 |
+
// Sanitize and validate the translations array.
|
235 |
+
$translations = $this->validate_translations( $translations, $id );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
|
237 |
+
// Unlink removed translations.
|
238 |
+
$old_translations = $this->get_translations( $id );
|
|
|
|
|
239 |
|
240 |
+
foreach ( array_diff_assoc( $old_translations, $translations ) as $object_id ) {
|
241 |
+
$this->delete_translation( $object_id );
|
242 |
+
}
|
243 |
+
|
244 |
+
// Check id we need to create or update the translation group.
|
245 |
+
if ( ! $this->should_update_translation_group( $id, $translations ) ) {
|
|
|
|
|
246 |
return $translations;
|
247 |
+
}
|
248 |
+
|
249 |
+
$terms = wp_get_object_terms( $translations, $this->tax_translations );
|
250 |
+
$term = is_array( $terms ) && ! empty( $terms ) ? reset( $terms ) : false;
|
251 |
+
|
252 |
+
if ( empty( $term ) ) {
|
253 |
+
// Create a new term if necessary.
|
254 |
+
$group = uniqid( 'pll_' );
|
255 |
+
wp_insert_term( $group, $this->tax_translations, array( 'description' => maybe_serialize( $translations ) ) );
|
256 |
} else {
|
257 |
+
// Take care not to overwrite extra data stored in the description field, if any.
|
258 |
+
$group = (int) $term->term_id;
|
259 |
+
$descr = maybe_unserialize( $term->description );
|
260 |
+
$descr = is_array( $descr ) ? array_diff_key( $descr, $old_translations ) : array(); // Remove old translations.
|
261 |
+
$descr = array_merge( $descr, $translations ); // Add new one.
|
262 |
+
wp_update_term( $group, $this->tax_translations, array( 'description' => maybe_serialize( $descr ) ) );
|
263 |
}
|
|
|
264 |
|
265 |
+
// Link all translations to the new term.
|
266 |
+
foreach ( $translations as $p ) {
|
267 |
+
wp_set_object_terms( $p, $group, $this->tax_translations );
|
268 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
+
if ( ! is_array( $terms ) ) {
|
271 |
+
return $translations;
|
272 |
+
}
|
273 |
+
|
274 |
+
// Clean now unused translation groups.
|
275 |
+
foreach ( $terms as $term ) {
|
276 |
+
// Get fresh count value.
|
277 |
+
$term = get_term( $term->term_id, $this->tax_translations );
|
278 |
+
|
279 |
+
if ( $term instanceof WP_Term && empty( $term->count ) ) {
|
280 |
+
wp_delete_term( $term->term_id, $this->tax_translations );
|
281 |
+
}
|
282 |
}
|
283 |
|
284 |
+
return $translations;
|
285 |
}
|
286 |
|
287 |
/**
|
293 |
* @return void
|
294 |
*/
|
295 |
public function delete_translation( $id ) {
|
296 |
+
$id = $this->sanitize_int_id( $id );
|
297 |
+
|
298 |
+
if ( empty( $id ) ) {
|
299 |
+
return;
|
300 |
+
}
|
301 |
+
|
302 |
$term = $this->get_object_term( $id, $this->tax_translations );
|
303 |
|
304 |
+
if ( empty( $term ) ) {
|
305 |
+
return;
|
306 |
+
}
|
307 |
+
|
308 |
+
$descr = maybe_unserialize( $term->description );
|
|
|
309 |
|
310 |
+
if ( ! empty( $descr ) && is_array( $descr ) ) {
|
311 |
+
$slug = array_search( $id, $this->get_translations( $id ) ); // In case some plugin stores the same value with different key.
|
312 |
+
|
313 |
+
if ( false !== $slug ) {
|
314 |
+
unset( $descr[ $slug ] );
|
315 |
}
|
316 |
}
|
317 |
+
|
318 |
+
if ( empty( $descr ) || ! is_array( $descr ) ) {
|
319 |
+
wp_delete_term( (int) $term->term_id, $this->tax_translations );
|
320 |
+
} else {
|
321 |
+
wp_update_term( (int) $term->term_id, $this->tax_translations, array( 'description' => maybe_serialize( $descr ) ) );
|
322 |
+
}
|
323 |
}
|
324 |
|
325 |
/**
|
331 |
* @return int[] An associative array of translations with language code as key and translation id as value.
|
332 |
*/
|
333 |
public function get_translations( $id ) {
|
334 |
+
$id = $this->sanitize_int_id( $id );
|
|
|
335 |
|
336 |
+
if ( empty( $id ) ) {
|
337 |
+
return array();
|
|
|
338 |
}
|
339 |
|
340 |
+
$term = $this->get_object_term( $id, $this->tax_translations );
|
341 |
+
$translations = empty( $term->description ) ? array() : maybe_unserialize( $term->description );
|
|
|
|
|
342 |
|
343 |
+
return $this->validate_translations( $translations, $id, 'display' );
|
344 |
}
|
345 |
|
346 |
/**
|
353 |
* @return int|false Object id of the translation, false if there is none.
|
354 |
*/
|
355 |
public function get_translation( $id, $lang ) {
|
356 |
+
$lang = $this->model->get_language( $lang );
|
357 |
+
|
358 |
+
if ( empty( $lang ) ) {
|
359 |
return false;
|
360 |
}
|
361 |
|
374 |
* @return int|false The translation object id if exists, otherwise the passed id, false if the passed object has no language.
|
375 |
*/
|
376 |
public function get( $id, $lang ) {
|
377 |
+
$id = $this->sanitize_int_id( $id );
|
378 |
+
|
379 |
+
if ( empty( $id ) ) {
|
380 |
+
return false;
|
381 |
+
}
|
382 |
+
|
383 |
$lang = $this->model->get_language( $lang );
|
384 |
+
|
385 |
+
if ( empty( $lang ) ) {
|
386 |
+
return false;
|
387 |
+
}
|
388 |
+
|
389 |
$obj_lang = $this->get_language( $id );
|
390 |
+
|
391 |
+
if ( empty( $obj_lang ) ) {
|
392 |
return false;
|
393 |
}
|
394 |
|
395 |
+
return $obj_lang->term_id === $lang->term_id ? $id : $this->get_translation( $id, $lang );
|
396 |
}
|
397 |
|
398 |
/**
|
438 |
}
|
439 |
|
440 |
/**
|
441 |
+
* Checks if a user can synchronize translations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
442 |
*
|
443 |
* @since 2.6
|
444 |
*
|
446 |
* @return bool
|
447 |
*/
|
448 |
public function current_user_can_synchronize( $id ) {
|
449 |
+
$id = $this->sanitize_int_id( $id );
|
450 |
+
|
451 |
+
if ( empty( $id ) ) {
|
452 |
+
return false;
|
453 |
+
}
|
454 |
+
|
455 |
/**
|
456 |
* Filters whether a synchronization capability check should take place.
|
457 |
*
|
464 |
* @param int $id The synchronization source object id.
|
465 |
*/
|
466 |
$check = apply_filters( "pll_pre_current_user_can_synchronize_{$this->type}", true, $id );
|
467 |
+
|
468 |
if ( null !== $check ) {
|
469 |
+
return (bool) $check;
|
470 |
}
|
471 |
|
472 |
if ( ! current_user_can( "edit_{$this->type}", $id ) ) {
|
481 |
|
482 |
return true;
|
483 |
}
|
484 |
+
|
485 |
+
/**
|
486 |
+
* Sanitizes an ID as positive integer.
|
487 |
+
* Kind of similar to `absint()`, but rejects negetive integers instead of making them positive.
|
488 |
+
*
|
489 |
+
* @since 3.2
|
490 |
+
*
|
491 |
+
* @param mixed $id A supposedly numeric ID.
|
492 |
+
* @return int A positive integer. `0` for non numeric values and negative integers.
|
493 |
+
*/
|
494 |
+
public function sanitize_int_id( $id ) {
|
495 |
+
return is_numeric( $id ) && $id >= 1 ? (int) $id : 0;
|
496 |
+
}
|
497 |
+
|
498 |
+
/**
|
499 |
+
* Sanitizes an array of IDs as positive integers.
|
500 |
+
* `0` values are removed.
|
501 |
+
*
|
502 |
+
* @since 3.2
|
503 |
+
*
|
504 |
+
* @param mixed $ids An associative array of translations with language code as key and translation ID as value.
|
505 |
+
* @return array<int> An associative array of translations with language code as key and translation ID as value.
|
506 |
+
*/
|
507 |
+
public function sanitize_int_ids_list( $ids ) {
|
508 |
+
if ( empty( $ids ) || ! is_array( $ids ) ) {
|
509 |
+
return array();
|
510 |
+
}
|
511 |
+
|
512 |
+
$ids = array_map( array( $this, 'sanitize_int_id' ), $ids );
|
513 |
+
|
514 |
+
return array_filter( $ids );
|
515 |
+
}
|
516 |
+
|
517 |
+
/**
|
518 |
+
* Validates and sanitizes translations.
|
519 |
+
* This will:
|
520 |
+
* - Make sure to return only translations in existing languages (and only translations).
|
521 |
+
* - Sanitize the values.
|
522 |
+
* - Make sure the provided translation (`$id`) is in the list.
|
523 |
+
* - Check that the translated objects are in the right language, if `$context` is set to 'save'.
|
524 |
+
*
|
525 |
+
* @since 3.1
|
526 |
+
* @since 3.2 Doesn't return `0` ID values.
|
527 |
+
* @since 3.2 Added parameters `$id` and `$context`.
|
528 |
+
*
|
529 |
+
* @param int[] $translations An associative array of translations with language code as key and translation ID as
|
530 |
+
* value.
|
531 |
+
* @param int $id Optional. The object ID for which the translations are validated. When provided, the
|
532 |
+
* process makes sure it is added to the list. Default 0.
|
533 |
+
* @param string $context Optional. The operation for which the translations are validated. When set to
|
534 |
+
* 'save', a check is done to verify that the IDs and langs correspond.
|
535 |
+
* 'display' should be used otherwise. Default 'save'.
|
536 |
+
* @return int[]
|
537 |
+
*/
|
538 |
+
protected function validate_translations( $translations, $id = 0, $context = 'save' ) {
|
539 |
+
if ( ! is_array( $translations ) ) {
|
540 |
+
$translations = array();
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Remove translations in non-existing languages, and non-translation data (we allow plugins to store other
|
545 |
+
* information in the array).
|
546 |
+
*/
|
547 |
+
$translations = array_intersect_key(
|
548 |
+
$translations,
|
549 |
+
array_flip( $this->model->get_languages_list( array( 'fields' => 'slug' ) ) )
|
550 |
+
);
|
551 |
+
|
552 |
+
// Make sure values are clean before working with them.
|
553 |
+
$translations = $this->sanitize_int_ids_list( $translations );
|
554 |
+
|
555 |
+
if ( 'save' === $context ) {
|
556 |
+
/**
|
557 |
+
* Check that the translated objects are in the right language.
|
558 |
+
* For better performance, this should be done only when saving the data into the database, not when
|
559 |
+
* retrieving data from it.
|
560 |
+
*/
|
561 |
+
$valid_translations = array();
|
562 |
+
|
563 |
+
foreach ( $translations as $lang_slug => $tr_id ) {
|
564 |
+
$tr_lang = $this->get_language( $tr_id );
|
565 |
+
|
566 |
+
if ( ! empty( $tr_lang ) && $tr_lang->slug === $lang_slug ) {
|
567 |
+
$valid_translations[ $lang_slug ] = $tr_id;
|
568 |
+
}
|
569 |
+
}
|
570 |
+
|
571 |
+
$translations = $valid_translations;
|
572 |
+
}
|
573 |
+
|
574 |
+
$id = $this->sanitize_int_id( $id );
|
575 |
+
|
576 |
+
if ( empty( $id ) ) {
|
577 |
+
return $translations;
|
578 |
+
}
|
579 |
+
|
580 |
+
// Make sure to return at least the passed object in its translation array.
|
581 |
+
$lang = $this->get_language( $id );
|
582 |
+
|
583 |
+
if ( empty( $lang ) ) {
|
584 |
+
return $translations;
|
585 |
+
}
|
586 |
+
|
587 |
+
return array_merge( array( $lang->slug => $id ), $translations );
|
588 |
+
}
|
589 |
}
|
include/translated-post.php
CHANGED
@@ -47,6 +47,12 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
47 |
* @return void
|
48 |
*/
|
49 |
public function set_language( $post_id, $lang ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
$old_lang = $this->get_language( $post_id );
|
51 |
$old_lang = $old_lang ? $old_lang->slug : '';
|
52 |
|
@@ -54,7 +60,7 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
54 |
$lang = $lang ? $lang->slug : '';
|
55 |
|
56 |
if ( $old_lang !== $lang ) {
|
57 |
-
wp_set_post_terms(
|
58 |
}
|
59 |
}
|
60 |
|
@@ -67,8 +73,14 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
67 |
* @return PLL_Language|false PLL_Language object, false if no language is associated to that post
|
68 |
*/
|
69 |
public function get_language( $post_id ) {
|
70 |
-
$
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
}
|
73 |
|
74 |
/**
|
@@ -80,6 +92,12 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
80 |
* @return void
|
81 |
*/
|
82 |
public function delete_translation( $id ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
parent::delete_translation( $id );
|
84 |
wp_set_object_terms( $id, array(), $this->tax_translations );
|
85 |
}
|
@@ -109,7 +127,7 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
109 |
*/
|
110 |
public function register_taxonomy() {
|
111 |
register_taxonomy(
|
112 |
-
|
113 |
$this->model->get_translated_post_types(),
|
114 |
array(
|
115 |
'labels' => array(
|
@@ -138,8 +156,8 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
138 |
*/
|
139 |
public function registered_post_type( $post_type ) {
|
140 |
if ( $this->model->is_translated_post_type( $post_type ) ) {
|
141 |
-
register_taxonomy_for_object_type(
|
142 |
-
register_taxonomy_for_object_type(
|
143 |
}
|
144 |
}
|
145 |
|
@@ -169,6 +187,12 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
169 |
* @return bool
|
170 |
*/
|
171 |
public function current_user_can_read( $post_id, $context = 'view' ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
$post = get_post( $post_id );
|
173 |
|
174 |
if ( empty( $post ) ) {
|
@@ -189,9 +213,19 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
189 |
|
190 |
// Follow WP practices, which shows links to private posts ( when readable ), but not for draft posts ( ex: get_adjacent_post_link() )
|
191 |
if ( in_array( $post->post_status, get_post_stati( array( 'private' => true ) ) ) ) {
|
192 |
-
|
|
|
|
|
|
|
193 |
$user = wp_get_current_user();
|
194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
}
|
196 |
|
197 |
// In edit context, show draft and future posts.
|
@@ -237,7 +271,7 @@ class PLL_Translated_Post extends PLL_Translated_Object {
|
|
237 |
'post_type' => $type,
|
238 |
'tax_query' => array(
|
239 |
array(
|
240 |
-
'taxonomy' =>
|
241 |
'field' => 'term_taxonomy_id', // WP 3.5+
|
242 |
'terms' => $lang->term_taxonomy_id,
|
243 |
),
|
47 |
* @return void
|
48 |
*/
|
49 |
public function set_language( $post_id, $lang ) {
|
50 |
+
$post_id = $this->sanitize_int_id( $post_id );
|
51 |
+
|
52 |
+
if ( empty( $post_id ) ) {
|
53 |
+
return;
|
54 |
+
}
|
55 |
+
|
56 |
$old_lang = $this->get_language( $post_id );
|
57 |
$old_lang = $old_lang ? $old_lang->slug : '';
|
58 |
|
60 |
$lang = $lang ? $lang->slug : '';
|
61 |
|
62 |
if ( $old_lang !== $lang ) {
|
63 |
+
wp_set_post_terms( $post_id, $lang, $this->tax_language );
|
64 |
}
|
65 |
}
|
66 |
|
73 |
* @return PLL_Language|false PLL_Language object, false if no language is associated to that post
|
74 |
*/
|
75 |
public function get_language( $post_id ) {
|
76 |
+
$post_id = $this->sanitize_int_id( $post_id );
|
77 |
+
|
78 |
+
if ( empty( $post_id ) ) {
|
79 |
+
return false;
|
80 |
+
}
|
81 |
+
|
82 |
+
$lang = $this->get_object_term( $post_id, $this->tax_language );
|
83 |
+
return ! empty( $lang ) ? $this->model->get_language( $lang ) : false;
|
84 |
}
|
85 |
|
86 |
/**
|
92 |
* @return void
|
93 |
*/
|
94 |
public function delete_translation( $id ) {
|
95 |
+
$id = $this->sanitize_int_id( $id );
|
96 |
+
|
97 |
+
if ( empty( $id ) ) {
|
98 |
+
return;
|
99 |
+
}
|
100 |
+
|
101 |
parent::delete_translation( $id );
|
102 |
wp_set_object_terms( $id, array(), $this->tax_translations );
|
103 |
}
|
127 |
*/
|
128 |
public function register_taxonomy() {
|
129 |
register_taxonomy(
|
130 |
+
$this->tax_language,
|
131 |
$this->model->get_translated_post_types(),
|
132 |
array(
|
133 |
'labels' => array(
|
156 |
*/
|
157 |
public function registered_post_type( $post_type ) {
|
158 |
if ( $this->model->is_translated_post_type( $post_type ) ) {
|
159 |
+
register_taxonomy_for_object_type( $this->tax_language, $post_type );
|
160 |
+
register_taxonomy_for_object_type( $this->tax_translations, $post_type );
|
161 |
}
|
162 |
}
|
163 |
|
187 |
* @return bool
|
188 |
*/
|
189 |
public function current_user_can_read( $post_id, $context = 'view' ) {
|
190 |
+
$post_id = $this->sanitize_int_id( $post_id );
|
191 |
+
|
192 |
+
if ( empty( $post_id ) ) {
|
193 |
+
return false;
|
194 |
+
}
|
195 |
+
|
196 |
$post = get_post( $post_id );
|
197 |
|
198 |
if ( empty( $post ) ) {
|
213 |
|
214 |
// Follow WP practices, which shows links to private posts ( when readable ), but not for draft posts ( ex: get_adjacent_post_link() )
|
215 |
if ( in_array( $post->post_status, get_post_stati( array( 'private' => true ) ) ) ) {
|
216 |
+
if ( ! is_user_logged_in() ) {
|
217 |
+
return false;
|
218 |
+
}
|
219 |
+
|
220 |
$user = wp_get_current_user();
|
221 |
+
|
222 |
+
if ( (int) $user->ID === (int) $post->post_author ) {
|
223 |
+
return true;
|
224 |
+
}
|
225 |
+
|
226 |
+
$post_type_object = get_post_type_object( $post->post_type );
|
227 |
+
|
228 |
+
return ! empty( $post_type_object ) && current_user_can( $post_type_object->cap->read_private_posts );
|
229 |
}
|
230 |
|
231 |
// In edit context, show draft and future posts.
|
271 |
'post_type' => $type,
|
272 |
'tax_query' => array(
|
273 |
array(
|
274 |
+
'taxonomy' => $this->tax_language,
|
275 |
'field' => 'term_taxonomy_id', // WP 3.5+
|
276 |
'terms' => $lang->term_taxonomy_id,
|
277 |
),
|
include/translated-term.php
CHANGED
@@ -43,7 +43,11 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
43 |
* @return void
|
44 |
*/
|
45 |
public function set_language( $term_id, $lang ) {
|
46 |
-
$term_id = (
|
|
|
|
|
|
|
|
|
47 |
|
48 |
$old_lang = $this->get_language( $term_id );
|
49 |
$old_lang = $old_lang ? $old_lang->tl_term_id : '';
|
@@ -51,17 +55,21 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
51 |
$lang = $this->model->get_language( $lang );
|
52 |
$lang = $lang ? $lang->tl_term_id : '';
|
53 |
|
54 |
-
if ( $old_lang
|
55 |
-
|
|
|
|
|
|
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
unset( $translations[ $slug ] );
|
61 |
-
}
|
62 |
|
63 |
-
|
|
|
64 |
}
|
|
|
|
|
65 |
}
|
66 |
|
67 |
/**
|
@@ -73,7 +81,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
73 |
* @return void
|
74 |
*/
|
75 |
public function delete_language( $term_id ) {
|
76 |
-
wp_delete_object_term_relationships( $term_id,
|
77 |
}
|
78 |
|
79 |
/**
|
@@ -87,7 +95,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
87 |
*/
|
88 |
public function get_language( $value, $taxonomy = '' ) {
|
89 |
if ( is_numeric( $value ) ) {
|
90 |
-
$term_id = $value;
|
91 |
}
|
92 |
|
93 |
// get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
|
@@ -98,8 +106,18 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
98 |
}
|
99 |
}
|
100 |
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
}
|
104 |
|
105 |
/**
|
@@ -108,19 +126,20 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
108 |
* @since 2.3
|
109 |
*
|
110 |
* @param int $id Post id or term id.
|
111 |
-
* @param int[] $translations An associative array of translations with language code as key and translation id as
|
|
|
112 |
* @return bool
|
113 |
*/
|
114 |
protected function should_update_translation_group( $id, $translations ) {
|
115 |
// Don't do anything if no translations have been added to the group
|
116 |
$old_translations = $this->get_translations( $id );
|
117 |
-
if ( count( $translations ) > 1 &&
|
118 |
return true;
|
119 |
}
|
120 |
|
121 |
// But we need a translation group for terms to allow relationships remap when importing from a WXR file
|
122 |
$term = $this->get_object_term( $id, $this->tax_translations );
|
123 |
-
return empty( $term ) ||
|
124 |
}
|
125 |
|
126 |
/**
|
@@ -133,16 +152,18 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
133 |
*/
|
134 |
public function delete_translation( $id ) {
|
135 |
global $wpdb;
|
|
|
136 |
$slug = array_search( $id, $this->get_translations( $id ) ); // in case some plugin stores the same value with different key
|
137 |
|
138 |
parent::delete_translation( $id );
|
139 |
-
wp_delete_object_term_relationships( $id,
|
140 |
|
141 |
if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
|
142 |
// Always keep a group for terms to allow relationships remap when importing from a WXR file
|
|
|
143 |
$translations = array( $slug => $id );
|
144 |
-
wp_insert_term( $group
|
145 |
-
wp_set_object_terms( $id, $group,
|
146 |
}
|
147 |
}
|
148 |
|
@@ -195,7 +216,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
195 |
* @return WP_Term[] Unmodified $terms.
|
196 |
*/
|
197 |
public function wp_get_object_terms( $terms, $object_ids, $taxonomies ) {
|
198 |
-
if ( ! in_array(
|
199 |
$this->_prime_terms_cache( $terms, $taxonomies );
|
200 |
}
|
201 |
return $terms;
|
@@ -210,6 +231,6 @@ class PLL_Translated_Term extends PLL_Translated_Object {
|
|
210 |
* @return void
|
211 |
*/
|
212 |
public function clean_term_cache( $ids ) {
|
213 |
-
clean_object_term_cache( $ids, 'term' );
|
214 |
}
|
215 |
}
|
43 |
* @return void
|
44 |
*/
|
45 |
public function set_language( $term_id, $lang ) {
|
46 |
+
$term_id = $this->sanitize_int_id( $term_id );
|
47 |
+
|
48 |
+
if ( empty( $term_id ) ) {
|
49 |
+
return;
|
50 |
+
}
|
51 |
|
52 |
$old_lang = $this->get_language( $term_id );
|
53 |
$old_lang = $old_lang ? $old_lang->tl_term_id : '';
|
55 |
$lang = $this->model->get_language( $lang );
|
56 |
$lang = $lang ? $lang->tl_term_id : '';
|
57 |
|
58 |
+
if ( $old_lang === $lang ) {
|
59 |
+
return;
|
60 |
+
}
|
61 |
+
|
62 |
+
wp_set_object_terms( $term_id, $lang, $this->tax_language );
|
63 |
|
64 |
+
// Add translation group for correct WXR export.
|
65 |
+
$translations = $this->get_translations( $term_id );
|
66 |
+
$slug = array_search( $term_id, $translations );
|
|
|
|
|
67 |
|
68 |
+
if ( ! empty( $slug ) ) {
|
69 |
+
unset( $translations[ $slug ] );
|
70 |
}
|
71 |
+
|
72 |
+
$this->save_translations( $term_id, $translations );
|
73 |
}
|
74 |
|
75 |
/**
|
81 |
* @return void
|
82 |
*/
|
83 |
public function delete_language( $term_id ) {
|
84 |
+
wp_delete_object_term_relationships( $this->sanitize_int_id( $term_id ), $this->tax_language );
|
85 |
}
|
86 |
|
87 |
/**
|
95 |
*/
|
96 |
public function get_language( $value, $taxonomy = '' ) {
|
97 |
if ( is_numeric( $value ) ) {
|
98 |
+
$term_id = $this->sanitize_int_id( $value );
|
99 |
}
|
100 |
|
101 |
// get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
|
106 |
}
|
107 |
}
|
108 |
|
109 |
+
if ( empty( $term_id ) ) {
|
110 |
+
return false;
|
111 |
+
}
|
112 |
+
|
113 |
+
// Get the language and make sure it is a PLL_Language object.
|
114 |
+
$lang = $this->get_object_term( $term_id, $this->tax_language );
|
115 |
+
|
116 |
+
if ( empty( $lang ) ) {
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
|
120 |
+
return $this->model->get_language( $lang->term_id );
|
121 |
}
|
122 |
|
123 |
/**
|
126 |
* @since 2.3
|
127 |
*
|
128 |
* @param int $id Post id or term id.
|
129 |
+
* @param int[] $translations An associative array of translations with language code as key and translation id as
|
130 |
+
* value. Make sure to sanitize this.
|
131 |
* @return bool
|
132 |
*/
|
133 |
protected function should_update_translation_group( $id, $translations ) {
|
134 |
// Don't do anything if no translations have been added to the group
|
135 |
$old_translations = $this->get_translations( $id );
|
136 |
+
if ( count( $translations ) > 1 && ! empty( array_diff_assoc( $translations, $old_translations ) ) ) {
|
137 |
return true;
|
138 |
}
|
139 |
|
140 |
// But we need a translation group for terms to allow relationships remap when importing from a WXR file
|
141 |
$term = $this->get_object_term( $id, $this->tax_translations );
|
142 |
+
return empty( $term ) || ! empty( array_diff_assoc( $translations, $old_translations ) );
|
143 |
}
|
144 |
|
145 |
/**
|
152 |
*/
|
153 |
public function delete_translation( $id ) {
|
154 |
global $wpdb;
|
155 |
+
$id = $this->sanitize_int_id( $id );
|
156 |
$slug = array_search( $id, $this->get_translations( $id ) ); // in case some plugin stores the same value with different key
|
157 |
|
158 |
parent::delete_translation( $id );
|
159 |
+
wp_delete_object_term_relationships( $id, $this->tax_translations );
|
160 |
|
161 |
if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
|
162 |
// Always keep a group for terms to allow relationships remap when importing from a WXR file
|
163 |
+
$group = uniqid( 'pll_' );
|
164 |
$translations = array( $slug => $id );
|
165 |
+
wp_insert_term( $group, $this->tax_translations, array( 'description' => maybe_serialize( $translations ) ) );
|
166 |
+
wp_set_object_terms( $id, $group, $this->tax_translations );
|
167 |
}
|
168 |
}
|
169 |
|
216 |
* @return WP_Term[] Unmodified $terms.
|
217 |
*/
|
218 |
public function wp_get_object_terms( $terms, $object_ids, $taxonomies ) {
|
219 |
+
if ( ! in_array( $this->tax_translations, $taxonomies ) ) {
|
220 |
$this->_prime_terms_cache( $terms, $taxonomies );
|
221 |
}
|
222 |
return $terms;
|
231 |
* @return void
|
232 |
*/
|
233 |
public function clean_term_cache( $ids ) {
|
234 |
+
clean_object_term_cache( $this->sanitize_int_ids_list( $ids ), 'term' );
|
235 |
}
|
236 |
}
|
include/walker-dropdown.php
CHANGED
@@ -31,12 +31,12 @@ class PLL_Walker_Dropdown extends Walker {
|
|
31 |
* @return void
|
32 |
*/
|
33 |
public function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
34 |
-
$
|
35 |
$output .= sprintf(
|
36 |
"\t" . '<option value="%1$s"%2$s%3$s>%4$s</option>' . "\n",
|
37 |
-
esc_attr( $element->$
|
38 |
method_exists( $element, 'get_locale' ) ? sprintf( ' lang="%s"', esc_attr( $element->get_locale( 'display' ) ) ) : '',
|
39 |
-
selected( isset( $args['selected'] ) && $args['selected'] === $element->$
|
40 |
esc_html( $element->name )
|
41 |
);
|
42 |
}
|
31 |
* @return void
|
32 |
*/
|
33 |
public function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
34 |
+
$value_type = $args['value'];
|
35 |
$output .= sprintf(
|
36 |
"\t" . '<option value="%1$s"%2$s%3$s>%4$s</option>' . "\n",
|
37 |
+
'url' === $value_type ? esc_url( $element->$value_type ) : esc_attr( $element->$value_type ),
|
38 |
method_exists( $element, 'get_locale' ) ? sprintf( ' lang="%s"', esc_attr( $element->get_locale( 'display' ) ) ) : '',
|
39 |
+
selected( isset( $args['selected'] ) && $args['selected'] === $element->$value_type, true, false ),
|
40 |
esc_html( $element->name )
|
41 |
);
|
42 |
}
|
include/widget-languages.php
CHANGED
@@ -67,7 +67,7 @@ class PLL_Widget_Languages extends WP_Widget {
|
|
67 |
$format = apply_filters( 'navigation_widgets_format', $format );
|
68 |
|
69 |
if ( 'html5' === $format ) {
|
70 |
-
echo '<nav
|
71 |
}
|
72 |
|
73 |
echo "<ul>\n" . $list . "</ul>\n"; // phpcs:ignore WordPress.Security.EscapeOutput
|
67 |
$format = apply_filters( 'navigation_widgets_format', $format );
|
68 |
|
69 |
if ( 'html5' === $format ) {
|
70 |
+
echo '<nav aria-label="' . esc_attr( $aria_label ) . '">';
|
71 |
}
|
72 |
|
73 |
echo "<ul>\n" . $list . "</ul>\n"; // phpcs:ignore WordPress.Security.EscapeOutput
|
install/plugin-updater.php
CHANGED
@@ -7,22 +7,22 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
7 |
|
8 |
/**
|
9 |
* Allows plugins to use their own update API.
|
10 |
-
* Modified version with 'polylang' text domain and comments for translators.
|
11 |
*
|
12 |
* @author Easy Digital Downloads
|
13 |
-
* @version 1.
|
14 |
*/
|
15 |
class PLL_Plugin_Updater {
|
16 |
|
17 |
-
private $api_url
|
18 |
-
private $api_data
|
19 |
-
private $
|
20 |
-
private $
|
21 |
-
private $
|
22 |
-
private $
|
23 |
-
private $
|
24 |
-
|
25 |
-
private $
|
26 |
|
27 |
/**
|
28 |
* Class constructor.
|
@@ -38,14 +38,15 @@ class PLL_Plugin_Updater {
|
|
38 |
|
39 |
global $edd_plugin_data;
|
40 |
|
41 |
-
$this->api_url
|
42 |
-
$this->api_data
|
43 |
-
$this->
|
44 |
-
$this->
|
45 |
-
$this->
|
46 |
-
$this->
|
47 |
-
$this->
|
48 |
-
$this->
|
|
|
49 |
|
50 |
$edd_plugin_data[ $this->slug ] = $this->api_data;
|
51 |
|
@@ -74,8 +75,7 @@ class PLL_Plugin_Updater {
|
|
74 |
|
75 |
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
76 |
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
|
77 |
-
|
78 |
-
add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
|
79 |
add_action( 'admin_init', array( $this, 'show_changelog' ) );
|
80 |
|
81 |
}
|
@@ -98,11 +98,7 @@ class PLL_Plugin_Updater {
|
|
98 |
global $pagenow;
|
99 |
|
100 |
if ( ! is_object( $_transient_data ) ) {
|
101 |
-
$_transient_data = new stdClass;
|
102 |
-
}
|
103 |
-
|
104 |
-
if ( 'plugins.php' == $pagenow && is_multisite() ) {
|
105 |
-
return $_transient_data;
|
106 |
}
|
107 |
|
108 |
if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
|
@@ -156,124 +152,127 @@ class PLL_Plugin_Updater {
|
|
156 |
}
|
157 |
|
158 |
/**
|
159 |
-
*
|
160 |
*
|
161 |
* @param string $file
|
162 |
* @param array $plugin
|
163 |
*/
|
164 |
public function show_update_notification( $file, $plugin ) {
|
165 |
|
166 |
-
if
|
167 |
-
|
168 |
-
}
|
169 |
-
|
170 |
-
if( ! current_user_can( 'update_plugins' ) ) {
|
171 |
return;
|
172 |
}
|
173 |
|
174 |
-
|
|
|
175 |
return;
|
176 |
}
|
177 |
|
178 |
-
if ( $this->name
|
179 |
return;
|
180 |
}
|
181 |
|
182 |
-
//
|
183 |
-
remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
|
184 |
-
|
185 |
$update_cache = get_site_transient( 'update_plugins' );
|
186 |
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
$version_info = $this->get_repo_api_data();
|
192 |
-
|
193 |
-
if ( false === $version_info ) {
|
194 |
-
$version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
|
195 |
-
|
196 |
-
// Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
|
197 |
-
if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
|
198 |
-
$version_info->banners = $this->convert_object_to_array( $version_info->banners );
|
199 |
-
}
|
200 |
-
|
201 |
-
if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
|
202 |
-
$version_info->sections = $this->convert_object_to_array( $version_info->sections );
|
203 |
-
}
|
204 |
-
|
205 |
-
if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
|
206 |
-
$version_info->icons = $this->convert_object_to_array( $version_info->icons );
|
207 |
-
}
|
208 |
-
|
209 |
-
if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
|
210 |
-
$version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
|
211 |
-
}
|
212 |
-
|
213 |
-
$this->set_version_info_cache( $version_info );
|
214 |
-
}
|
215 |
-
|
216 |
-
if ( ! is_object( $version_info ) ) {
|
217 |
-
return;
|
218 |
}
|
|
|
|
|
219 |
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
}
|
225 |
|
226 |
-
|
227 |
-
$
|
|
|
|
|
|
|
|
|
228 |
|
229 |
-
|
|
|
230 |
|
231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
|
233 |
-
|
|
|
|
|
|
|
|
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
}
|
236 |
|
237 |
-
|
238 |
-
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
239 |
|
240 |
-
|
241 |
-
|
242 |
-
// build a plugin list row, with update notification
|
243 |
-
$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
|
244 |
-
# <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
|
245 |
-
echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
|
246 |
-
echo '<td colspan="3" class="plugin-update colspanchange">';
|
247 |
-
echo '<div class="update-message notice inline notice-warning notice-alt">';
|
248 |
-
|
249 |
-
$changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
|
250 |
-
|
251 |
-
if ( empty( $version_info->download_link ) ) {
|
252 |
-
printf(
|
253 |
-
/* translators: %1$s plugin name, %3$s plugin version, %2$s is link start tag, %4$s is link end tag. */
|
254 |
-
__( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'polylang' ),
|
255 |
-
esc_html( $version_info->name ),
|
256 |
-
'<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
|
257 |
-
esc_html( $version_info->new_version ),
|
258 |
-
'</a>'
|
259 |
-
);
|
260 |
-
} else {
|
261 |
-
printf(
|
262 |
-
/* translators: %1$s plugin name, %3$s plugin version, %2$s and %5$s are link start tags, %4$s and %6$s are link end tags. */
|
263 |
-
__( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'polylang' ),
|
264 |
-
esc_html( $version_info->name ),
|
265 |
-
'<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
|
266 |
-
esc_html( $version_info->new_version ),
|
267 |
-
'</a>',
|
268 |
-
'<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
|
269 |
-
'</a>'
|
270 |
-
);
|
271 |
-
}
|
272 |
|
273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
|
275 |
-
|
276 |
-
}
|
277 |
}
|
278 |
|
279 |
/**
|
@@ -288,13 +287,13 @@ class PLL_Plugin_Updater {
|
|
288 |
*/
|
289 |
public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
|
290 |
|
291 |
-
if (
|
292 |
|
293 |
return $_data;
|
294 |
|
295 |
}
|
296 |
|
297 |
-
if ( ! isset( $_args->slug ) || ( $_args->slug
|
298 |
|
299 |
return $_data;
|
300 |
|
@@ -307,7 +306,7 @@ class PLL_Plugin_Updater {
|
|
307 |
'banners' => array(),
|
308 |
'reviews' => false,
|
309 |
'icons' => array(),
|
310 |
-
)
|
311 |
);
|
312 |
|
313 |
// Get the transient where we store the api request for this plugin for 24 hours
|
@@ -324,7 +323,6 @@ class PLL_Plugin_Updater {
|
|
324 |
if ( false !== $api_response ) {
|
325 |
$_data = $api_response;
|
326 |
}
|
327 |
-
|
328 |
} else {
|
329 |
$_data = $edd_api_request_transient;
|
330 |
}
|
@@ -349,7 +347,7 @@ class PLL_Plugin_Updater {
|
|
349 |
$_data->contributors = $this->convert_object_to_array( $_data->contributors );
|
350 |
}
|
351 |
|
352 |
-
if( ! isset( $_data->plugin ) ) {
|
353 |
$_data->plugin = $this->name;
|
354 |
}
|
355 |
|
@@ -369,6 +367,9 @@ class PLL_Plugin_Updater {
|
|
369 |
* @return array
|
370 |
*/
|
371 |
private function convert_object_to_array( $data ) {
|
|
|
|
|
|
|
372 |
$new_data = array();
|
373 |
foreach ( $data as $key => $value ) {
|
374 |
$new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
|
@@ -386,9 +387,8 @@ class PLL_Plugin_Updater {
|
|
386 |
*/
|
387 |
public function http_request_args( $args, $url ) {
|
388 |
|
389 |
-
$verify_ssl = $this->verify_ssl();
|
390 |
if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
|
391 |
-
$args['sslverify'] = $verify_ssl;
|
392 |
}
|
393 |
return $args;
|
394 |
|
@@ -403,85 +403,68 @@ class PLL_Plugin_Updater {
|
|
403 |
*
|
404 |
* @param string $_action The requested action.
|
405 |
* @param array $_data Parameters for the API action.
|
406 |
-
* @return false|object
|
407 |
*/
|
408 |
private function api_request( $_action, $_data ) {
|
|
|
409 |
|
410 |
-
|
411 |
-
|
412 |
-
$verify_ssl = $this->verify_ssl();
|
413 |
-
|
414 |
-
// Do a quick status check on this domain if we haven't already checked it.
|
415 |
-
$store_hash = md5( $this->api_url );
|
416 |
-
if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
|
417 |
-
$test_url_parts = parse_url( $this->api_url );
|
418 |
-
|
419 |
-
$scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
|
420 |
-
$host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
|
421 |
-
$port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
|
422 |
-
|
423 |
-
if ( empty( $host ) ) {
|
424 |
-
$edd_plugin_url_available[ $store_hash ] = false;
|
425 |
-
} else {
|
426 |
-
$test_url = $scheme . '://' . $host . $port;
|
427 |
-
$response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) );
|
428 |
-
$edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
|
429 |
-
}
|
430 |
}
|
431 |
|
432 |
-
|
|
|
433 |
return false;
|
434 |
}
|
435 |
|
436 |
-
|
437 |
-
|
438 |
-
if ( $data['slug'] != $this->slug ) {
|
439 |
return false;
|
440 |
}
|
441 |
|
442 |
-
|
443 |
-
|
444 |
-
}
|
445 |
-
|
446 |
-
$api_params = array(
|
447 |
-
'edd_action' => 'get_version',
|
448 |
-
'license' => ! empty( $data['license'] ) ? $data['license'] : '',
|
449 |
-
'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
|
450 |
-
'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
|
451 |
-
'version' => isset( $data['version'] ) ? $data['version'] : false,
|
452 |
-
'slug' => $data['slug'],
|
453 |
-
'author' => $data['author'],
|
454 |
-
'url' => home_url(),
|
455 |
-
'beta' => ! empty( $data['beta'] ),
|
456 |
-
);
|
457 |
-
|
458 |
-
$request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
|
459 |
|
460 |
-
|
461 |
-
|
462 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
463 |
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
$request = false;
|
468 |
}
|
469 |
|
470 |
-
|
471 |
-
|
472 |
-
|
|
|
|
|
|
|
473 |
|
474 |
-
|
475 |
-
$request->icons = maybe_unserialize( $request->icons );
|
476 |
}
|
477 |
|
478 |
-
|
479 |
-
|
480 |
-
$request->$key = (array) $section;
|
481 |
-
}
|
482 |
-
}
|
483 |
|
484 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
485 |
}
|
486 |
|
487 |
/**
|
@@ -489,90 +472,119 @@ class PLL_Plugin_Updater {
|
|
489 |
*/
|
490 |
public function show_changelog() {
|
491 |
|
492 |
-
|
493 |
-
|
494 |
-
if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
|
495 |
return;
|
496 |
}
|
497 |
|
498 |
-
if( empty( $_REQUEST['plugin'] ) ) {
|
499 |
return;
|
500 |
}
|
501 |
|
502 |
-
if( empty( $_REQUEST['slug'] ) ) {
|
503 |
return;
|
504 |
}
|
505 |
|
506 |
-
if( ! current_user_can( 'update_plugins' ) ) {
|
507 |
-
wp_die(
|
508 |
}
|
509 |
|
510 |
-
$
|
511 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
512 |
|
513 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
524 |
|
525 |
-
|
526 |
-
$
|
527 |
|
528 |
-
|
529 |
-
|
530 |
-
}
|
531 |
|
532 |
-
|
533 |
-
$version_info->sections = maybe_unserialize( $version_info->sections );
|
534 |
-
} else {
|
535 |
-
$version_info = false;
|
536 |
-
}
|
537 |
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
|
544 |
-
|
|
|
|
|
545 |
|
546 |
-
|
547 |
-
|
548 |
}
|
549 |
|
550 |
-
if (
|
551 |
-
$sections
|
552 |
-
|
553 |
-
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
|
554 |
}
|
555 |
}
|
556 |
|
557 |
-
|
558 |
}
|
559 |
|
560 |
/**
|
561 |
-
*
|
562 |
*
|
563 |
* @param string $cache_key
|
564 |
-
* @return
|
565 |
*/
|
566 |
public function get_cached_version_info( $cache_key = '' ) {
|
567 |
|
568 |
-
if( empty( $cache_key ) ) {
|
569 |
-
$cache_key = $this->
|
570 |
}
|
571 |
|
572 |
$cache = get_option( $cache_key );
|
573 |
|
574 |
-
|
575 |
-
|
|
|
576 |
}
|
577 |
|
578 |
// We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
|
@@ -593,13 +605,13 @@ class PLL_Plugin_Updater {
|
|
593 |
*/
|
594 |
public function set_version_info_cache( $value = '', $cache_key = '' ) {
|
595 |
|
596 |
-
if( empty( $cache_key ) ) {
|
597 |
-
$cache_key = $this->
|
598 |
}
|
599 |
|
600 |
$data = array(
|
601 |
'timeout' => strtotime( '+3 hours', time() ),
|
602 |
-
'value' =>
|
603 |
);
|
604 |
|
605 |
update_option( $cache_key, $data, 'no' );
|
@@ -618,4 +630,16 @@ class PLL_Plugin_Updater {
|
|
618 |
return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
|
619 |
}
|
620 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
}
|
7 |
|
8 |
/**
|
9 |
* Allows plugins to use their own update API.
|
10 |
+
* Modified version with 'polylang' text domain and missing comments for translators.
|
11 |
*
|
12 |
* @author Easy Digital Downloads
|
13 |
+
* @version 1.9.1
|
14 |
*/
|
15 |
class PLL_Plugin_Updater {
|
16 |
|
17 |
+
private $api_url = '';
|
18 |
+
private $api_data = array();
|
19 |
+
private $plugin_file = '';
|
20 |
+
private $name = '';
|
21 |
+
private $slug = '';
|
22 |
+
private $version = '';
|
23 |
+
private $wp_override = false;
|
24 |
+
private $beta = false;
|
25 |
+
private $failed_request_cache_key;
|
26 |
|
27 |
/**
|
28 |
* Class constructor.
|
38 |
|
39 |
global $edd_plugin_data;
|
40 |
|
41 |
+
$this->api_url = trailingslashit( $_api_url );
|
42 |
+
$this->api_data = $_api_data;
|
43 |
+
$this->plugin_file = $_plugin_file;
|
44 |
+
$this->name = plugin_basename( $_plugin_file );
|
45 |
+
$this->slug = basename( $_plugin_file, '.php' );
|
46 |
+
$this->version = $_api_data['version'];
|
47 |
+
$this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
|
48 |
+
$this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
|
49 |
+
$this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
|
50 |
|
51 |
$edd_plugin_data[ $this->slug ] = $this->api_data;
|
52 |
|
75 |
|
76 |
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
77 |
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
|
78 |
+
add_action( 'after_plugin_row', array( $this, 'show_update_notification' ), 10, 2 );
|
|
|
79 |
add_action( 'admin_init', array( $this, 'show_changelog' ) );
|
80 |
|
81 |
}
|
98 |
global $pagenow;
|
99 |
|
100 |
if ( ! is_object( $_transient_data ) ) {
|
101 |
+
$_transient_data = new stdClass();
|
|
|
|
|
|
|
|
|
102 |
}
|
103 |
|
104 |
if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
|
152 |
}
|
153 |
|
154 |
/**
|
155 |
+
* Show the update notification on multisite subsites.
|
156 |
*
|
157 |
* @param string $file
|
158 |
* @param array $plugin
|
159 |
*/
|
160 |
public function show_update_notification( $file, $plugin ) {
|
161 |
|
162 |
+
// Return early if in the network admin, or if this is not a multisite install.
|
163 |
+
if ( is_network_admin() || ! is_multisite() ) {
|
|
|
|
|
|
|
164 |
return;
|
165 |
}
|
166 |
|
167 |
+
// Allow single site admins to see that an update is available.
|
168 |
+
if ( ! current_user_can( 'activate_plugins' ) ) {
|
169 |
return;
|
170 |
}
|
171 |
|
172 |
+
if ( $this->name !== $file ) {
|
173 |
return;
|
174 |
}
|
175 |
|
176 |
+
// Do not print any message if update does not exist.
|
|
|
|
|
177 |
$update_cache = get_site_transient( 'update_plugins' );
|
178 |
|
179 |
+
if ( ! isset( $update_cache->response[ $this->name ] ) ) {
|
180 |
+
if ( ! is_object( $update_cache ) ) {
|
181 |
+
$update_cache = new stdClass();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
+
$update_cache->response[ $this->name ] = $this->get_repo_api_data();
|
184 |
+
}
|
185 |
|
186 |
+
// Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin.
|
187 |
+
if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) {
|
188 |
+
return;
|
189 |
+
}
|
|
|
190 |
|
191 |
+
printf(
|
192 |
+
'<tr class="plugin-update-tr %3$s" id="%1$s-update" data-slug="%1$s" data-plugin="%2$s">',
|
193 |
+
$this->slug,
|
194 |
+
$file,
|
195 |
+
in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
|
196 |
+
);
|
197 |
|
198 |
+
echo '<td colspan="3" class="plugin-update colspanchange">';
|
199 |
+
echo '<div class="update-message notice inline notice-warning notice-alt"><p>';
|
200 |
|
201 |
+
$changelog_link = '';
|
202 |
+
if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) {
|
203 |
+
$changelog_link = add_query_arg(
|
204 |
+
array(
|
205 |
+
'edd_sl_action' => 'view_plugin_changelog',
|
206 |
+
'plugin' => urlencode( $this->name ),
|
207 |
+
'slug' => urlencode( $this->slug ),
|
208 |
+
'TB_iframe' => 'true',
|
209 |
+
'width' => 77,
|
210 |
+
'height' => 911,
|
211 |
+
),
|
212 |
+
self_admin_url( 'index.php' )
|
213 |
+
);
|
214 |
+
}
|
215 |
+
$update_link = add_query_arg(
|
216 |
+
array(
|
217 |
+
'action' => 'upgrade-plugin',
|
218 |
+
'plugin' => urlencode( $this->name ),
|
219 |
+
),
|
220 |
+
self_admin_url( 'update.php' )
|
221 |
+
);
|
222 |
|
223 |
+
printf(
|
224 |
+
/* translators: the plugin name. */
|
225 |
+
esc_html__( 'There is a new version of %1$s available.', 'polylang' ),
|
226 |
+
esc_html( $plugin['Name'] )
|
227 |
+
);
|
228 |
|
229 |
+
if ( ! current_user_can( 'update_plugins' ) ) {
|
230 |
+
echo ' ';
|
231 |
+
esc_html_e( 'Contact your network administrator to install the update.', 'polylang' );
|
232 |
+
} elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) {
|
233 |
+
echo ' ';
|
234 |
+
printf(
|
235 |
+
/* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
|
236 |
+
__( '%1$sView version %2$s details%3$s.', 'polylang' ),
|
237 |
+
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
|
238 |
+
esc_html( $update_cache->response[ $this->name ]->new_version ),
|
239 |
+
'</a>'
|
240 |
+
);
|
241 |
+
} elseif ( ! empty( $changelog_link ) ) {
|
242 |
+
echo ' ';
|
243 |
+
printf(
|
244 |
+
/* translators: 1. and 4. are opening anchor tags 2. the new plugin version 3. and 5. are closing anchor tags. */
|
245 |
+
__( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'polylang' ),
|
246 |
+
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
|
247 |
+
esc_html( $update_cache->response[ $this->name ]->new_version ),
|
248 |
+
'</a>',
|
249 |
+
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
|
250 |
+
'</a>'
|
251 |
+
);
|
252 |
+
} else {
|
253 |
+
printf(
|
254 |
+
' %1$s%2$s%3$s',
|
255 |
+
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
|
256 |
+
esc_html__( 'Update now.', 'polylang' ),
|
257 |
+
'</a>'
|
258 |
+
);
|
259 |
}
|
260 |
|
261 |
+
do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
|
|
|
262 |
|
263 |
+
echo '</p></div></td></tr>';
|
264 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
|
266 |
+
/**
|
267 |
+
* Gets the plugins active in a multisite network.
|
268 |
+
*
|
269 |
+
* @return array
|
270 |
+
*/
|
271 |
+
private function get_active_plugins() {
|
272 |
+
$active_plugins = (array) get_option( 'active_plugins' );
|
273 |
+
$active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
|
274 |
|
275 |
+
return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
|
|
|
276 |
}
|
277 |
|
278 |
/**
|
287 |
*/
|
288 |
public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
|
289 |
|
290 |
+
if ( 'plugin_information' !== $_action ) {
|
291 |
|
292 |
return $_data;
|
293 |
|
294 |
}
|
295 |
|
296 |
+
if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
|
297 |
|
298 |
return $_data;
|
299 |
|
306 |
'banners' => array(),
|
307 |
'reviews' => false,
|
308 |
'icons' => array(),
|
309 |
+
),
|
310 |
);
|
311 |
|
312 |
// Get the transient where we store the api request for this plugin for 24 hours
|
323 |
if ( false !== $api_response ) {
|
324 |
$_data = $api_response;
|
325 |
}
|
|
|
326 |
} else {
|
327 |
$_data = $edd_api_request_transient;
|
328 |
}
|
347 |
$_data->contributors = $this->convert_object_to_array( $_data->contributors );
|
348 |
}
|
349 |
|
350 |
+
if ( ! isset( $_data->plugin ) ) {
|
351 |
$_data->plugin = $this->name;
|
352 |
}
|
353 |
|
367 |
* @return array
|
368 |
*/
|
369 |
private function convert_object_to_array( $data ) {
|
370 |
+
if ( ! is_array( $data ) && ! is_object( $data ) ) {
|
371 |
+
return array();
|
372 |
+
}
|
373 |
$new_data = array();
|
374 |
foreach ( $data as $key => $value ) {
|
375 |
$new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
|
387 |
*/
|
388 |
public function http_request_args( $args, $url ) {
|
389 |
|
|
|
390 |
if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
|
391 |
+
$args['sslverify'] = $this->verify_ssl();
|
392 |
}
|
393 |
return $args;
|
394 |
|
403 |
*
|
404 |
* @param string $_action The requested action.
|
405 |
* @param array $_data Parameters for the API action.
|
406 |
+
* @return false|object|void
|
407 |
*/
|
408 |
private function api_request( $_action, $_data ) {
|
409 |
+
$data = array_merge( $this->api_data, $_data );
|
410 |
|
411 |
+
if ( $data['slug'] !== $this->slug ) {
|
412 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
}
|
414 |
|
415 |
+
// Don't allow a plugin to ping itself
|
416 |
+
if ( trailingslashit( home_url() ) === $this->api_url ) {
|
417 |
return false;
|
418 |
}
|
419 |
|
420 |
+
if ( $this->request_recently_failed() ) {
|
|
|
|
|
421 |
return false;
|
422 |
}
|
423 |
|
424 |
+
return $this->get_version_from_remote();
|
425 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
|
427 |
+
/**
|
428 |
+
* Determines if a request has recently failed.
|
429 |
+
*
|
430 |
+
* @since 1.9.1
|
431 |
+
*
|
432 |
+
* @return bool
|
433 |
+
*/
|
434 |
+
private function request_recently_failed() {
|
435 |
+
$failed_request_details = get_option( $this->failed_request_cache_key );
|
436 |
|
437 |
+
// Request has never failed.
|
438 |
+
if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
|
439 |
+
return false;
|
|
|
440 |
}
|
441 |
|
442 |
+
/*
|
443 |
+
* Request previously failed, but the timeout has expired.
|
444 |
+
* This means we're allowed to try again.
|
445 |
+
*/
|
446 |
+
if ( time() > $failed_request_details ) {
|
447 |
+
delete_option( $this->failed_request_cache_key );
|
448 |
|
449 |
+
return false;
|
|
|
450 |
}
|
451 |
|
452 |
+
return true;
|
453 |
+
}
|
|
|
|
|
|
|
454 |
|
455 |
+
/**
|
456 |
+
* Logs a failed HTTP request for this API URL.
|
457 |
+
* We set a timestamp for 1 hour from now. This prevents future API requests from being
|
458 |
+
* made to this domain for 1 hour. Once the timestamp is in the past, API requests
|
459 |
+
* will be allowed again. This way if the site is down for some reason we don't bombard
|
460 |
+
* it with failed API requests.
|
461 |
+
*
|
462 |
+
* @see EDD_SL_Plugin_Updater::request_recently_failed
|
463 |
+
*
|
464 |
+
* @since 1.9.1
|
465 |
+
*/
|
466 |
+
private function log_failed_request() {
|
467 |
+
update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
|
468 |
}
|
469 |
|
470 |
/**
|
472 |
*/
|
473 |
public function show_changelog() {
|
474 |
|
475 |
+
if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
|
|
|
|
|
476 |
return;
|
477 |
}
|
478 |
|
479 |
+
if ( empty( $_REQUEST['plugin'] ) ) {
|
480 |
return;
|
481 |
}
|
482 |
|
483 |
+
if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
|
484 |
return;
|
485 |
}
|
486 |
|
487 |
+
if ( ! current_user_can( 'update_plugins' ) ) {
|
488 |
+
wp_die( esc_html__( 'You do not have permission to install plugin updates', 'polylang' ), esc_html__( 'Error', 'polylang' ), array( 'response' => 403 ) );
|
489 |
}
|
490 |
|
491 |
+
$version_info = $this->get_repo_api_data();
|
492 |
+
if ( isset( $version_info->sections ) ) {
|
493 |
+
$sections = $this->convert_object_to_array( $version_info->sections );
|
494 |
+
if ( ! empty( $sections['changelog'] ) ) {
|
495 |
+
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
|
496 |
+
}
|
497 |
+
}
|
498 |
+
|
499 |
+
exit;
|
500 |
+
}
|
501 |
|
502 |
+
/**
|
503 |
+
* Gets the current version information from the remote site.
|
504 |
+
*
|
505 |
+
* @return array|false
|
506 |
+
*/
|
507 |
+
private function get_version_from_remote() {
|
508 |
+
$api_params = array(
|
509 |
+
'edd_action' => 'get_version',
|
510 |
+
'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
|
511 |
+
'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
|
512 |
+
'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
|
513 |
+
'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
|
514 |
+
'slug' => $this->slug,
|
515 |
+
'author' => $this->api_data['author'],
|
516 |
+
'url' => home_url(),
|
517 |
+
'beta' => $this->beta,
|
518 |
+
'php_version' => phpversion(),
|
519 |
+
'wp_version' => get_bloginfo( 'version' ),
|
520 |
+
);
|
521 |
|
522 |
+
/**
|
523 |
+
* Filters the parameters sent in the API request.
|
524 |
+
*
|
525 |
+
* @param array $api_params The array of data sent in the request.
|
526 |
+
* @param array $this->api_data The array of data set up in the class constructor.
|
527 |
+
* @param string $this->plugin_file The full path and filename of the file.
|
528 |
+
*/
|
529 |
+
$api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
|
530 |
+
|
531 |
+
$request = wp_remote_post(
|
532 |
+
$this->api_url,
|
533 |
+
array(
|
534 |
+
'timeout' => 15,
|
535 |
+
'sslverify' => $this->verify_ssl(),
|
536 |
+
'body' => $api_params,
|
537 |
+
)
|
538 |
+
);
|
539 |
|
540 |
+
if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
|
541 |
+
$this->log_failed_request();
|
542 |
|
543 |
+
return false;
|
544 |
+
}
|
|
|
545 |
|
546 |
+
$request = json_decode( wp_remote_retrieve_body( $request ) );
|
|
|
|
|
|
|
|
|
547 |
|
548 |
+
if ( $request && isset( $request->sections ) ) {
|
549 |
+
$request->sections = maybe_unserialize( $request->sections );
|
550 |
+
} else {
|
551 |
+
$request = false;
|
552 |
+
}
|
553 |
|
554 |
+
if ( $request && isset( $request->banners ) ) {
|
555 |
+
$request->banners = maybe_unserialize( $request->banners );
|
556 |
+
}
|
557 |
|
558 |
+
if ( $request && isset( $request->icons ) ) {
|
559 |
+
$request->icons = maybe_unserialize( $request->icons );
|
560 |
}
|
561 |
|
562 |
+
if ( ! empty( $request->sections ) ) {
|
563 |
+
foreach ( $request->sections as $key => $section ) {
|
564 |
+
$request->$key = (array) $section;
|
|
|
565 |
}
|
566 |
}
|
567 |
|
568 |
+
return $request;
|
569 |
}
|
570 |
|
571 |
/**
|
572 |
+
* Get the version info from the cache, if it exists.
|
573 |
*
|
574 |
* @param string $cache_key
|
575 |
+
* @return object
|
576 |
*/
|
577 |
public function get_cached_version_info( $cache_key = '' ) {
|
578 |
|
579 |
+
if ( empty( $cache_key ) ) {
|
580 |
+
$cache_key = $this->get_cache_key();
|
581 |
}
|
582 |
|
583 |
$cache = get_option( $cache_key );
|
584 |
|
585 |
+
// Cache is expired
|
586 |
+
if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
|
587 |
+
return false;
|
588 |
}
|
589 |
|
590 |
// We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
|
605 |
*/
|
606 |
public function set_version_info_cache( $value = '', $cache_key = '' ) {
|
607 |
|
608 |
+
if ( empty( $cache_key ) ) {
|
609 |
+
$cache_key = $this->get_cache_key();
|
610 |
}
|
611 |
|
612 |
$data = array(
|
613 |
'timeout' => strtotime( '+3 hours', time() ),
|
614 |
+
'value' => wp_json_encode( $value ),
|
615 |
);
|
616 |
|
617 |
update_option( $cache_key, $data, 'no' );
|
630 |
return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
|
631 |
}
|
632 |
|
633 |
+
/**
|
634 |
+
* Gets the unique key (option name) for a plugin.
|
635 |
+
*
|
636 |
+
* @since 1.9.0
|
637 |
+
* @return string
|
638 |
+
*/
|
639 |
+
private function get_cache_key() {
|
640 |
+
$string = $this->slug . $this->api_data['license'] . $this->beta;
|
641 |
+
|
642 |
+
return 'edd_sl_' . md5( serialize( $string ) );
|
643 |
+
}
|
644 |
+
|
645 |
}
|
integrations/integrations.php
CHANGED
@@ -35,7 +35,7 @@ class PLL_Integrations {
|
|
35 |
*
|
36 |
* @since 1.7
|
37 |
*
|
38 |
-
* @return
|
39 |
*/
|
40 |
public static function instance() {
|
41 |
if ( empty( self::$instance ) ) {
|
35 |
*
|
36 |
* @since 1.7
|
37 |
*
|
38 |
+
* @return PLL_Integrations
|
39 |
*/
|
40 |
public static function instance() {
|
41 |
if ( empty( self::$instance ) ) {
|
integrations/wp-importer/wp-import.php
CHANGED
@@ -17,14 +17,14 @@ class PLL_WP_Import extends WP_Import {
|
|
17 |
public $post_translations = array();
|
18 |
|
19 |
/**
|
20 |
-
* Overrides WP_Import::process_terms to remap terms translations
|
21 |
*
|
22 |
* @since 1.2
|
23 |
*/
|
24 |
public function process_terms() {
|
25 |
$term_translations = array();
|
26 |
|
27 |
-
// Store this for future usage as parent function unsets $this->terms
|
28 |
foreach ( $this->terms as $term ) {
|
29 |
if ( 'post_translations' == $term['term_taxonomy'] ) {
|
30 |
$this->post_translations[] = $term;
|
@@ -36,16 +36,15 @@ class PLL_WP_Import extends WP_Import {
|
|
36 |
|
37 |
parent::process_terms();
|
38 |
|
39 |
-
// Update the languages list if needed
|
40 |
// First reset the core terms cache as WordPress Importer calls wp_suspend_cache_invalidation( true );
|
41 |
wp_cache_set( 'last_changed', microtime(), 'terms' );
|
42 |
-
PLL()->model->clean_languages_cache();
|
43 |
|
44 |
-
|
45 |
-
|
|
|
46 |
$default_lang = reset( $languages );
|
47 |
-
|
48 |
-
update_option( 'polylang',
|
49 |
}
|
50 |
|
51 |
$this->remap_terms_relations( $term_translations );
|
17 |
public $post_translations = array();
|
18 |
|
19 |
/**
|
20 |
+
* Overrides WP_Import::process_terms to remap terms translations.
|
21 |
*
|
22 |
* @since 1.2
|
23 |
*/
|
24 |
public function process_terms() {
|
25 |
$term_translations = array();
|
26 |
|
27 |
+
// Store this for future usage as parent function unsets $this->terms.
|
28 |
foreach ( $this->terms as $term ) {
|
29 |
if ( 'post_translations' == $term['term_taxonomy'] ) {
|
30 |
$this->post_translations[] = $term;
|
36 |
|
37 |
parent::process_terms();
|
38 |
|
|
|
39 |
// First reset the core terms cache as WordPress Importer calls wp_suspend_cache_invalidation( true );
|
40 |
wp_cache_set( 'last_changed', microtime(), 'terms' );
|
|
|
41 |
|
42 |
+
// Assign the default language in case the importer created the first language.
|
43 |
+
if ( empty( PLL()->options['default_lang'] ) ) {
|
44 |
+
$languages = get_terms( 'language', array( 'hide_empty' => false, 'orderby' => 'term_id' ) );
|
45 |
$default_lang = reset( $languages );
|
46 |
+
PLL()->options['default_lang'] = $default_lang->slug;
|
47 |
+
update_option( 'polylang', PLL()->options );
|
48 |
}
|
49 |
|
50 |
$this->remap_terms_relations( $term_translations );
|
integrations/wpseo/wpseo.php
CHANGED
@@ -39,16 +39,12 @@ class PLL_WPSEO {
|
|
39 |
}
|
40 |
|
41 |
add_filter( 'pll_home_url_white_list', array( $this, 'wpseo_home_url_white_list' ) );
|
42 |
-
|
43 |
-
add_action( 'wpseo_opengraph', array( $this, 'wpseo_ogp' ), 2 );
|
44 |
-
} else {
|
45 |
-
add_filter( 'wpseo_frontend_presenters', array( $this, 'wpseo_frontend_presenters' ) );
|
46 |
-
}
|
47 |
add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) );
|
48 |
add_filter( 'wpseo_frontend_presentation', array( $this, 'frontend_presentation' ) );
|
49 |
add_filter( 'wpseo_breadcrumb_indexables', array( $this, 'breadcrumb_indexables' ) );
|
50 |
} else {
|
51 |
-
add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ), 10,
|
52 |
add_filter( 'pll_translate_post_meta', array( $this, 'translate_post_meta' ), 10, 3 );
|
53 |
|
54 |
// Yoast SEO adds the columns hooks only for the 'inline-save' action. We need them for 'pll_update_post_rows' too.
|
@@ -105,7 +101,7 @@ class PLL_WPSEO {
|
|
105 |
*/
|
106 |
public function wpseo_home_url( $url, $path ) {
|
107 |
if ( empty( $path ) ) {
|
108 |
-
$path = ltrim( wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' );
|
109 |
}
|
110 |
|
111 |
if ( preg_match( '#sitemap(_index)?\.xml|([^\/]+?)-?sitemap([0-9]+)?\.xml|([a-z]+)?-?sitemap\.xsl#', $path ) ) {
|
@@ -292,17 +288,17 @@ class PLL_WPSEO {
|
|
292 |
}
|
293 |
|
294 |
/**
|
295 |
-
* Get alternate language codes for Opengraph
|
296 |
*
|
297 |
* @since 2.7.3
|
298 |
*
|
299 |
-
* @return
|
300 |
*/
|
301 |
protected function get_ogp_alternate_languages() {
|
302 |
$alternates = array();
|
303 |
|
304 |
foreach ( PLL()->model->get_languages_list() as $language ) {
|
305 |
-
if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) {
|
306 |
$alternates[] = $language->facebook;
|
307 |
}
|
308 |
}
|
@@ -311,22 +307,6 @@ class PLL_WPSEO {
|
|
311 |
return array_unique( $alternates );
|
312 |
}
|
313 |
|
314 |
-
/**
|
315 |
-
* Adds opengraph support for translations
|
316 |
-
*
|
317 |
-
* @since 1.6
|
318 |
-
*/
|
319 |
-
public function wpseo_ogp() {
|
320 |
-
global $wpseo_og;
|
321 |
-
|
322 |
-
// WPSEO already deals with the locale
|
323 |
-
if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
|
324 |
-
foreach ( $this->get_ogp_alternate_languages() as $lang ) {
|
325 |
-
$wpseo_og->og_tag( 'og:locale:alternate', $lang );
|
326 |
-
}
|
327 |
-
}
|
328 |
-
}
|
329 |
-
|
330 |
/**
|
331 |
* Adds opengraph support for translations
|
332 |
*
|
@@ -438,9 +418,11 @@ class PLL_WPSEO {
|
|
438 |
*
|
439 |
* @param string[] $keys List of custom fields names.
|
440 |
* @param bool $sync True if it is synchronization, false if it is a copy.
|
|
|
|
|
441 |
* @return array
|
442 |
*/
|
443 |
-
public function copy_post_metas( $keys, $sync ) {
|
444 |
if ( ! $sync ) {
|
445 |
// Text requiring translation.
|
446 |
$keys[] = '_yoast_wpseo_title';
|
@@ -468,6 +450,10 @@ class PLL_WPSEO {
|
|
468 |
)
|
469 |
);
|
470 |
|
|
|
|
|
|
|
|
|
471 |
foreach ( $taxonomies as $taxonomy ) {
|
472 |
$keys[] = '_yoast_wpseo_primary_' . $taxonomy;
|
473 |
}
|
@@ -486,9 +472,15 @@ class PLL_WPSEO {
|
|
486 |
* @return int
|
487 |
*/
|
488 |
public function translate_post_meta( $value, $key, $lang ) {
|
489 |
-
if (
|
490 |
-
|
|
|
|
|
|
|
|
|
|
|
491 |
}
|
492 |
-
|
|
|
493 |
}
|
494 |
}
|
39 |
}
|
40 |
|
41 |
add_filter( 'pll_home_url_white_list', array( $this, 'wpseo_home_url_white_list' ) );
|
42 |
+
add_filter( 'wpseo_frontend_presenters', array( $this, 'wpseo_frontend_presenters' ) );
|
|
|
|
|
|
|
|
|
43 |
add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) );
|
44 |
add_filter( 'wpseo_frontend_presentation', array( $this, 'frontend_presentation' ) );
|
45 |
add_filter( 'wpseo_breadcrumb_indexables', array( $this, 'breadcrumb_indexables' ) );
|
46 |
} else {
|
47 |
+
add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ), 10, 4 );
|
48 |
add_filter( 'pll_translate_post_meta', array( $this, 'translate_post_meta' ), 10, 3 );
|
49 |
|
50 |
// Yoast SEO adds the columns hooks only for the 'inline-save' action. We need them for 'pll_update_post_rows' too.
|
101 |
*/
|
102 |
public function wpseo_home_url( $url, $path ) {
|
103 |
if ( empty( $path ) ) {
|
104 |
+
$path = ltrim( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' );
|
105 |
}
|
106 |
|
107 |
if ( preg_match( '#sitemap(_index)?\.xml|([^\/]+?)-?sitemap([0-9]+)?\.xml|([a-z]+)?-?sitemap\.xsl#', $path ) ) {
|
288 |
}
|
289 |
|
290 |
/**
|
291 |
+
* Get alternate language codes for Opengraph.
|
292 |
*
|
293 |
* @since 2.7.3
|
294 |
*
|
295 |
+
* @return string[]
|
296 |
*/
|
297 |
protected function get_ogp_alternate_languages() {
|
298 |
$alternates = array();
|
299 |
|
300 |
foreach ( PLL()->model->get_languages_list() as $language ) {
|
301 |
+
if ( isset( PLL()->curlang ) && PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) {
|
302 |
$alternates[] = $language->facebook;
|
303 |
}
|
304 |
}
|
307 |
return array_unique( $alternates );
|
308 |
}
|
309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
/**
|
311 |
* Adds opengraph support for translations
|
312 |
*
|
418 |
*
|
419 |
* @param string[] $keys List of custom fields names.
|
420 |
* @param bool $sync True if it is synchronization, false if it is a copy.
|
421 |
+
* @param int $from Id of the post from which we copy informations.
|
422 |
+
* @param int $to Id of the post to which we paste informations.
|
423 |
* @return array
|
424 |
*/
|
425 |
+
public function copy_post_metas( $keys, $sync, $from, $to ) {
|
426 |
if ( ! $sync ) {
|
427 |
// Text requiring translation.
|
428 |
$keys[] = '_yoast_wpseo_title';
|
450 |
)
|
451 |
);
|
452 |
|
453 |
+
$sync_taxonomies = PLL()->sync->taxonomies->get_taxonomies_to_copy( $sync, $from, $to );
|
454 |
+
|
455 |
+
$taxonomies = array_intersect( $taxonomies, $sync_taxonomies );
|
456 |
+
|
457 |
foreach ( $taxonomies as $taxonomy ) {
|
458 |
$keys[] = '_yoast_wpseo_primary_' . $taxonomy;
|
459 |
}
|
472 |
* @return int
|
473 |
*/
|
474 |
public function translate_post_meta( $value, $key, $lang ) {
|
475 |
+
if ( 0 !== strpos( $key, '_yoast_wpseo_primary_' ) ) {
|
476 |
+
return $value;
|
477 |
+
}
|
478 |
+
|
479 |
+
$taxonomy = str_replace( '_yoast_wpseo_primary_', '', $key );
|
480 |
+
if ( ! PLL()->model->is_translated_taxonomy( $taxonomy ) ) {
|
481 |
+
return $value;
|
482 |
}
|
483 |
+
|
484 |
+
return pll_get_term( $value, $lang );
|
485 |
}
|
486 |
}
|
modules/site-health/admin-site-health.php
CHANGED
@@ -43,10 +43,12 @@ class PLL_Admin_Site_Health {
|
|
43 |
// Information tab.
|
44 |
add_filter( 'debug_information', array( $this, 'info_options' ), 15 );
|
45 |
add_filter( 'debug_information', array( $this, 'info_languages' ), 15 );
|
46 |
-
add_filter( 'debug_information', array( $this, '
|
47 |
|
48 |
// Tests Tab.
|
49 |
add_filter( 'site_status_tests', array( $this, 'status_tests' ) );
|
|
|
|
|
50 |
}
|
51 |
|
52 |
/**
|
@@ -168,9 +170,10 @@ class PLL_Admin_Site_Health {
|
|
168 |
}
|
169 |
}
|
170 |
}
|
|
|
171 |
$debug_info['pll_options'] = array(
|
172 |
/* translators: placeholder is the plugin name */
|
173 |
-
'label' => sprintf(
|
174 |
'fields' => $fields,
|
175 |
);
|
176 |
|
@@ -208,7 +211,7 @@ class PLL_Admin_Site_Health {
|
|
208 |
|
209 |
$debug_info[ 'pll_language_' . $language->slug ] = array(
|
210 |
/* translators: placeholder is the language name */
|
211 |
-
'label' => sprintf(
|
212 |
/* translators: placeholder is the flag image */
|
213 |
'description' => sprintf( esc_html__( 'Flag used in the language switcher: %s', 'polylang' ), $this->get_flag( $language ) ),
|
214 |
'fields' => $fields,
|
@@ -291,9 +294,10 @@ class PLL_Admin_Site_Health {
|
|
291 |
* @param array $debug_info The debug information to be added to the core information page.
|
292 |
* @return array
|
293 |
*/
|
294 |
-
public function
|
295 |
$fields = array();
|
296 |
|
|
|
297 |
$posts_no_lang = $this->get_post_ids_without_lang();
|
298 |
|
299 |
if ( ! empty( $posts_no_lang ) ) {
|
@@ -308,9 +312,23 @@ class PLL_Admin_Site_Health {
|
|
308 |
$fields['term-no-lang']['value'] = $this->format_array( $terms_no_lang );
|
309 |
}
|
310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
if ( ! empty( $fields ) ) {
|
312 |
$debug_info['pll_warnings'] = array(
|
313 |
-
|
|
|
314 |
'fields' => $fields,
|
315 |
);
|
316 |
}
|
@@ -365,4 +383,24 @@ class PLL_Admin_Site_Health {
|
|
365 |
|
366 |
return $terms;
|
367 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
368 |
}
|
43 |
// Information tab.
|
44 |
add_filter( 'debug_information', array( $this, 'info_options' ), 15 );
|
45 |
add_filter( 'debug_information', array( $this, 'info_languages' ), 15 );
|
46 |
+
add_filter( 'debug_information', array( $this, 'info' ), 15 );
|
47 |
|
48 |
// Tests Tab.
|
49 |
add_filter( 'site_status_tests', array( $this, 'status_tests' ) );
|
50 |
+
add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health.
|
51 |
+
|
52 |
}
|
53 |
|
54 |
/**
|
170 |
}
|
171 |
}
|
172 |
}
|
173 |
+
|
174 |
$debug_info['pll_options'] = array(
|
175 |
/* translators: placeholder is the plugin name */
|
176 |
+
'label' => sprintf( __( '%s options', 'polylang' ), POLYLANG ),
|
177 |
'fields' => $fields,
|
178 |
);
|
179 |
|
211 |
|
212 |
$debug_info[ 'pll_language_' . $language->slug ] = array(
|
213 |
/* translators: placeholder is the language name */
|
214 |
+
'label' => sprintf( __( 'Language: %s', 'polylang' ), $language->name ),
|
215 |
/* translators: placeholder is the flag image */
|
216 |
'description' => sprintf( esc_html__( 'Flag used in the language switcher: %s', 'polylang' ), $this->get_flag( $language ) ),
|
217 |
'fields' => $fields,
|
294 |
* @param array $debug_info The debug information to be added to the core information page.
|
295 |
* @return array
|
296 |
*/
|
297 |
+
public function info( $debug_info ) {
|
298 |
$fields = array();
|
299 |
|
300 |
+
// Add Post Types without languages.
|
301 |
$posts_no_lang = $this->get_post_ids_without_lang();
|
302 |
|
303 |
if ( ! empty( $posts_no_lang ) ) {
|
312 |
$fields['term-no-lang']['value'] = $this->format_array( $terms_no_lang );
|
313 |
}
|
314 |
|
315 |
+
// Add WPML files.
|
316 |
+
$wpml_files = PLL_WPML_Config::instance()->get_files();
|
317 |
+
if ( ! empty( $wpml_files ) ) {
|
318 |
+
$fields['wpml']['label'] = 'wpml-config.xml files';
|
319 |
+
$fields['wpml']['value'] = $wpml_files;
|
320 |
+
|
321 |
+
if ( ! extension_loaded( 'simplexml' ) ) {
|
322 |
+
$fields['simplexml']['label'] = __( 'PHP SimpleXML extension', 'polylang' );
|
323 |
+
$fields['simplexml']['value'] = __( 'Not loaded. Contact your host provider.', 'polylang' );
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
// Create the section.
|
328 |
if ( ! empty( $fields ) ) {
|
329 |
$debug_info['pll_warnings'] = array(
|
330 |
+
/* translators: placeholder is the plugin name */
|
331 |
+
'label' => sprintf( __( '%s information', 'polylang' ), POLYLANG ),
|
332 |
'fields' => $fields,
|
333 |
);
|
334 |
}
|
383 |
|
384 |
return $terms;
|
385 |
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Requires the simplexml PHP module when a wpml-config.xml has been found.
|
389 |
+
*
|
390 |
+
* @since 3.1
|
391 |
+
* @since 3.2 Moved from PLL_WPML_Config
|
392 |
+
*
|
393 |
+
* @param array $modules An associative array of modules to test for.
|
394 |
+
* @return array
|
395 |
+
*/
|
396 |
+
public function site_status_test_php_modules( $modules ) {
|
397 |
+
$files = PLL_WPML_Config::instance()->get_files();
|
398 |
+
if ( ! empty( $files ) ) {
|
399 |
+
$modules['simplexml'] = array(
|
400 |
+
'extension' => 'simplexml',
|
401 |
+
'required' => true,
|
402 |
+
);
|
403 |
+
}
|
404 |
+
return $modules;
|
405 |
+
}
|
406 |
}
|
modules/sync/sync-metas.php
CHANGED
@@ -348,9 +348,6 @@ abstract class PLL_Sync_Metas {
|
|
348 |
public function copy( $from, $to, $lang, $sync = false ) {
|
349 |
$this->remove_all_meta_actions();
|
350 |
|
351 |
-
remove_action( "delete_{$this->meta_type}_meta", array( $this, 'store_metas_to_sync' ), 10, 2 );
|
352 |
-
remove_action( "deleted_{$this->meta_type}_meta", array( $this, 'delete_meta' ), 10, 4 );
|
353 |
-
|
354 |
$to_copy = $this->get_metas_to_copy( $from, $to, $lang, $sync );
|
355 |
$metas = get_metadata( $this->meta_type, $from );
|
356 |
$tr_metas = get_metadata( $this->meta_type, $to );
|
348 |
public function copy( $from, $to, $lang, $sync = false ) {
|
349 |
$this->remove_all_meta_actions();
|
350 |
|
|
|
|
|
|
|
351 |
$to_copy = $this->get_metas_to_copy( $from, $to, $lang, $sync );
|
352 |
$metas = get_metadata( $this->meta_type, $from );
|
353 |
$tr_metas = get_metadata( $this->meta_type, $to );
|
modules/sync/sync-post-metas.php
CHANGED
@@ -45,20 +45,22 @@ class PLL_Sync_Post_Metas extends PLL_Sync_Metas {
|
|
45 |
* @return string[] List of meta keys.
|
46 |
*/
|
47 |
protected function get_metas_to_copy( $from, $to, $lang, $sync = false ) {
|
48 |
-
// Copy or synchronize post metas and allow plugins to do the same
|
49 |
-
$metas = get_post_custom( $from );
|
50 |
$keys = array();
|
51 |
|
52 |
-
// Get public meta keys ( including from translated post in case we just deleted a custom field )
|
53 |
if ( ! $sync || in_array( 'post_meta', $this->options['sync'] ) ) {
|
54 |
-
|
|
|
|
|
|
|
|
|
55 |
if ( is_protected_meta( $meta_key ) ) {
|
56 |
unset( $keys[ $k ] );
|
57 |
}
|
58 |
}
|
59 |
}
|
60 |
|
61 |
-
// Add page template and featured image
|
62 |
foreach ( array( '_wp_page_template', '_thumbnail_id' ) as $meta ) {
|
63 |
if ( ! $sync || in_array( $meta, $this->options['sync'] ) ) {
|
64 |
$keys[] = $meta;
|
45 |
* @return string[] List of meta keys.
|
46 |
*/
|
47 |
protected function get_metas_to_copy( $from, $to, $lang, $sync = false ) {
|
|
|
|
|
48 |
$keys = array();
|
49 |
|
50 |
+
// Get public meta keys ( including from translated post in case we just deleted a custom field ).
|
51 |
if ( ! $sync || in_array( 'post_meta', $this->options['sync'] ) ) {
|
52 |
+
$from_keys = (array) get_post_custom_keys( $from );
|
53 |
+
$to_keys = (array) get_post_custom_keys( $to );
|
54 |
+
|
55 |
+
$keys = array_unique( array_merge( $from_keys, $to_keys ) );
|
56 |
+
foreach ( $keys as $k => $meta_key ) {
|
57 |
if ( is_protected_meta( $meta_key ) ) {
|
58 |
unset( $keys[ $k ] );
|
59 |
}
|
60 |
}
|
61 |
}
|
62 |
|
63 |
+
// Add page template and featured image.
|
64 |
foreach ( array( '_wp_page_template', '_thumbnail_id' ) as $meta ) {
|
65 |
if ( ! $sync || in_array( $meta, $this->options['sync'] ) ) {
|
66 |
$keys[] = $meta;
|
modules/sync/sync-tax.php
CHANGED
@@ -44,6 +44,7 @@ class PLL_Sync_Tax {
|
|
44 |
*
|
45 |
* @since 1.7
|
46 |
* @since 2.1 The `$from`, `$to`, `$lang` parameters were added.
|
|
|
47 |
*
|
48 |
* @param bool $sync True if it is synchronization, false if it is a copy.
|
49 |
* @param int $from Id of the post from which we copy informations, optional, defaults to null.
|
@@ -51,7 +52,7 @@ class PLL_Sync_Tax {
|
|
51 |
* @param string $lang Language slug, optional, defaults to null.
|
52 |
* @return string[] List of taxonomy names.
|
53 |
*/
|
54 |
-
|
55 |
$taxonomies = ! $sync || in_array( 'taxonomies', $this->options['sync'] ) ? $this->model->get_translated_taxonomies() : array();
|
56 |
if ( ! $sync || in_array( 'post_format', $this->options['sync'] ) ) {
|
57 |
$taxonomies[] = 'post_format';
|
44 |
*
|
45 |
* @since 1.7
|
46 |
* @since 2.1 The `$from`, `$to`, `$lang` parameters were added.
|
47 |
+
* @since 3.2 Changed visibility from protected to public.
|
48 |
*
|
49 |
* @param bool $sync True if it is synchronization, false if it is a copy.
|
50 |
* @param int $from Id of the post from which we copy informations, optional, defaults to null.
|
52 |
* @param string $lang Language slug, optional, defaults to null.
|
53 |
* @return string[] List of taxonomy names.
|
54 |
*/
|
55 |
+
public function get_taxonomies_to_copy( $sync, $from = null, $to = null, $lang = null ) {
|
56 |
$taxonomies = ! $sync || in_array( 'taxonomies', $this->options['sync'] ) ? $this->model->get_translated_taxonomies() : array();
|
57 |
if ( ! $sync || in_array( 'post_format', $this->options['sync'] ) ) {
|
58 |
$taxonomies[] = 'post_format';
|
modules/wpml/wpml-api.php
CHANGED
@@ -224,15 +224,21 @@ class PLL_WPML_API {
|
|
224 |
*/
|
225 |
public function wpml_element_language_code( $language_code, $args ) {
|
226 |
$type = $args['element_type'];
|
227 |
-
$id
|
228 |
-
|
229 |
-
if ( '
|
|
|
|
|
|
|
|
|
230 |
$term = get_term_by( 'term_taxonomy_id', $id );
|
231 |
if ( $term instanceof WP_Term ) {
|
232 |
$id = $term->term_id;
|
233 |
}
|
|
|
234 |
}
|
235 |
-
|
|
|
236 |
}
|
237 |
|
238 |
/**
|
@@ -302,7 +308,12 @@ class PLL_WPML_API {
|
|
302 |
* @return bool
|
303 |
*/
|
304 |
public function wpml_element_has_translations( $null, $id, $type ) {
|
305 |
-
|
306 |
-
|
|
|
|
|
|
|
|
|
|
|
307 |
}
|
308 |
}
|
224 |
*/
|
225 |
public function wpml_element_language_code( $language_code, $args ) {
|
226 |
$type = $args['element_type'];
|
227 |
+
$id = $args['element_id'];
|
228 |
+
|
229 |
+
if ( 'post' === $type || pll_is_translated_post_type( $type ) ) {
|
230 |
+
return pll_get_post_language( $id );
|
231 |
+
}
|
232 |
+
|
233 |
+
if ( 'term' === $type || pll_is_translated_taxonomy( $type ) ) {
|
234 |
$term = get_term_by( 'term_taxonomy_id', $id );
|
235 |
if ( $term instanceof WP_Term ) {
|
236 |
$id = $term->term_id;
|
237 |
}
|
238 |
+
return pll_get_term_language( $id );
|
239 |
}
|
240 |
+
|
241 |
+
return $language_code;
|
242 |
}
|
243 |
|
244 |
/**
|
308 |
* @return bool
|
309 |
*/
|
310 |
public function wpml_element_has_translations( $null, $id, $type ) {
|
311 |
+
if ( 'post' === $type || pll_is_translated_post_type( $type ) ) {
|
312 |
+
return count( pll_get_post_translations( $id ) ) > 1;
|
313 |
+
} elseif ( 'term' === $type || pll_is_translated_taxonomy( $type ) ) {
|
314 |
+
return count( pll_get_term_translations( $id ) ) > 1;
|
315 |
+
}
|
316 |
+
|
317 |
+
return false;
|
318 |
}
|
319 |
}
|
modules/wpml/wpml-config.php
CHANGED
@@ -25,6 +25,13 @@ class PLL_WPML_Config {
|
|
25 |
*/
|
26 |
protected $xmls;
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
/**
|
29 |
* Constructor
|
30 |
*
|
@@ -41,7 +48,7 @@ class PLL_WPML_Config {
|
|
41 |
*
|
42 |
* @since 1.7
|
43 |
*
|
44 |
-
* @return
|
45 |
*/
|
46 |
public static function instance() {
|
47 |
if ( empty( self::$instance ) ) {
|
@@ -62,7 +69,6 @@ class PLL_WPML_Config {
|
|
62 |
$files = $this->get_files();
|
63 |
|
64 |
if ( ! empty( $files ) ) {
|
65 |
-
add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health.
|
66 |
|
67 |
// Read all files.
|
68 |
if ( extension_loaded( 'simplexml' ) ) {
|
@@ -113,7 +119,12 @@ class PLL_WPML_Config {
|
|
113 |
*
|
114 |
* @return array
|
115 |
*/
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
117 |
$files = array();
|
118 |
|
119 |
// Plugins
|
@@ -142,23 +153,9 @@ class PLL_WPML_Config {
|
|
142 |
$files['Polylang'] = $file;
|
143 |
}
|
144 |
|
145 |
-
|
146 |
-
}
|
147 |
|
148 |
-
|
149 |
-
* Requires the simplexml PHP module when a wpml-config.xml has been found.
|
150 |
-
*
|
151 |
-
* @since 3.1
|
152 |
-
*
|
153 |
-
* @param array $modules An associative array of modules to test for.
|
154 |
-
* @return array
|
155 |
-
*/
|
156 |
-
public function site_status_test_php_modules( $modules ) {
|
157 |
-
$modules['simplexml'] = array(
|
158 |
-
'extension' => 'simplexml',
|
159 |
-
'required' => true,
|
160 |
-
);
|
161 |
-
return $modules;
|
162 |
}
|
163 |
|
164 |
/**
|
@@ -270,9 +267,9 @@ class PLL_WPML_Config {
|
|
270 |
*
|
271 |
* @since 2.8
|
272 |
*
|
273 |
-
* @param string
|
274 |
-
* @param string
|
275 |
-
* @param
|
276 |
* @return void
|
277 |
*/
|
278 |
protected function register_or_translate_option( $context, $name, $key ) {
|
@@ -285,8 +282,8 @@ class PLL_WPML_Config {
|
|
285 |
*
|
286 |
* @since 2.9
|
287 |
*
|
288 |
-
* @param
|
289 |
-
* @param array
|
290 |
* @return array
|
291 |
*/
|
292 |
protected function xml_to_array( $key, &$arr = array() ) {
|
25 |
*/
|
26 |
protected $xmls;
|
27 |
|
28 |
+
/**
|
29 |
+
* The list of xml files.
|
30 |
+
*
|
31 |
+
* @var string[]
|
32 |
+
*/
|
33 |
+
protected $files;
|
34 |
+
|
35 |
/**
|
36 |
* Constructor
|
37 |
*
|
48 |
*
|
49 |
* @since 1.7
|
50 |
*
|
51 |
+
* @return PLL_WPML_Config
|
52 |
*/
|
53 |
public static function instance() {
|
54 |
if ( empty( self::$instance ) ) {
|
69 |
$files = $this->get_files();
|
70 |
|
71 |
if ( ! empty( $files ) ) {
|
|
|
72 |
|
73 |
// Read all files.
|
74 |
if ( extension_loaded( 'simplexml' ) ) {
|
119 |
*
|
120 |
* @return array
|
121 |
*/
|
122 |
+
public function get_files() {
|
123 |
+
|
124 |
+
if ( ! empty( $this->files ) ) {
|
125 |
+
return $this->files;
|
126 |
+
}
|
127 |
+
|
128 |
$files = array();
|
129 |
|
130 |
// Plugins
|
153 |
$files['Polylang'] = $file;
|
154 |
}
|
155 |
|
156 |
+
$this->files = $files;
|
|
|
157 |
|
158 |
+
return $files;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
}
|
160 |
|
161 |
/**
|
267 |
*
|
268 |
* @since 2.8
|
269 |
*
|
270 |
+
* @param string $context The group in which the strings will be registered.
|
271 |
+
* @param string $name Option name.
|
272 |
+
* @param SimpleXMLElement $key XML node.
|
273 |
* @return void
|
274 |
*/
|
275 |
protected function register_or_translate_option( $context, $name, $key ) {
|
282 |
*
|
283 |
* @since 2.9
|
284 |
*
|
285 |
+
* @param SimpleXMLElement $key XML node.
|
286 |
+
* @param array $arr Array of option keys to translate.
|
287 |
* @return array
|
288 |
*/
|
289 |
protected function xml_to_array( $key, &$arr = array() ) {
|
modules/wpml/wpml-legacy-api.php
CHANGED
@@ -157,34 +157,61 @@ if ( ! function_exists( 'icl_link_to_element' ) ) {
|
|
157 |
|
158 |
if ( ! function_exists( 'icl_object_id' ) ) {
|
159 |
/**
|
160 |
-
*
|
161 |
*
|
162 |
* @since 0.9.5
|
163 |
*
|
164 |
-
* @param int
|
165 |
-
* @param string
|
166 |
-
* @param bool
|
167 |
-
* @param string $
|
168 |
-
* @return int|null The object id of the translation, null if the translation is missing and $return_original_if_missing set to false
|
169 |
*/
|
170 |
-
function icl_object_id( $
|
171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
|
173 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
174 |
$theme = get_option( 'stylesheet' );
|
175 |
if ( isset( PLL()->options['nav_menus'][ $theme ] ) ) {
|
176 |
foreach ( PLL()->options['nav_menus'][ $theme ] as $menu ) {
|
177 |
-
if ( array_search( $
|
178 |
-
$tr_id = $menu[ $
|
179 |
break;
|
180 |
}
|
181 |
}
|
182 |
}
|
183 |
-
} elseif (
|
184 |
-
$tr_id = PLL()->model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
}
|
186 |
|
187 |
-
return
|
188 |
}
|
189 |
}
|
190 |
|
157 |
|
158 |
if ( ! function_exists( 'icl_object_id' ) ) {
|
159 |
/**
|
160 |
+
* Returns an element’s ID in the current language or in another specified language.
|
161 |
*
|
162 |
* @since 0.9.5
|
163 |
*
|
164 |
+
* @param int $element_id Object id.
|
165 |
+
* @param string $element_type Optional, post type or taxonomy name of the object, defaults to 'post'.
|
166 |
+
* @param bool $return_original_if_missing Optional, true if Polylang should return the original id if the translation is missing, defaults to false.
|
167 |
+
* @param string|null $ulanguage_code Optional, language code, defaults to the current language.
|
168 |
+
* @return int|null The object id of the translation, null if the translation is missing and $return_original_if_missing set to false.
|
169 |
*/
|
170 |
+
function icl_object_id( $element_id, $element_type = 'post', $return_original_if_missing = false, $ulanguage_code = null ) {
|
171 |
+
if ( empty( $element_id ) ) {
|
172 |
+
return null;
|
173 |
+
}
|
174 |
+
|
175 |
+
$element_id = (int) $element_id;
|
176 |
+
|
177 |
+
if ( 'any' === $element_type ) {
|
178 |
+
$element_type = get_post_type( $element_id );
|
179 |
+
}
|
180 |
+
|
181 |
+
if ( empty( $element_type ) ) {
|
182 |
+
return null;
|
183 |
+
}
|
184 |
|
185 |
+
if ( empty( $ulanguage_code ) ) {
|
186 |
+
$ulanguage_code = pll_current_language();
|
187 |
+
}
|
188 |
+
|
189 |
+
if ( 'nav_menu' === $element_type ) {
|
190 |
+
$tr_id = false;
|
191 |
$theme = get_option( 'stylesheet' );
|
192 |
if ( isset( PLL()->options['nav_menus'][ $theme ] ) ) {
|
193 |
foreach ( PLL()->options['nav_menus'][ $theme ] as $menu ) {
|
194 |
+
if ( array_search( $element_id, $menu ) && ! empty( $menu[ $ulanguage_code ] ) ) {
|
195 |
+
$tr_id = $menu[ $ulanguage_code ];
|
196 |
break;
|
197 |
}
|
198 |
}
|
199 |
}
|
200 |
+
} elseif ( pll_is_translated_post_type( $element_type ) ) {
|
201 |
+
$tr_id = PLL()->model->post->get_translation( $element_id, $ulanguage_code );
|
202 |
+
} elseif ( pll_is_translated_taxonomy( $element_type ) ) {
|
203 |
+
$tr_id = PLL()->model->term->get_translation( $element_id, $ulanguage_code );
|
204 |
+
}
|
205 |
+
|
206 |
+
if ( ! isset( $tr_id ) ) {
|
207 |
+
return $element_id; // WPML doesn't honor $return_original_if_missing if the post type or taxonomy is not translated.
|
208 |
+
}
|
209 |
+
|
210 |
+
if ( empty( $tr_id ) ) {
|
211 |
+
return $return_original_if_missing ? $element_id : null;
|
212 |
}
|
213 |
|
214 |
+
return (int) $tr_id;
|
215 |
}
|
216 |
}
|
217 |
|
polylang.php
CHANGED
@@ -10,8 +10,8 @@
|
|
10 |
* Plugin Name: Polylang
|
11 |
* Plugin URI: https://polylang.pro
|
12 |
* Description: Adds multilingual capability to WordPress
|
13 |
-
* Version: 3.
|
14 |
-
* Requires at least: 5.
|
15 |
* Requires PHP: 5.6
|
16 |
* Author: WP SYNTEX
|
17 |
* Author URI: https://polylang.pro
|
@@ -53,8 +53,8 @@ if ( defined( 'POLYLANG_VERSION' ) ) {
|
|
53 |
}
|
54 |
} else {
|
55 |
// Go on loading the plugin
|
56 |
-
define( 'POLYLANG_VERSION', '3.
|
57 |
-
define( 'PLL_MIN_WP_VERSION', '5.
|
58 |
define( 'PLL_MIN_PHP_VERSION', '5.6' );
|
59 |
|
60 |
define( 'POLYLANG_FILE', __FILE__ );
|
10 |
* Plugin Name: Polylang
|
11 |
* Plugin URI: https://polylang.pro
|
12 |
* Description: Adds multilingual capability to WordPress
|
13 |
+
* Version: 3.2
|
14 |
+
* Requires at least: 5.6
|
15 |
* Requires PHP: 5.6
|
16 |
* Author: WP SYNTEX
|
17 |
* Author URI: https://polylang.pro
|
53 |
}
|
54 |
} else {
|
55 |
// Go on loading the plugin
|
56 |
+
define( 'POLYLANG_VERSION', '3.2' );
|
57 |
+
define( 'PLL_MIN_WP_VERSION', '5.6' );
|
58 |
define( 'PLL_MIN_PHP_VERSION', '5.6' );
|
59 |
|
60 |
define( 'POLYLANG_FILE', __FILE__ );
|
readme.txt
CHANGED
@@ -1,34 +1,59 @@
|
|
1 |
=== Polylang ===
|
2 |
-
Contributors: Chouby, manooweb, raaaahman, marianne38, sebastienserre
|
3 |
Donate link: https://polylang.pro
|
4 |
Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
|
5 |
-
Requires at least: 5.
|
6 |
-
Tested up to: 5.
|
7 |
Requires PHP: 5.6
|
8 |
-
Stable tag: 3.
|
9 |
License: GPLv3 or later
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
11 |
|
12 |
-
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
-
|
17 |
|
18 |
-
|
19 |
|
20 |
-
|
21 |
-
* You can translate posts, pages, media, categories, post tags, menus, widgets...
|
22 |
-
* Custom post types, custom taxonomies, sticky posts and post formats, RSS feeds and all default WordPress widgets are supported.
|
23 |
-
* The language is either set by the content or by the language code in url, or you can use one different subdomain or domain per language
|
24 |
-
* Categories, post tags as well as some other metas are automatically copied when adding a new post or page translation
|
25 |
-
* A customizable language switcher is provided as a widget or in the nav menu
|
26 |
|
27 |
-
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
= Credits =
|
34 |
|
@@ -37,18 +62,12 @@ Thanks a lot to [Alex Lopez](http://www.alexlopez.rocks/) for the design of the
|
|
37 |
Most of the flags included with Polylang are coming from [famfamfam](http://famfamfam.com/) and are public domain.
|
38 |
Wherever third party code has been used, credit has been given in the code’s comments.
|
39 |
|
40 |
-
= Do you like Polylang? =
|
41 |
-
|
42 |
-
Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-reviews/polylang#postform).
|
43 |
-
|
44 |
== Installation ==
|
45 |
|
46 |
-
1. Make sure you are using WordPress 5.
|
47 |
1. If you tried other multilingual plugins, deactivate them before activating Polylang, otherwise, you may get unexpected results!
|
48 |
1. Install and activate the plugin as usual from the 'Plugins' menu in WordPress.
|
49 |
-
1.
|
50 |
-
1. Add the 'language switcher' widget to let your visitors switch the language.
|
51 |
-
1. Take care that your theme must come with the corresponding .mo files (Polylang automatically downloads them when they are available for themes and plugins in this repository). If your theme is not internationalized yet, please refer to the [Theme Handbook](https://developer.wordpress.org/themes/functionality/internationalization/) or ask the theme author to internationalize it.
|
52 |
|
53 |
== Frequently Asked Questions ==
|
54 |
|
@@ -59,11 +78,11 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
|
|
59 |
* Search the [community support forum](https://wordpress.org/search/). You will probably find your answer here.
|
60 |
* Read the sticky posts in the [community support forum](http://wordpress.org/support/plugin/polylang).
|
61 |
* If you still have a problem, open a new thread in the [community support forum](http://wordpress.org/support/plugin/polylang).
|
62 |
-
* [Polylang Pro](https://polylang.pro) users have access to our helpdesk.
|
63 |
|
64 |
= Is Polylang compatible with WooCommerce? =
|
65 |
|
66 |
-
* You need
|
67 |
|
68 |
= Do you need translation services? =
|
69 |
|
@@ -78,6 +97,38 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
|
|
78 |
|
79 |
== Changelog ==
|
80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
= 3.1.4 (2022-01-31) =
|
82 |
|
83 |
* Pro: Adapt duplication and synchronization of the gallery block refactored in WP 5.9
|
1 |
=== Polylang ===
|
2 |
+
Contributors: Chouby, manooweb, raaaahman, marianne38, sebastienserre, greglone, hugod
|
3 |
Donate link: https://polylang.pro
|
4 |
Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
|
5 |
+
Requires at least: 5.6
|
6 |
+
Tested up to: 5.9
|
7 |
Requires PHP: 5.6
|
8 |
+
Stable tag: 3.2
|
9 |
License: GPLv3 or later
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
11 |
|
12 |
+
Go multilingual in a simple and efficient way. Keep writing posts, creating categories and post tags as usual while defining the language all at once.
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
+
With Polylang fully integrated to WordPress and using only its built-in core features (taxonomies), keep steady performances on your site and create a multilingual site featuring from just one extra language to 10 or more depending on your needs. There is no limit in the number of languages added and WordPress’ language packs are automatically downloaded when ready.
|
17 |
|
18 |
+
= Features =
|
19 |
|
20 |
+
Depending on the type of site you have built or are planning to build, a combination of plugins from the list below might be of interest:
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
+
### Polylang
|
23 |
|
24 |
+
Polylang and [Polylang Pro](https://polylang.pro) share the same core providing features such as:
|
25 |
+
* Translating posts, pages, media, categories, post tags, custom post types and taxonomies, RSS feeds; RTL scripts are supported.
|
26 |
+
* The language is either set by the language code in URL, or you can use a different sub-domain or domain per language.
|
27 |
+
* Automatic copy of categories, post tags and other metas when creating a new post or page translation.
|
28 |
+
* Translating menus and widgets.
|
29 |
+
* Customizable language switcher available as a widget or a navigation menu item.
|
30 |
|
31 |
+
### Polylang Pro
|
32 |
+
|
33 |
+
Helps optimizing the time spent translating your site with some very useful extra features such as:
|
34 |
+
* Better integration in the new Block Editor.
|
35 |
+
* Language switcher available as a block.
|
36 |
+
* Widget block editor and full Site Editing (FSE) compatibility.
|
37 |
+
* Duplicate and/or synchronize content across post translations.
|
38 |
+
* Improved compatibilities with other plugins such as [ACF Pro](https://polylang.pro/doc/working-with-acf-pro/).
|
39 |
+
* Share the same URL slug for posts or terms across languages.
|
40 |
+
* [Translate the slugs](https://polylang.pro/doc/translating-urls-slugs/) in the URL for category and author bases, custom post types and more...
|
41 |
+
* **Access to a Premium Support for personalized assistance**
|
42 |
+
|
43 |
+
### Polylang for WooCommerce
|
44 |
+
|
45 |
+
[Add-on](https://polylang.pro/downloads/polylang-for-woocommerce/) for the compatibility with WooCommerce will provide features such as:
|
46 |
+
* Translating WooCommerce pages (shop, check-out, cart, my account), product categories and global attribute terms directly in the WooCommerce interface.
|
47 |
+
* Translating WooCommerce e-mails and sending them to customers in their language.
|
48 |
+
* Products metadata synchronization.
|
49 |
+
* Compatibility with the native WooCommerce CSV import & export tool.
|
50 |
+
* Compatibility with popular plugins such as WooCommerce Subscriptions, Product Bundles, WooCommerce Bookings, Shipment tracking and more.
|
51 |
+
* Ability to use the WooCommerce REST API (available with Polylang Pro).
|
52 |
+
* **Access to a Premium Support for personalized assistance**
|
53 |
+
|
54 |
+
Neither of them will allow you to do automated translation. Nevertheless, you can install, alongside Polylang Pro or Polylang, a third party plugin such as [Lingotek Translation](https://wordpress.org/plugins/lingotek-translation/) which offers a complete translation management system and provides services such as a translation memory or semi-automated translation processes (e.g., machine translation => human translation => legal review).
|
55 |
+
|
56 |
+
If you wish to migrate from WPML, you can use the plugin [WPML to Polylang](https://wordpress.org/plugins/wpml-to-polylang/).
|
57 |
|
58 |
= Credits =
|
59 |
|
62 |
Most of the flags included with Polylang are coming from [famfamfam](http://famfamfam.com/) and are public domain.
|
63 |
Wherever third party code has been used, credit has been given in the code’s comments.
|
64 |
|
|
|
|
|
|
|
|
|
65 |
== Installation ==
|
66 |
|
67 |
+
1. Make sure you are using WordPress 5.6 or later and that your server is running PHP 5.6 or later (same requirement as WordPress itself).
|
68 |
1. If you tried other multilingual plugins, deactivate them before activating Polylang, otherwise, you may get unexpected results!
|
69 |
1. Install and activate the plugin as usual from the 'Plugins' menu in WordPress.
|
70 |
+
1. The [setup wizard](https://polylang.pro/doc/setup-wizard/) is automatically launched to help you get started more easily with Polylang by configuring the main features.
|
|
|
|
|
71 |
|
72 |
== Frequently Asked Questions ==
|
73 |
|
78 |
* Search the [community support forum](https://wordpress.org/search/). You will probably find your answer here.
|
79 |
* Read the sticky posts in the [community support forum](http://wordpress.org/support/plugin/polylang).
|
80 |
* If you still have a problem, open a new thread in the [community support forum](http://wordpress.org/support/plugin/polylang).
|
81 |
+
* [Polylang Pro and Polylang for WooCommerce](https://polylang.pro) users have access to our helpdesk.
|
82 |
|
83 |
= Is Polylang compatible with WooCommerce? =
|
84 |
|
85 |
+
* You need [Polylang for WooCommerce](https://polylang.pro/downloads/polylang-for-woocommerce/), a premium addon, to make both plugins work together.
|
86 |
|
87 |
= Do you need translation services? =
|
88 |
|
97 |
|
98 |
== Changelog ==
|
99 |
|
100 |
+
= 3.2 (2022-04-12) =
|
101 |
+
|
102 |
+
* Requires WP 5.6 as minimum version
|
103 |
+
* Pro: Add compatibility with the full site editing introduced in WP 5.9
|
104 |
+
* Pro: Add a language switcher block for the navigation block introduced in WP 5.9
|
105 |
+
* Pro: Add compatibility with the new gallery block introduced in WP 5.9
|
106 |
+
* Pro: Make the language switcher block available in the widget section of the customizer
|
107 |
+
* Pro: Fix wrong category when translating the latest block
|
108 |
+
* Pro: Fix the language switcher block when using the dropdown option
|
109 |
+
* Pro: Fix some edge cases with locale fallback
|
110 |
+
* Pro: Fix post template replacing the post content when duplicating a post
|
111 |
+
* Pro: Fix synchronization groups not correctly cleaned up when a language is deleted
|
112 |
+
* Pro: Fix incorrect sticky property when duplicating / synchronizing posts
|
113 |
+
* Pro: Fix "Page for posts" label after the page has been bulk translated
|
114 |
+
* Pro: Fix translated slug when the url includes a query string
|
115 |
+
* Pro: Synchronize ACF layout fields if a child field is synchronized or translatable
|
116 |
+
* Pro: Fix wrong field group translation displayed when using object cache with ACF
|
117 |
+
* Update plugin updater to 1.9.1
|
118 |
+
* Add compatibility with the block site title introduced in WP 5.9
|
119 |
+
* Add the list of wpml-config.xml files in the site health information
|
120 |
+
* Improve the performance of the get_pages() filter #980
|
121 |
+
* Improve the compatibility of 'wpml_object_id' with the original filter #972
|
122 |
+
* Prevent term_exists to be filtered by language in WP 6.0
|
123 |
+
* Fix some PHP 8.1 deprecations #949 #985
|
124 |
+
* Fix a fatal error in PHP 8.1 #987
|
125 |
+
* Fix category feed not redirected when the langage code is wrong #887
|
126 |
+
* Fix default category not created for secondary languages (introduced in 3.1) #997
|
127 |
+
* Fix parent page when the parent post type is not translatable #1001
|
128 |
+
* Fix the Yoast SEO breadcrumb when it includes a non-synchronized taxonomy #1005
|
129 |
+
* Fix a PHP Notice when adding a new language and Yoast SEO is active #979
|
130 |
+
* Fix a PHP warning in Yoast SEO compatibility #954
|
131 |
+
|
132 |
= 3.1.4 (2022-01-31) =
|
133 |
|
134 |
* Pro: Adapt duplication and synchronization of the gallery block refactored in WP 5.9
|
settings/settings-module.php
CHANGED
@@ -81,7 +81,7 @@ class PLL_Settings_Module {
|
|
81 |
/**
|
82 |
* Stores html form when provided by a child class.
|
83 |
*
|
84 |
-
* @var
|
85 |
*/
|
86 |
protected $form = false;
|
87 |
|
@@ -251,9 +251,10 @@ class PLL_Settings_Module {
|
|
251 |
// Don't use flush_rewrite_rules as we don't have the right links model and permastruct
|
252 |
delete_option( 'rewrite_rules' );
|
253 |
|
|
|
254 |
ob_start();
|
255 |
|
256 |
-
if (
|
257 |
// Send update message
|
258 |
add_settings_error( 'general', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'updated' );
|
259 |
settings_errors();
|
81 |
/**
|
82 |
* Stores html form when provided by a child class.
|
83 |
*
|
84 |
+
* @var string|false
|
85 |
*/
|
86 |
protected $form = false;
|
87 |
|
251 |
// Don't use flush_rewrite_rules as we don't have the right links model and permastruct
|
252 |
delete_option( 'rewrite_rules' );
|
253 |
|
254 |
+
|
255 |
ob_start();
|
256 |
|
257 |
+
if ( empty( get_settings_errors() ) ) {
|
258 |
// Send update message
|
259 |
add_settings_error( 'general', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'updated' );
|
260 |
settings_errors();
|
settings/settings.php
CHANGED
@@ -364,7 +364,8 @@ class PLL_Settings extends PLL_Admin_Base {
|
|
364 |
* @return void
|
365 |
*/
|
366 |
public static function redirect( $args = array() ) {
|
367 |
-
|
|
|
368 |
set_transient( 'settings_errors', $errors, 30 );
|
369 |
$args['settings-updated'] = 1;
|
370 |
}
|
364 |
* @return void
|
365 |
*/
|
366 |
public static function redirect( $args = array() ) {
|
367 |
+
$errors = get_settings_errors();
|
368 |
+
if ( ! empty( $errors ) ) {
|
369 |
set_transient( 'settings_errors', $errors, 30 );
|
370 |
$args['settings-updated'] = 1;
|
371 |
}
|
settings/table-languages.php
CHANGED
@@ -229,12 +229,12 @@ class PLL_Table_Languages extends WP_List_Table {
|
|
229 |
}
|
230 |
|
231 |
/**
|
232 |
-
*
|
233 |
*
|
234 |
* @since 0.1
|
235 |
*
|
236 |
-
* @param
|
237 |
-
* @param
|
238 |
* @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
|
239 |
*/
|
240 |
protected function usort_reorder( $a, $b ) {
|
@@ -245,16 +245,16 @@ class PLL_Table_Languages extends WP_List_Table {
|
|
245 |
} else {
|
246 |
$result = strcmp( $a->$orderby, $b->$orderby );
|
247 |
}
|
248 |
-
// Send final sort direction to usort
|
249 |
return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // phpcs:ignore WordPress.Security.NonceVerification
|
250 |
}
|
251 |
|
252 |
/**
|
253 |
-
* Prepares the list of
|
254 |
*
|
255 |
* @since 0.1
|
256 |
*
|
257 |
-
* @param
|
258 |
* @return void
|
259 |
*/
|
260 |
public function prepare_items( $data = array() ) {
|
229 |
}
|
230 |
|
231 |
/**
|
232 |
+
* Sorts language items.
|
233 |
*
|
234 |
* @since 0.1
|
235 |
*
|
236 |
+
* @param PLL_Language $a The first language to compare.
|
237 |
+
* @param PLL_Language $b The second language to compare.
|
238 |
* @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
|
239 |
*/
|
240 |
protected function usort_reorder( $a, $b ) {
|
245 |
} else {
|
246 |
$result = strcmp( $a->$orderby, $b->$orderby );
|
247 |
}
|
248 |
+
// Send final sort direction to usort.
|
249 |
return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // phpcs:ignore WordPress.Security.NonceVerification
|
250 |
}
|
251 |
|
252 |
/**
|
253 |
+
* Prepares the list of languages for display.
|
254 |
*
|
255 |
* @since 0.1
|
256 |
*
|
257 |
+
* @param PLL_Language[] $data The list of languages.
|
258 |
* @return void
|
259 |
*/
|
260 |
public function prepare_items( $data = array() ) {
|
settings/table-string.php
CHANGED
@@ -211,12 +211,12 @@ class PLL_Table_String extends WP_List_Table {
|
|
211 |
}
|
212 |
|
213 |
/**
|
214 |
-
*
|
215 |
*
|
216 |
* @since 0.6
|
217 |
*
|
218 |
-
* @param
|
219 |
-
* @param
|
220 |
* @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
|
221 |
*/
|
222 |
protected function usort_reorder( $a, $b ) {
|
@@ -232,7 +232,7 @@ class PLL_Table_String extends WP_List_Table {
|
|
232 |
}
|
233 |
|
234 |
/**
|
235 |
-
* Prepares the list of
|
236 |
*
|
237 |
* @since 0.6
|
238 |
*
|
211 |
}
|
212 |
|
213 |
/**
|
214 |
+
* Sorts registered string items.
|
215 |
*
|
216 |
* @since 0.6
|
217 |
*
|
218 |
+
* @param array $a The first item to compare.
|
219 |
+
* @param array $b The second item to compare.
|
220 |
* @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
|
221 |
*/
|
222 |
protected function usort_reorder( $a, $b ) {
|
232 |
}
|
233 |
|
234 |
/**
|
235 |
+
* Prepares the list of registered strings for display.
|
236 |
*
|
237 |
* @since 0.6
|
238 |
*
|
settings/view-tab-strings.php
CHANGED
@@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
26 |
<div class="metabox-holder">
|
27 |
<?php
|
28 |
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
|
29 |
-
do_meta_boxes( 'languages_page_mlang_strings', '
|
30 |
?>
|
31 |
</div>
|
32 |
|
26 |
<div class="metabox-holder">
|
27 |
<?php
|
28 |
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
|
29 |
+
do_meta_boxes( 'languages_page_mlang_strings', 'normal', array() );
|
30 |
?>
|
31 |
</div>
|
32 |
|
vendor/composer/autoload_classmap.php
CHANGED
@@ -43,6 +43,7 @@ return array(
|
|
43 |
'PLL_Choose_Lang_Domain' => $baseDir . '/frontend/choose-lang-domain.php',
|
44 |
'PLL_Choose_Lang_Url' => $baseDir . '/frontend/choose-lang-url.php',
|
45 |
'PLL_Cookie' => $baseDir . '/include/cookie.php',
|
|
|
46 |
'PLL_Domain_Mapping' => $baseDir . '/integrations/domain-mapping/domain-mapping.php',
|
47 |
'PLL_Duplicate_Post' => $baseDir . '/integrations/duplicate-post/duplicate-post.php',
|
48 |
'PLL_Featured_Content' => $baseDir . '/integrations/jetpack/featured-content.php',
|
43 |
'PLL_Choose_Lang_Domain' => $baseDir . '/frontend/choose-lang-domain.php',
|
44 |
'PLL_Choose_Lang_Url' => $baseDir . '/frontend/choose-lang-url.php',
|
45 |
'PLL_Cookie' => $baseDir . '/include/cookie.php',
|
46 |
+
'PLL_Db_Tools' => $baseDir . '/include/db-tools.php',
|
47 |
'PLL_Domain_Mapping' => $baseDir . '/integrations/domain-mapping/domain-mapping.php',
|
48 |
'PLL_Duplicate_Post' => $baseDir . '/integrations/duplicate-post/duplicate-post.php',
|
49 |
'PLL_Featured_Content' => $baseDir . '/integrations/jetpack/featured-content.php',
|
vendor/composer/autoload_static.php
CHANGED
@@ -44,6 +44,7 @@ class ComposerStaticInit57e007bdf76a1fe336cb43b59389545b
|
|
44 |
'PLL_Choose_Lang_Domain' => __DIR__ . '/../..' . '/frontend/choose-lang-domain.php',
|
45 |
'PLL_Choose_Lang_Url' => __DIR__ . '/../..' . '/frontend/choose-lang-url.php',
|
46 |
'PLL_Cookie' => __DIR__ . '/../..' . '/include/cookie.php',
|
|
|
47 |
'PLL_Domain_Mapping' => __DIR__ . '/../..' . '/integrations/domain-mapping/domain-mapping.php',
|
48 |
'PLL_Duplicate_Post' => __DIR__ . '/../..' . '/integrations/duplicate-post/duplicate-post.php',
|
49 |
'PLL_Featured_Content' => __DIR__ . '/../..' . '/integrations/jetpack/featured-content.php',
|
44 |
'PLL_Choose_Lang_Domain' => __DIR__ . '/../..' . '/frontend/choose-lang-domain.php',
|
45 |
'PLL_Choose_Lang_Url' => __DIR__ . '/../..' . '/frontend/choose-lang-url.php',
|
46 |
'PLL_Cookie' => __DIR__ . '/../..' . '/include/cookie.php',
|
47 |
+
'PLL_Db_Tools' => __DIR__ . '/../..' . '/include/db-tools.php',
|
48 |
'PLL_Domain_Mapping' => __DIR__ . '/../..' . '/integrations/domain-mapping/domain-mapping.php',
|
49 |
'PLL_Duplicate_Post' => __DIR__ . '/../..' . '/integrations/duplicate-post/duplicate-post.php',
|
50 |
'PLL_Featured_Content' => __DIR__ . '/../..' . '/integrations/jetpack/featured-content.php',
|