├── .gitignore ├── vendor ├── composer │ ├── installed.json │ ├── autoload_psr4.php │ ├── autoload_namespaces.php │ ├── installed.php │ ├── LICENSE │ └── autoload_real.php └── autoload.php ├── js └── build │ ├── media.min.js │ ├── filter-path-middleware.min.js │ ├── user.min.js │ ├── admin.min.js │ ├── media.js │ ├── metabox-button.min.js │ ├── index.min.js │ ├── filter-path-middleware.js │ ├── metabox-autocomplete.min.js │ ├── user.js │ ├── bulk-translate.min.js │ ├── confirmation-modal.min.js │ ├── metabox-button.js │ ├── widgets.min.js │ ├── admin.js │ ├── integrations │ └── acf.min.js │ ├── post.min.js │ ├── index.js │ ├── metabox-autocomplete.js │ └── nav-menu.min.js ├── modules ├── duplicate │ ├── uninstall.php │ ├── load.php │ ├── duplicate.php │ └── duplicate-rest.php ├── Machine_Translation │ ├── uninstall.php │ ├── Views │ │ ├── progress-bar.php │ │ ├── characters-consumption-row.php │ │ ├── inner-notice.php │ │ ├── inner-notices-row.php │ │ └── string-form.php │ ├── Clients │ │ └── Client_Interface.php │ ├── Settings │ │ └── Settings_Interface.php │ ├── load.php │ ├── Posts │ │ ├── Button.php │ │ └── Button_REST.php │ ├── Strings │ │ └── Metabox.php │ └── css │ │ └── machine-translation-settings.css ├── translate-slugs │ ├── uninstall.php │ ├── load.php │ └── settings-translate-slugs.php ├── active-languages │ └── load.php ├── rest │ ├── load.php │ └── rest-comment.php ├── locale-fallback │ ├── load.php │ └── view-locale-fallback.php ├── sync │ └── load.php ├── Site_Health │ ├── load.php │ └── Info.php ├── wizard │ ├── load.php │ └── wizard-pro.php ├── bulk-translate │ ├── load.php │ ├── view-bulk-translate-option.php │ ├── css │ │ └── bulk-translate.css │ └── view-bulk-translate.php ├── xdata │ ├── load.php │ └── xdata-session-manager.php ├── import-export │ ├── xliff │ │ ├── export │ │ │ └── xliff-export-20.php │ │ └── xliff-format.php │ ├── load.php │ ├── export │ │ ├── view-export-file-format.php │ │ ├── export-file.php │ │ ├── strings-form-trait.php │ │ └── view-tab-export-strings.php │ ├── file-format │ │ └── file-format.php │ ├── po │ │ └── po-format.php │ └── import │ │ ├── view-tab-import-translations.php │ │ ├── import-file-interface.php │ │ └── import-object-interface.php ├── blocks │ ├── load.php │ └── language-switcher │ │ └── language-switcher-block.php ├── module-interface.php ├── Widget_Blocks │ ├── load.php │ └── Frontend_Filters.php ├── frontend-filter-template │ ├── load.php │ ├── filter-template-single.php │ ├── filter-template-custom-taxonomy.php │ ├── filter-templates.php │ ├── filter-template-page.php │ ├── filter-template-core-taxonomy.php │ └── abstract-filter-template.php ├── share-slug │ ├── load.php │ └── settings-share-slug.php ├── sync-post │ ├── load.php │ └── sync-post-bulk-option.php ├── Editors │ ├── load.php │ └── Screens │ │ ├── Post.php │ │ ├── Widget.php │ │ └── Site.php ├── media │ ├── media-bulk-option.php │ ├── load.php │ └── settings-advanced-media.php └── full-site-editing │ ├── fse-abstract-module.php │ ├── load.php │ ├── fse-post-types.php │ ├── fse-post-deletion.php │ ├── fse-default-language-change.php │ ├── fse-language-slug-change.php │ └── fse-language.php ├── css └── build │ ├── metabox-button.min.css │ ├── metabox-button.css │ ├── bulk-translate.min.css │ ├── translations-dashboard.min.css │ ├── bulk-translate.css │ ├── dialog.min.css │ ├── machine-translation-settings.min.css │ ├── translations-dashboard.css │ ├── machine-translation-settings.css │ └── dialog.css ├── integrations ├── beaver-builder │ ├── load.php │ └── flbuilder.php ├── cptui │ └── load.php ├── divi │ ├── load.php │ └── divi-builder.php ├── events-calendar │ └── load.php ├── admin-columns │ ├── load.php │ └── cpac.php ├── content-blocks │ ├── load.php │ └── content-blocks.php └── acf │ ├── Strategy │ ├── Copy_All.php │ ├── Collect_Term_Ids.php │ └── Collect_Post_Ids.php │ ├── Entity │ ├── Translatable_Entity_Interface.php │ ├── Term.php │ └── Media.php │ ├── load.php │ ├── Labels │ ├── Taxonomy.php │ └── Post_Type.php │ ├── README.md │ └── js │ └── index.js ├── services ├── exporter │ ├── export-term-metas.php │ ├── export-post-metas.php │ ├── export-data-from-strings.php │ └── export-container.php ├── metabox-button │ ├── css │ │ └── metabox-button.css │ ├── metabox-user-button.php │ ├── js │ │ └── metabox-button.js │ └── toggle-user-meta.php ├── translation │ ├── translation-walker-interface.php │ ├── translation-post-metas.php │ ├── translation-term-metas.php │ ├── translation-object-model-trait.php │ ├── translation-walker-factory.php │ ├── translation-data-model-interface.php │ └── translation-content.php └── manage-user-capabilities.php ├── include ├── Options │ ├── Registry.php │ └── Business │ │ ├── Machine_Translation_Enabled.php │ │ ├── Media.php │ │ └── Machine_Translation_Services.php ├── functions.php └── upgrade.php ├── uninstall.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | *.log -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [], 3 | "dev": true, 4 | "dev-package-names": [] 5 | } 6 | -------------------------------------------------------------------------------- /js/build/media.min.js: -------------------------------------------------------------------------------- 1 | jQuery((function(a){a.ajaxPrefilter((function(t,d,f){"string"==typeof t.data&&-1!==t.data.indexOf("action=find_posts")&&(t.data="pll_post_id="+a("#affected").val()+"&"+t.data)}))})); -------------------------------------------------------------------------------- /modules/duplicate/uninstall.php: -------------------------------------------------------------------------------- 1 | {const r=t.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(e).find((t=>r===t))?l(t):t};var __WEBPACK_DEFAULT_EXPORT__=null; -------------------------------------------------------------------------------- /vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | model->has_languages() ) { 11 | $polylang->active_languages = new PLL_Active_Languages( $polylang ); 12 | } 13 | -------------------------------------------------------------------------------- /modules/rest/load.php: -------------------------------------------------------------------------------- 1 | rest_api = new PLL_REST_API( $polylang ); 14 | } 15 | ); 16 | -------------------------------------------------------------------------------- /modules/locale-fallback/load.php: -------------------------------------------------------------------------------- 1 | locale_fallback = new PLL_Locale_Fallback(); 11 | add_action( 'pll_init', array( $polylang->locale_fallback, 'init' ) ); 12 | -------------------------------------------------------------------------------- /css/build/metabox-button.min.css: -------------------------------------------------------------------------------- 1 | .pll-button{background:none;border:none;cursor:pointer;font-size:20px;height:20px;padding:0}.pll-button:not(.wp-ui-text-highlight){color:#ddd}.pll-button svg{fill:currentColor}.pll-before-post-translations-button{float:right;margin:13px 7px}.rtl .pll-before-post-translations-button{float:left} -------------------------------------------------------------------------------- /modules/sync/load.php: -------------------------------------------------------------------------------- 1 | model->has_languages() ) { 11 | $polylang->sync_content = new PLL_Sync_Content( $polylang ); 12 | $polylang->navigation = new PLL_Sync_Navigation( $polylang ); 13 | } 14 | -------------------------------------------------------------------------------- /modules/Site_Health/load.php: -------------------------------------------------------------------------------- 1 | model->has_languages() ) { 13 | $polylang->site_health_pro = new Info(); 14 | } 15 | -------------------------------------------------------------------------------- /integrations/beaver-builder/load.php: -------------------------------------------------------------------------------- 1 | flbuilder = new PLL_FLBuilder(); 15 | } 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /integrations/cptui/load.php: -------------------------------------------------------------------------------- 1 | cptui = new PLL_CPTUI(), 'init' ) ); 15 | } 16 | }, 17 | 0 18 | ); 19 | -------------------------------------------------------------------------------- /integrations/divi/load.php: -------------------------------------------------------------------------------- 1 | divi_builder = new PLL_Divi_Builder(); 15 | } 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /modules/wizard/load.php: -------------------------------------------------------------------------------- 1 | wizard_pro = new PLL_Wizard_Pro( $polylang ); 15 | }, 16 | 30 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /integrations/events-calendar/load.php: -------------------------------------------------------------------------------- 1 | tec = new PLL_TEC(), 'init' ) ); 15 | } 16 | }, 17 | 0 18 | ); 19 | -------------------------------------------------------------------------------- /modules/bulk-translate/load.php: -------------------------------------------------------------------------------- 1 | model->has_languages() ) { 11 | $polylang->bulk_translate = new PLL_Bulk_Translate( $polylang->model ); 12 | add_action( 'current_screen', array( $polylang->bulk_translate, 'init' ) ); 13 | } 14 | -------------------------------------------------------------------------------- /js/build/user.min.js: -------------------------------------------------------------------------------- 1 | jQuery((function(e){var n=e("#description").parent(),i=e("#description").clone(),t=n.children(".description").clone();n.children().remove(),e(".biography").each((function(){lang=e(this).attr("name").split("___"),desc=i.clone(),desc.attr("name","description_"+lang[0]),desc.attr("id","description_"+lang[0]),desc.html(e(this).val()),n.append(e("
").text(lang[1])),n.append(desc)})),n.append("21 |
` tags.
7 | * @type string $slug Slug of the machine translation service.
8 | * @type string $type Optional. Possible values are `success`, `warning`, `error`, and `info`. Default is `error`.
9 | * }
10 | */
11 |
12 | defined( 'ABSPATH' ) || exit;
13 |
14 | $tags = array(
15 | 'br' => array(),
16 | 'code' => array(),
17 | );
18 |
19 | $atts['type'] = ! empty( $atts['type'] ) && in_array( $atts['type'], array( 'success', 'warning', 'info' ), true ) ? $atts['type'] : 'error';
20 | ?>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/modules/import-export/export/view-export-file-format.php:
--------------------------------------------------------------------------------
1 |
16 |
30 |
--------------------------------------------------------------------------------
/modules/media/media-bulk-option.php:
--------------------------------------------------------------------------------
1 | base && current_user_can( 'upload_files' );
22 | }
23 |
24 |
25 | /**
26 | * Duplicates a media object
27 | *
28 | * @since 2.7
29 | *
30 | * @param int $object_id The media id.
31 | * @param string $lang A language locale.
32 | * @return void
33 | */
34 | public function translate( $object_id, $lang ) {
35 | $this->model->post->create_media_translation( $object_id, $lang );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/css/build/bulk-translate.min.css:
--------------------------------------------------------------------------------
1 | .bulk-translate-save .button{margin-right:20px}#wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper{display:flex}#wpbody-content #pll-translate fieldset{flex-basis:fit-content;margin-right:10%}#pll-translate .pll-translation-flag{margin:auto 10px auto 7px}.rtl #pll-translate .pll-translation-flag{margin:auto 7px auto 10px}#pll-translate .title{display:block;line-height:2.5}#pll-translate label{align-items:center;display:flex}#pll-translate label span.description{line-height:normal}#pll-translate label[for=pll-select-format]{padding-left:18px}#pll-translate #pll-select-format{margin-left:.5rem}@supports(selector(:has(*))){#pll-translate label[for=pll-select-format]{display:none}#pll-translate label:has([name=translate][value=pll_export_post]:checked)~[for=pll-select-format]{display:flex}}@media screen and (max-width:782px){#wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper{flex-direction:column}}
--------------------------------------------------------------------------------
/modules/media/load.php:
--------------------------------------------------------------------------------
1 | model->has_languages() ) {
11 | add_filter(
12 | 'pll_settings_modules',
13 | function ( $modules ) {
14 | $k = array_search( 'PLL_Settings_Media', $modules );
15 | if ( $k ) {
16 | $modules[ $k ] = 'PLL_Settings_Advanced_Media';
17 | }
18 | return $modules;
19 | },
20 | 0
21 | );
22 |
23 | add_action(
24 | 'pll_init',
25 | function ( $polylang ) {
26 | if ( $polylang->options['media_support'] ) {
27 | if ( $polylang instanceof PLL_Admin ) {
28 | require_once POLYLANG_PRO_DIR . '/modules/bulk-translate/load.php';
29 | }
30 |
31 | if ( $polylang instanceof PLL_Admin || $polylang instanceof PLL_REST_Request ) {
32 | $polylang->advanced_media = new PLL_Admin_Advanced_Media( $polylang );
33 | }
34 | }
35 | }
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/include/Options/Business/Machine_Translation_Enabled.php:
--------------------------------------------------------------------------------
1 | 'libxml',
34 | 'required' => true,
35 | );
36 | $modules['zip'] = array(
37 | 'class' => 'ZipArchive',
38 | 'required' => true,
39 | );
40 | return $modules;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/modules/translate-slugs/load.php:
--------------------------------------------------------------------------------
1 | model->has_languages() ) {
11 | add_filter(
12 | 'pll_settings_modules',
13 | function ( $modules ) {
14 | $k = array_search( 'PLL_Settings_Preview_Translate_Slugs', $modules );
15 | if ( $k ) {
16 | $modules[ $k ] = 'PLL_Settings_Translate_Slugs';
17 | }
18 | return $modules;
19 | },
20 | 20 // After Polylang.
21 | );
22 |
23 | if ( get_option( 'permalink_structure' ) ) {
24 | $slugs_model = new PLL_Translate_Slugs_Model( $polylang );
25 |
26 | if ( $polylang instanceof PLL_Frontend ) {
27 | $polylang->translate_slugs = new PLL_Frontend_Translate_Slugs( $slugs_model, $polylang->curlang );
28 | } else {
29 | $curlang = isset( $polylang->curlang ) ? $polylang->curlang : null;
30 | $polylang->translate_slugs = new PLL_Translate_Slugs( $slugs_model, $curlang );
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/services/metabox-button/metabox-user-button.php:
--------------------------------------------------------------------------------
1 | user_meta->is_active();
26 | }
27 |
28 | /**
29 | * Saves the button state.
30 | *
31 | * @since 3.6
32 | *
33 | * @param string $post_type Current post type.
34 | * @param bool $active New requested button state.
35 | * @return bool Whether the new button state is accepted or not.
36 | */
37 | protected function toggle_option( $post_type, $active ) {
38 | return $this->user_meta->toggle_option( $post_type, $active );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/modules/duplicate/duplicate.php:
--------------------------------------------------------------------------------
1 | user_meta = new PLL_Toggle_User_Meta( PLL_Duplicate_Action::META_NAME );
29 |
30 | $args = array(
31 | 'position' => 'before_post_translations',
32 | 'activate' => __( 'Activate content duplication', 'polylang-pro' ),
33 | 'deactivate' => __( 'Deactivate content duplication', 'polylang-pro' ),
34 | 'class' => 'dashicons-before dashicons-admin-page',
35 | );
36 |
37 | parent::__construct( 'pll-duplicate', $args );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/integrations/beaver-builder/flbuilder.php:
--------------------------------------------------------------------------------
1 | 'none' ) );
21 | }
22 |
23 | /**
24 | * Returns the module description.
25 | *
26 | * @since 3.1
27 | *
28 | * @return string
29 | */
30 | protected function get_description() {
31 | return parent::get_description() . ' ' . __( 'The module is automatically deactivated when using plain permalinks.', 'polylang-pro' );
32 | }
33 |
34 | /**
35 | * Tells if the module is active.
36 | *
37 | * @since 1.9
38 | *
39 | * @return bool
40 | */
41 | public function is_active() {
42 | return get_option( 'permalink_structure' );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/integrations/acf/Strategy/Collect_Term_Ids.php:
--------------------------------------------------------------------------------
1 | model = &$polylang->model;
39 | $this->options = &$polylang->options;
40 | }
41 |
42 | /**
43 | * Returns the list of the slugs of enabled languages.
44 | *
45 | * @since 1.0
46 | *
47 | * @return string[]
48 | */
49 | protected function get_languages_slugs() {
50 | return $this->model->get_languages_list( array( 'fields' => 'slug' ) );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/modules/rest/rest-comment.php:
--------------------------------------------------------------------------------
1 | array() ) );
22 |
23 | $this->type = 'comment';
24 |
25 | add_action( 'parse_comment_query', array( $this, 'parse_comment_query' ), 5 );
26 | }
27 |
28 | /**
29 | * Filters the query per language according to the 'lang' parameter.
30 | *
31 | * @since 2.6.9
32 | *
33 | * @param WP_Comment_Query $query Comment query.
34 | * @return void
35 | */
36 | public function parse_comment_query( $query ) {
37 | if ( isset( $this->request['lang'] ) && in_array( $this->request['lang'], $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ) {
38 | $query->query_vars['lang'] = $this->request['lang'];
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/vendor/composer/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) Nils Adermann, Jordi Boggiano
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is furnished
9 | to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/integrations/acf/Strategy/Collect_Post_Ids.php:
--------------------------------------------------------------------------------
1 | options['media_support'] && is_numeric( $value ) ) {
31 | return $value;
32 | }
33 | break;
34 | case 'gallery':
35 | if ( PLL()->options['media_support'] && is_array( $value ) ) {
36 | return $value;
37 | }
38 | break;
39 | }
40 |
41 | return array();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/modules/import-export/file-format/file-format.php:
--------------------------------------------------------------------------------
1 |
51 | */
52 | abstract public function get_export_class( $version = '' ): string;
53 | }
54 |
--------------------------------------------------------------------------------
/modules/import-export/export/export-file.php:
--------------------------------------------------------------------------------
1 | get_source_language()->get_locale( 'display' );
22 | $target_language = $this->get_target_language()->get_locale( 'display' );
23 | $datenow = gmdate( 'Y-m-d_G-i-s' );
24 | $extension = $this->get_extension();
25 |
26 | return "{$source_language}_{$target_language}_{$datenow}.{$extension}";
27 | }
28 |
29 | /**
30 | * Returns exported data.
31 | *
32 | * @since 3.6
33 | *
34 | * @return string
35 | */
36 | abstract public function get(): string;
37 |
38 | /**
39 | * Returns the current file extension.
40 | *
41 | * @since 3.1
42 | *
43 | * @return string The file extension.
44 | */
45 | abstract protected function get_extension(): string;
46 | }
47 |
--------------------------------------------------------------------------------
/vendor/composer/autoload_real.php:
--------------------------------------------------------------------------------
1 | register(true);
33 |
34 | return $loader;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/css/build/translations-dashboard.min.css:
--------------------------------------------------------------------------------
1 | .languages_page_mlang_strings .metabox-holder>div{display:flex;flex-wrap:wrap}.languages_page_mlang_strings .metabox-holder>div>div{display:flex;flex-basis:0;flex-direction:column;flex-grow:1}.languages_page_mlang_strings .metabox-holder>div>div:not(:first-child){margin-left:1rem}.languages_page_mlang_strings .metabox-holder>div>div.closed{background:none;border:0}.languages_page_mlang_strings .metabox-holder>div>div.closed .postbox-header{background:#fff;border:1px solid #ccd0d4}#pll-export-strings-box.postbox .submit,#pll-import-translations-box.postbox .submit,#pll-machine-strings-translations.postbox .submit{float:none;padding:0}.postbox .inside{margin:0}#export-string-translation .pll-translation-flag,#pll-machine-strings-translations .pll-translation-flag{margin:auto 10px auto 7px}#export-string-translation label,#export-string-translation label[for=pll-select-format] span,#import-translation label,#pll-machine-strings-translations label,.pll-legend{display:block;margin:.35em 0 .5em}.pll-legend{color:#1d2327;font-weight:400;padding:2px 0;text-shadow:none}@media screen and (max-width:1024px){.languages_page_mlang_strings .metabox-holder>div{flex-direction:column}.languages_page_mlang_strings .metabox-holder>div>div:not(:first-child){margin-left:0}}
--------------------------------------------------------------------------------
/modules/Machine_Translation/Clients/Client_Interface.php:
--------------------------------------------------------------------------------
1 | 'text/x-po' );
23 |
24 | /**
25 | * Po format is always supported.
26 | *
27 | * @since 3.1
28 | *
29 | * @return true
30 | */
31 | public function is_supported() {
32 | return true;
33 | }
34 |
35 | /**
36 | * Returns the associated import class.
37 | *
38 | * @since 3.1
39 | *
40 | * @return PLL_PO_Import
41 | */
42 | public function get_import() {
43 | return new PLL_PO_Import();
44 | }
45 |
46 | /**
47 | * Returns the associated export class.
48 | *
49 | * @since 3.6
50 | *
51 | * @param string $version Optional file format version. Not used for PO.
52 | * @return string
53 | *
54 | * @phpstan-return class-string
55 | */
56 | public function get_export_class( $version = '' ): string { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
57 | return PLL_PO_Export::class;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/js/build/user.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds one biography input field per language in the user profile.
3 | *
4 | * @package Polylang
5 | */
6 |
7 | jQuery(
8 | function ( $ ) {
9 | // biography
10 | // FIXME there is probably a more efficient way to do this
11 | var td = $( '#description' ).parent();
12 | var d = $( '#description' ).clone();
13 | var span = td.children( '.description' ).clone();
14 | td.children().remove();
15 |
16 | $( '.biography' ).each(
17 | function () {
18 | lang = $( this ).attr( 'name' ).split( '___' );
19 | desc = d.clone();
20 | desc.attr( 'name', 'description_' + lang[0] );
21 | desc.attr( 'id', 'description_' + lang[0] );
22 | // Whitelist because description and lang value is already escaped by the side of PHP
23 | desc.html( $( this ).val() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
24 | td.append( $( '' ).text( lang[1] ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
25 | td.append( desc ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
26 | }
27 | );
28 |
29 | td.append( '
' );
30 | // Whitelist because description come from html code generated by WordPress
31 | td.append( span ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
32 | }
33 | );
34 |
35 |
--------------------------------------------------------------------------------
/css/build/bulk-translate.css:
--------------------------------------------------------------------------------
1 | .bulk-translate-save .button {
2 | margin-right: 20px;
3 | }
4 |
5 | #wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper {
6 | display: flex;
7 | }
8 |
9 | #wpbody-content #pll-translate fieldset {
10 | flex-basis: fit-content;
11 | margin-right: 10%;
12 | }
13 |
14 | #pll-translate .pll-translation-flag {
15 | margin: auto 10px auto 7px;
16 | }
17 |
18 | .rtl #pll-translate .pll-translation-flag {
19 | margin: auto 7px auto 10px;
20 | }
21 |
22 | #pll-translate .title {
23 | display: block;
24 | line-height: 2.5;
25 | }
26 |
27 | #pll-translate label {
28 | display: flex;
29 | align-items: center;
30 | }
31 |
32 | #pll-translate label span.description{
33 | line-height: normal;
34 | }
35 |
36 | #pll-translate label[for="pll-select-format"] {
37 | padding-left: 18px;
38 | }
39 |
40 | #pll-translate #pll-select-format {
41 | margin-left: 0.5rem;
42 | }
43 |
44 | @supports(selector(:has(*))) {
45 | #pll-translate label[for="pll-select-format"] {
46 | display: none;
47 | }
48 | #pll-translate label:has([name="translate"][value="pll_export_post"]:checked) ~ [for="pll-select-format"] {
49 | display: flex;
50 | }
51 | }
52 |
53 | @media screen and ( max-width: 782px ) {
54 | #wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper {
55 | flex-direction: column;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/integrations/divi/divi-builder.php:
--------------------------------------------------------------------------------
1 | '),t("#pll-translate .inline-edit-wrapper").attr("tabindex","-1").focus(),t("html, body").animate({scrollTop:0},"fast")):t("#pll-translate").find(".cancel").trigger("click")})),t("#pll-translate").on("click",".cancel",(function(){t("#pll-translate").siblings(".hidden").remove(),t("#pll-bulk-translate").append(t("#pll-translate")),t("#"+e.whichBulkButtonId).trigger("focus")})),t("#pll-translate").on("keydown",(function(e){"Enter"!==e.key||t(e.target).hasClass("cancel")||(e.preventDefault(),t(this).find("input[type=submit]").trigger("click")),"Escape"===e.key&&(e.preventDefault(),t(this).find(".cancel").trigger("click"))})),t("#posts-filter").on("submit",(function(){t(".settings-error").remove(),setTimeout((function(){t("input[type=checkbox]:checked").attr("checked",!1),t("#pll-translate").find(".cancel").trigger("click")}),500)}))}));
--------------------------------------------------------------------------------
/modules/Machine_Translation/Views/inner-notices-row.php:
--------------------------------------------------------------------------------
1 | ` and `` tags.
7 | * @type string $type Optional type of notice. Possible values are `success`, `warning`, `error`, and `info`. Default is `error`.
8 | * @type string $name Name of the machine translation service.
9 | * @type string[] $languages List of language names with their locale. Can contain `` tags.
10 | * Example array( 'Afrikaans (af)' ).
11 | * }
12 | */
13 |
14 | defined( 'ABSPATH' ) || exit;
15 |
16 | if ( ! empty( $atts['languages'] ) ) {
17 | $atts['type'] = 'warning';
18 | if ( 1 === count( $atts['languages'] ) ) {
19 | /* translators: %1$s is a machine translation service's name, %2$s is a language name (and its locale). */
20 | $atts['message'] = __( 'The following language is not available in %1$s: %2$s.', 'polylang-pro' );
21 | } else {
22 | /* translators: %1$s is a machine translation service's name, %2$s is a list of language names (and their locale). */
23 | $atts['message'] = __( 'The following languages are not available in %1$s: %2$s.', 'polylang-pro' );
24 | }
25 | $atts['message'] = sprintf( $atts['message'], $atts['name'], wp_sprintf_l( '%l', $atts['languages'] ) );
26 |
27 | include __DIR__ . '/inner-notice.php';
28 | }
29 |
--------------------------------------------------------------------------------
/js/build/confirmation-modal.min.js:
--------------------------------------------------------------------------------
1 | "use strict";var __webpack_require__={d:(e,a)=>{for(var t in a)__webpack_require__.o(a,t)&&!__webpack_require__.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},o:(e,a)=>Object.prototype.hasOwnProperty.call(e,a)},__webpack_exports__={};const languagesList=jQuery(".post_lang_choice"),initializeConfirmationModal=()=>{const{__:e}=wp.i18n,a=jQuery("",{id:"pll-dialog",style:"display:none;"}).text(e("Are you sure you want to change the language of the current content?","polylang"));languagesList.after(a);const t=new Promise(((t,l)=>{const n=e=>{switch(e){case"yes":languagesList.data("old-value",languagesList.children(":selected").first().val()),t();break;case"no":languagesList.val(languagesList.data("old-value")),l("Cancel")}a.dialog("close")},i={autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:e("Change language","polylang"),minWidth:600,maxWidth:"100%",open:function(e,a){jQuery("body").hasClass("rtl")&&jQuery(this).parent().css({right:jQuery(this).parent().css("left"),left:"auto"})},close:function(e,a){n("no")},buttons:[{text:e("OK","polylang"),click:function(e){n("yes")}},{text:e("Cancel","polylang"),click:function(e){n("no")}}]};jQuery.ui.version>="1.12.0"?Object.assign(i,{classes:{"ui-dialog":"pll-confirmation-modal"}}):Object.assign(i,{dialogClass:"pll-confirmation-modal"}),a.dialog(i)}));return{dialogContainer:a,dialogResult:t}},initializeLanguageOldValue=()=>{languagesList.attr("data-old-value",languagesList.children(":selected").first().val())};
--------------------------------------------------------------------------------
/js/build/metabox-button.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handle the response to a click on a Languages metabox button.
3 | *
4 | * @package Polylang-Pro
5 | */
6 |
7 | jQuery(
8 | function ( $ ) {
9 | $( '#ml_box' ).on(
10 | 'click',
11 | '.pll-button',
12 | function () {
13 | var value = $( this ).hasClass( 'wp-ui-text-highlight' );
14 | var id = $( this ).attr( 'id' );
15 | var post_id = $( '#htr_lang_' + id.replace( 'pll_sync_post[', '' ).replace( ']', '' ) ).val();
16 |
17 | if ( 'undefined' == typeof( post_id ) || 0 == post_id || value || confirm( pll_sync_post.confirm_text ) ) {
18 | var data = {
19 | action: 'toggle_' + id,
20 | value: value,
21 | post_type: $( '#post_type' ).val(),
22 | _pll_nonce: $( '#_pll_nonce' ).val()
23 | }
24 |
25 | $.post(
26 | ajaxurl,
27 | data,
28 | function ( response ) {
29 | // Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
30 | var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
31 | $.each(
32 | res.responses,
33 | function () {
34 | id = id.replace( '[', '\\[' ).replace( ']', '\\]' );
35 | $( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).text( this.data );
36 | $( 'input[name="' + id + '"]' ).val( ! data['value'] );
37 | }
38 | );
39 | }
40 | );
41 | }
42 | }
43 | );
44 | }
45 | );
46 |
47 |
--------------------------------------------------------------------------------
/services/metabox-button/js/metabox-button.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handle the response to a click on a Languages metabox button.
3 | *
4 | * @package Polylang-Pro
5 | */
6 |
7 | jQuery(
8 | function ( $ ) {
9 | $( '#ml_box' ).on(
10 | 'click',
11 | '.pll-button',
12 | function () {
13 | var value = $( this ).hasClass( 'wp-ui-text-highlight' );
14 | var id = $( this ).attr( 'id' );
15 | var post_id = $( '#htr_lang_' + id.replace( 'pll_sync_post[', '' ).replace( ']', '' ) ).val();
16 |
17 | if ( 'undefined' == typeof( post_id ) || 0 == post_id || value || confirm( pll_sync_post.confirm_text ) ) {
18 | var data = {
19 | action: 'toggle_' + id,
20 | value: value,
21 | post_type: $( '#post_type' ).val(),
22 | _pll_nonce: $( '#_pll_nonce' ).val()
23 | }
24 |
25 | $.post(
26 | ajaxurl,
27 | data,
28 | function ( response ) {
29 | // Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
30 | var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
31 | $.each(
32 | res.responses,
33 | function () {
34 | id = id.replace( '[', '\\[' ).replace( ']', '\\]' );
35 | $( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).text( this.data );
36 | $( 'input[name="' + id + '"]' ).val( ! data['value'] );
37 | }
38 | );
39 | }
40 | );
41 | }
42 | }
43 | );
44 | }
45 | );
46 |
--------------------------------------------------------------------------------
/integrations/acf/Entity/Term.php:
--------------------------------------------------------------------------------
1 | term_id;
27 | }
28 |
29 | /**
30 | * Transforms a term ID to the corresponding ACF post ID.
31 | *
32 | * @since 3.7
33 | *
34 | * @param int $id Term ID.
35 | * @return string ACF post ID.
36 | */
37 | protected static function acf_id( $id ) {
38 | return 'term_' . $id;
39 | }
40 |
41 | /**
42 | * Returns source object ID passed in the main request if exists.
43 | *
44 | * @since 3.7
45 | *
46 | * @return int
47 | */
48 | protected function get_from_id_in_request(): int {
49 | if ( isset( $_GET['taxonomy'], $_GET['from_tag'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
50 | return (int) $_GET['from_tag']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
51 | }
52 |
53 | return 0;
54 | }
55 |
56 | /**
57 | * Returns current object type.
58 | *
59 | * @since 3.7
60 | *
61 | * @return string
62 | * @phpstan-return non-falsy-string
63 | */
64 | public function get_type(): string {
65 | return 'term';
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/css/build/dialog.min.css:
--------------------------------------------------------------------------------
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}
--------------------------------------------------------------------------------
/modules/frontend-filter-template/filter-templates.php:
--------------------------------------------------------------------------------
1 | >
24 | */
25 | private $template_types = array(
26 | 'category' => PLL_Filter_Template_Core_Taxonomy::class,
27 | 'tag' => PLL_Filter_Template_Core_Taxonomy::class,
28 | 'taxonomy' => PLL_Filter_Template_Custom_Taxonomy::class,
29 | 'page' => PLL_Filter_Template_Page::class,
30 | 'single' => PLL_Filter_Template_Single::class,
31 | );
32 |
33 | /**
34 | * Constructor.
35 | *
36 | * @since 3.7
37 | *
38 | * @param PLL_Frontend $polylang Main Polylang object.
39 | */
40 | public function __construct( PLL_Frontend $polylang ) {
41 | $this->model = $polylang->model;
42 | }
43 |
44 | /**
45 | * Hooks to the template hierarchy filters with the corresponding objects.
46 | *
47 | * @since 3.7
48 | *
49 | * @return self
50 | */
51 | public function init(): self {
52 | foreach ( $this->template_types as $type => $class ) {
53 | $template_filter = new $class( $this->model );
54 | add_filter( "{$type}_template_hierarchy", array( $template_filter, 'filter' ) );
55 | }
56 |
57 | return $this;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/modules/import-export/import/view-tab-import-translations.php:
--------------------------------------------------------------------------------
1 |
15 |
16 |
36 |
37 |
--------------------------------------------------------------------------------
/js/build/widgets.min.js:
--------------------------------------------------------------------------------
1 | jQuery((function(e){var t,i,n,o=void 0!==wp.blockEditor;function l(t){if(n){t=e(t);var i=o?t.prev("h3"):e(".widget-top .widget-title h3",t),l=e(".pll-lang-choice option:selected",t).val(),d=l&&n.hasOwnProperty(l)?n[l]:null;if(d){d+=" ";var s=e(".pll-lang",i);s.length?s.html(d):(flag=e("").addClass("pll-lang").html(d),i.prepend(flag))}else e(".pll-lang",i).remove()}}if("undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(n=pll_widgets.flags),o)i=".widget",(t=e(".edit-widgets-main-block-list")).on("click",".wp-block-legacy-widget",(function(){l(e(this).find(".widget"))}));else{if(void 0!==wp.customize){function d(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),l(e.container.find(".widget")))}t=e("#customize-controls"),i=".customize-control .widget",wp.customize.control.each(d),wp.customize.control.bind("add",d)}else t=e("#widgets-right"),i=".widget";e(i,t).each((function(){l(this)}))}t.on("change",".pll-lang-choice",(function(){l(e(this).parents(".widget"))})),e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll-dropdown",(function(){var t,i=e(this).parent().parent().parent().children(".widget-id").attr("value");t=e(".no-dropdown-"+i),1!=e(this).prop("checked")?t.show():t.hide()}));var s=["-show_flags","-show_names"];e.each(s,(function(t,i){e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll"+i,(function(){var i=e(this).parent().parent().parent().children(".widget-id").attr("value");1!=e(this).prop("checked")&&e("#widget-"+i+s[1-t]).prop("checked",!0)}))}))}));
--------------------------------------------------------------------------------
/integrations/acf/Labels/Taxonomy.php:
--------------------------------------------------------------------------------
1 |
53 | */
54 | protected function get_type_objects(): array {
55 | return $GLOBALS['wp_taxonomies'];
56 | }
57 |
58 | /**
59 | * Returns the label of the type.
60 | *
61 | * @since 3.7
62 | *
63 | * @return string
64 | *
65 | * @phpstan-return non-empty-string
66 | */
67 | protected function get_type_label(): string {
68 | return 'Taxonomy';
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/js/build/admin.js:
--------------------------------------------------------------------------------
1 | /******/ "use strict";
2 |
3 | ;// ./vendor/wpsyntex/polylang/js/src/lib/ajax-filter/index.js
4 | /**
5 | * @package Polylang
6 | */
7 |
8 | /**
9 | * Adds data to all ajax requests made with jQuery.
10 | *
11 | * @since 3.7
12 | *
13 | * @param {Object} data The data to add.
14 | * @returns {void}
15 | */
16 | function ajaxFilter( data ) {
17 | if ( 'undefined' === typeof jQuery || ! data ) {
18 | return;
19 | }
20 |
21 | const dataStr = jQuery.param( data );
22 |
23 | jQuery.ajaxPrefilter( function ( options ) {
24 | if ( -1 === options.url.indexOf( ajaxurl ) && -1 === ajaxurl.indexOf( options.url ) ) {
25 | return;
26 | }
27 |
28 | if (
29 | 'undefined' === typeof options.data ||
30 | null === options.data ||
31 | 'string' === typeof options.data && '' === options.data.trim()
32 | ) {
33 | // An empty string or null/undefined.
34 | options.data = dataStr;
35 | } else if ( 'string' === typeof options.data ) {
36 | // A non-empty string: can be a JSON string or a query string.
37 | try {
38 | options.data = JSON.stringify( Object.assign( JSON.parse( options.data ), data ) );
39 | } catch ( exception ) {
40 | // A non-empty non-JSON string is considered a query string.
41 | options.data = `${ options.data }&${ dataStr }`;
42 | }
43 | } else if ( jQuery.isPlainObject( options.data ) ) {
44 | // An object.
45 | options.data = Object.assign( options.data, data );
46 | }
47 | } );
48 | }
49 |
50 | ;// ./vendor/wpsyntex/polylang/js/src/admin.js
51 | /**
52 | * @package Polylang
53 | */
54 |
55 |
56 |
57 | ajaxFilter( pll_admin?.ajax_filter );
58 |
59 |
--------------------------------------------------------------------------------
/integrations/acf/Labels/Post_Type.php:
--------------------------------------------------------------------------------
1 |
53 | */
54 | protected function get_type_objects(): array {
55 | return $GLOBALS['wp_post_types'];
56 | }
57 |
58 | /**
59 | * Returns the label of the type.
60 | *
61 | * @since 3.7
62 | *
63 | * @return string
64 | *
65 | * @phpstan-return non-empty-string
66 | */
67 | protected function get_type_label(): string {
68 | return 'Post Type';
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/modules/full-site-editing/load.php:
--------------------------------------------------------------------------------
1 | model->has_languages() ) {
9 | return;
10 | }
11 |
12 | add_action(
13 | 'pll_init',
14 | function ( $polylang ) {
15 | $pll_fse_sub_modules = array(
16 | PLL_FSE_Default_Language_Change::class,
17 | PLL_FSE_Language::class,
18 | PLL_FSE_Language_Slug_Change::class,
19 | PLL_FSE_Filter_Block_Types::class,
20 | PLL_FSE_Post_Types::class,
21 | PLL_FSE_Query_Filters::class,
22 | PLL_FSE_REST_Duplicate_Template::class,
23 | PLL_FSE_REST_Enforce_Default_Template::class,
24 | PLL_FSE_Post_Deletion::class,
25 | PLL_FSE_Template_Model::class,
26 | PLL_FSE_Template_Slug_Sync::class,
27 | );
28 |
29 | foreach ( $pll_fse_sub_modules as $pll_fse_class ) {
30 | $polylang->{$pll_fse_class::get_name()} = ( new $pll_fse_class( $polylang ) )->init();
31 | }
32 |
33 | if ( $polylang->model instanceof PLL_Admin_Model ) {
34 | $polylang->{PLL_FSE_Recreate_Language::get_name()} = ( new PLL_FSE_Recreate_Language( $polylang ) )->init();
35 | }
36 |
37 | // PLL_FSE_REST_Template is required only in a REST context.
38 | add_action(
39 | 'rest_api_init',
40 | function () use ( $polylang ) {
41 | $polylang->rest_api->template = ( new PLL_FSE_REST_Template( $polylang->rest_api, PLL_FSE_Tools::get_template_post_types() ) )->init();
42 | },
43 | 20 // Load the FSE modules after the PLL_REST_API.
44 | );
45 |
46 | unset( $pll_fse_sub_modules, $pll_fse_class );
47 | },
48 | 20 // Load the FSE modules after the PLL_REST_API.
49 | );
50 |
--------------------------------------------------------------------------------
/css/build/machine-translation-settings.min.css:
--------------------------------------------------------------------------------
1 | .pll-settings .pll-inner-notice{background:#fff;border:1px solid #c3c4c7;border-left-width:4px;box-shadow:0 1px 1px rgba(0,0,0,.04);margin:5px 0 15px;padding:1px 12px}.form-table .pll-inner-notice{margin-bottom:5px}.pll-settings .notice-success{border-left-color:#00a32a}.pll-settings .notice-warning{border-left-color:#dba617}.pll-settings .notice-error{border-left-color:#d63638}.pll-settings .pll-inner-notice p{margin:.5em 0;padding:2px}.pll-settings .notice-error .pll-origin-message,.pll-settings .notice-success .pll-origin-message,.pll-settings .notice-warning .pll-origin-message,.pll-settings .pll-message:not(.pll-origin-message){display:none}.pll-settings .notice-error .pll-error-message.pll-message-shown,.pll-settings .notice-success .pll-success-message,.pll-settings .notice-warning .pll-warning-message.pll-message-shown{display:block}.pll-progress-bar-wrapper .spinner,.pll-settings [disabled]+.spinner{visibility:visible}.pll-success-message .pll-icon{color:#125b91}.pll-error-message .pll-icon,.pll-warning-message .pll-icon{color:#911e1f}.pll-icon{font-size:1.8em;margin-left:1px;margin-right:3px;vertical-align:-2px}.pll-progress-bar-wrapper{border:1px solid #404648;border-radius:4px;color:#1772b5;font-size:2em;height:2em;line-height:2em;max-width:500px;overflow:hidden;position:relative;text-align:left;text-indent:1em;vertical-align:middle;white-space:nowrap}.pll-progress-bar-wrapper div{background-color:#1772b5;color:#e8e6e3;height:100%;left:0;overflow:hidden;position:absolute;top:0}.pll-settings [type=password]+.button{margin-left:20px;margin-right:0}.pll-settings [type=password]+.button+.spinner{float:none}.pll-progress-bar-wrapper .spinner{float:none;margin:0}
--------------------------------------------------------------------------------
/modules/Machine_Translation/Settings/Settings_Interface.php:
--------------------------------------------------------------------------------
1 | $key, 'meta_compare' => 'EXISTS' ) );
47 |
48 | if ( ! empty( $users ) ) {
49 | $user = reset( $users );
50 | $data = get_user_meta( $user->ID, $key, true );
51 | delete_user_meta( $user->ID, wp_slash( $key ) ); // No replay.
52 | $data['user_id'] = $user->ID;
53 | return $data;
54 | }
55 |
56 | $data = get_option( $key, array() );
57 |
58 | if ( ! empty( $data ) ) {
59 | delete_option( $key ); // No replay.
60 | return $data;
61 | }
62 |
63 | wp_die( esc_html__( 'An error has occurred.', 'polylang-pro' ) );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/modules/import-export/export/strings-form-trait.php:
--------------------------------------------------------------------------------
1 | |WP_Error
22 | */
23 | private function get_sanitized_languages( array $languages ) {
24 | if ( empty( $languages ) ) {
25 | return new WP_Error( 'pll_export_no_target_languages', __( 'Error: Please select a target language.', 'polylang-pro' ) );
26 | }
27 |
28 | $languages = array_filter( $languages, 'is_string' );
29 | $languages = array_map( 'sanitize_key', $languages );
30 | $languages = array_map( array( $this->model, 'get_language' ), $languages );
31 | $languages = array_filter( $languages );
32 |
33 | if ( empty( $languages ) ) {
34 | return new WP_Error( 'invalid-target-languages', __( 'Error: invalid target languages.', 'polylang-pro' ) );
35 | }
36 |
37 | return $languages;
38 | }
39 |
40 | /**
41 | * Registers settings errors to be displayed to the user.
42 | *
43 | * @since 3.6
44 | * @since 3.7 Moved from PLL_Export_Strings_Action.
45 | *
46 | * @param WP_Error $error An error object.
47 | * @return never
48 | */
49 | private function display_errors( WP_Error $error ) {
50 | pll_add_notice( $error );
51 |
52 | PLL_Settings::redirect();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/js/build/integrations/acf.min.js:
--------------------------------------------------------------------------------
1 | (()=>{var e={631:e=>{e.exports=function(){return this.wp.apiFetch}()}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,o),a.exports}o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};(()=>{"use strict";o.r(n);var e=o(631),t=o.n(e);document.addEventListener("onPostLangChoice",(e=>{const o=[],n=document.querySelectorAll(".acf-field-relationship");n.forEach((function(e){const t=e.getAttribute("data-key");o.push(t)}));document.querySelectorAll(".acf-field-post-object").forEach((function(e){const t=e.getAttribute("data-key");o.push(t)}));if(document.querySelectorAll(".acf-field-taxonomy").forEach((function(e){const t=e.getAttribute("data-key");o.push(t)})),0{e.forEach((function(e){const t=document.querySelector(".acf-"+e.field_key);t.outerHTML=e.field_data,acf.do_action("ready_field/type="+t.getAttribute("data-type"),t)})),0meta_type = 'post';
19 | $this->import_export_meta_type = PLL_Import_Export::POST_META;
20 | }
21 |
22 | /**
23 | * Get the meta names to export.
24 | *
25 | * @since 3.3
26 | *
27 | * @param int $from ID of the source object.
28 | * @param int $to ID of the target object.
29 | * @return string[] List of custom fields names.
30 | */
31 | protected function get_meta_names_to_export( int $from, int $to ): array {
32 | $default_metas_to_export = array(
33 | '_wp_attachment_image_alt' => 1,
34 | 'footnotes' => array(
35 | '*' => array(
36 | 'content' => 1,
37 | ),
38 | ),
39 | );
40 |
41 | /** This filter is documented in modules/import-export/export/export-metas.php */
42 | return (array) apply_filters( "pll_{$this->meta_type}_metas_to_export", $default_metas_to_export, $from, $to );
43 | }
44 |
45 | /**
46 | * Returns the meta formats.
47 | *
48 | * @since 3.6
49 | *
50 | * @param int $from ID of the source object.
51 | * @param int $to ID of the target object.
52 | * @return array List of custom fields formats.
53 | */
54 | protected function get_meta_encodings( int $from, int $to ): array {
55 | $formats = array(
56 | 'footnotes' => 'json',
57 | );
58 |
59 | /** This filter is documented in modules/import-export/export/export-metas.php */
60 | return (array) apply_filters( "pll_{$this->meta_type}_meta_encodings", $formats, $from, $to );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/modules/import-export/import/import-file-interface.php:
--------------------------------------------------------------------------------
1 | div {
3 | display: flex;
4 | flex-wrap: wrap;
5 | }
6 | .languages_page_mlang_strings .metabox-holder > div > div {
7 | display: flex;
8 | flex-direction: column;
9 | flex-basis: 0;
10 | flex-grow: 1;
11 | }
12 | .languages_page_mlang_strings .metabox-holder > div > div:not(:first-child) {
13 | margin-left: 1rem;
14 | }
15 | .languages_page_mlang_strings .metabox-holder > div > div.closed {
16 | border:0;
17 | background: none;
18 | }
19 | .languages_page_mlang_strings .metabox-holder > div > div.closed .postbox-header{
20 | border: 1px solid #ccd0d4;
21 | background: #fff;
22 | }
23 |
24 | #pll-export-strings-box.postbox .submit, /* Override WordPress styles */
25 | #pll-import-translations-box.postbox .submit,
26 | #pll-machine-strings-translations.postbox .submit {
27 | float: none;
28 | padding: 0;
29 | }
30 | .postbox .inside {
31 | margin: 0;
32 | }
33 |
34 | #pll-machine-strings-translations .pll-translation-flag, #export-string-translation .pll-translation-flag {
35 | margin: auto 10px auto 7px;
36 | }
37 |
38 | #export-string-translation label,
39 | #export-string-translation label[for="pll-select-format"] span,
40 | #import-translation label,
41 | #pll-machine-strings-translations label {
42 | display: block;
43 | margin: 0.35em 0 0.5em;
44 | }
45 |
46 | .pll-legend {
47 | display: block;
48 | padding: 2px 0;
49 | color: #1d2327;
50 | font-weight: 400;
51 | text-shadow: none;
52 | margin: 0.35em 0 0.5em;
53 | }
54 |
55 | /* Narrow devices */
56 | @media screen and ( max-width: 1024px ) {
57 | .languages_page_mlang_strings .metabox-holder > div {
58 | flex-direction: column;
59 | }
60 | .languages_page_mlang_strings .metabox-holder > div > div:not(:first-child) {
61 | margin-left: 0;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/js/build/post.min.js:
--------------------------------------------------------------------------------
1 | jQuery((function(n){n.ajaxPrefilter((function(e,t,a){"string"==typeof e.data&&-1!==e.data.indexOf("action=ajax-tag-search")&&(lang=n(':input[name="inline_lang_choice"]').val())&&(e.data="lang="+lang+"&"+e.data)}))})),jQuery((function(n){const e=document.getElementById("the-list");if(!e)return;new MutationObserver((e=>{for(const i of e){const o=Array.from(i.addedNodes).filter((n=>n.nodeType===Node.ELEMENT_NODE))[0];if(00){const l=o.querySelector('select[name="inline_lang_choice"]'),r=document.querySelector("#lang_"+String(s)).innerHTML;l.value=r,t(r),a(r),l.addEventListener("change",(function(n){const e=n.target.value;t(e),a(e)}))}}function t(e){"undefined"!=typeof pll_term_languages&&n.each(pll_term_languages,(function(t,a){n.each(a,(function(a,i){n.each(i,(function(i){id="#"+a+"-"+pll_term_languages[t][a][i],e==t?n(id).show():n(id).hide()}))}))}))}function a(e){"undefined"!=typeof pll_page_languages&&n.each(pll_page_languages,(function(t,a){n.each(a,(function(a){v=n('#post_parent option[value="'+pll_page_languages[t][a]+'"]'),e==t?v.show():v.hide()}))}))}}})).observe(e,{childList:!0,subtree:!0})})),jQuery((function(n){n(document).ajaxSuccess((function(e,t,a){if("string"==typeof a.data){var i=wpAjax.unserialize(a.data);void 0!==i.action&&"inline-save"==i.action&&function(e){var t=new Array;n(".translation_"+e).each((function(){t.push(n(this).parent().parent().attr("id").substring(5))}));var a={action:"pll_update_post_rows",post_id:e,translations:t.join(","),post_type:n("input[name='post_type']").val(),screen:n("input[name='screen']").val(),_pll_nonce:n("input[name='_inline_edit']").val()};n.post(ajaxurl,a,(function(e){if(e){var t=wpAjax.parseAjaxResponse(e,"pll-ajax-response");n.each(t.responses,(function(){"row"==this.what&&n("#post-"+this.supplemental.post_id).replaceWith(this.data)}))}}))}(i.post_ID)}}))}));
--------------------------------------------------------------------------------
/modules/import-export/import/import-object-interface.php:
--------------------------------------------------------------------------------
1 | parse( $widget_data['settings'][ $widget_data['number'] ]['content'] );
34 | if ( is_array( $parser->output ) ) {
35 | foreach ( $parser->output as $output ) {
36 | if ( isset( $output['attrs'] ) ) {
37 | if ( array_key_exists( 'pll_lang', $output['attrs'] ) ) {
38 | $lang_to_be_displayed = $output['attrs']['pll_lang'];
39 |
40 | if ( ! empty( $this->curlang ) && $this->curlang->slug !== $lang_to_be_displayed ) {
41 | unset( $sidebars_widgets[ $sidebar ][ $key ] );
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 | return $sidebars_widgets;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/services/manage-user-capabilities.php:
--------------------------------------------------------------------------------
1 | model->has_languages() ) {
14 | // Ensure dependencies are loaded.
15 | require_once POLYLANG_PRO_DIR . '/modules/sync/load.php';
16 | require_once POLYLANG_PRO_DIR . '/modules/sync-post/load.php';
17 | require_once POLYLANG_DIR . '/modules/sync/load.php';
18 |
19 | $machine_translation_factory = new Machine_Translation\Factory( $polylang->model );
20 |
21 | if ( $machine_translation_factory->is_enabled() ) {
22 | $active_service = $machine_translation_factory->get_active_service();
23 |
24 | if ( $active_service && $polylang instanceof PLL_Admin ) {
25 | new PLL_Admin_Loader( $polylang, 'machine_translation', array( $active_service ) );
26 | $polylang->machine_translation_action = new Post_Action( $polylang, $active_service );
27 | } elseif ( $active_service && $polylang instanceof PLL_REST_Request ) {
28 | $polylang->machine_translation = new Button_REST( $polylang, $active_service );
29 | } elseif ( $active_service && $polylang instanceof PLL_Settings ) {
30 | $polylang->machine_translation = ( new Strings_Metabox( $polylang, $active_service ) )->init();
31 | }
32 | }
33 |
34 | if ( $polylang instanceof PLL_Settings ) {
35 | add_filter(
36 | 'pll_settings_modules',
37 | function ( $modules ) {
38 | $k = array_search( PLL_Settings_Preview_Machine_Translation::class, $modules );
39 | if ( $k ) {
40 | unset( $modules[ $k ] );
41 | $modules['machine_translation'] = Machine_Translation\Module_Settings::class;
42 | }
43 | return $modules;
44 | },
45 | 100
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/integrations/acf/Entity/Media.php:
--------------------------------------------------------------------------------
1 | model->get_language( $target_language );
29 | if ( empty( $target_language ) ) {
30 | return;
31 | }
32 |
33 | $this->maybe_reset_fields_store( $target_language );
34 |
35 | $this->apply_to_all_fields( new Copy(), $to_id, array( 'target_language' => $target_language ) );
36 | }
37 |
38 | /**
39 | * Transforms a post ID to the corresponding ACF post ID.
40 | *
41 | * @since 3.7
42 | *
43 | * @param int $id Post ID.
44 | * @return string ACF post ID.
45 | */
46 | protected static function acf_id( $id ): string {
47 | return 'attachment_' . $id;
48 | }
49 |
50 | /**
51 | * Does nothing for media. `self::translate_fields()` does the job instead.
52 | *
53 | * @since 3.7
54 | *
55 | * @param array $field Custom field definition.
56 | * @return array Custom field of the target object.
57 | */
58 | public function render_field( $field ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
59 |
60 | /*
61 | * Does nothing, media translations are created in two times.
62 | * 1. A request is made to create the media translation.
63 | * 2. A redirect is made toward the edit page of the media, where ACF loads the fields.
64 | */
65 | return $field;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/include/Options/Business/Media.php:
--------------------------------------------------------------------------------
1 | false );
40 | }
41 |
42 | /**
43 | * Returns the JSON schema part specific to this option.
44 | *
45 | * @since 3.7
46 | *
47 | * @return array Partial schema.
48 | *
49 | * @phpstan-return array{
50 | * type: 'object',
51 | * properties: array{
52 | * duplicate: array{
53 | * type: 'boolean',
54 | * required: true
55 | * }
56 | * },
57 | * additionalProperties: false
58 | * }
59 | */
60 | protected function get_data_structure(): array {
61 | return array(
62 | 'type' => 'object', // Correspond to associative array in PHP, @see{https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#primitive-types}.
63 | 'properties' => array(
64 | 'duplicate' => array(
65 | 'type' => 'boolean',
66 | 'required' => true,
67 | ),
68 | ),
69 | 'additionalProperties' => false,
70 | );
71 | }
72 |
73 | /**
74 | * Returns the description used in the JSON schema.
75 | *
76 | * @since 3.7
77 | *
78 | * @return string
79 | */
80 | protected function get_description(): string {
81 | return __( 'Automatically duplicate media in all languages when uploading a new file.', 'polylang-pro' );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/modules/Editors/Screens/Post.php:
--------------------------------------------------------------------------------
1 | posts = &$polylang->posts;
33 | }
34 |
35 |
36 | /**
37 | * Tells whether the given screen is the Post edtitor or not.
38 | *
39 | * @since 3.7
40 | *
41 | * @param WP_Screen $screen The current screen.
42 | * @return bool True if Post editor screen, false otherwise.
43 | */
44 | protected function screen_matches( WP_Screen $screen ): bool {
45 | return (
46 | 'post' === $screen->base
47 | && $this->model->post_types->is_translated( $screen->post_type )
48 | && method_exists( $screen, 'is_block_editor' )
49 | && $screen->is_block_editor()
50 | );
51 | }
52 |
53 | /**
54 | * Returns the language to use in the Post editor.
55 | *
56 | * @since 3.7
57 | *
58 | * @return PLL_Language|null
59 | */
60 | protected function get_language(): ?PLL_Language {
61 | global $post;
62 |
63 | if ( ! empty( $post ) && ! empty( $this->posts ) && $this->model->post_types->is_translated( $post->post_type ) ) {
64 | $this->posts->set_default_language( $post->ID );
65 | $post_lang = $this->model->post->get_language( $post->ID );
66 | return ! empty( $post_lang ) ? $post_lang : null;
67 | }
68 |
69 | return null;
70 | }
71 |
72 | /**
73 | * Returns the screen name for the Post editor to use across all process.
74 | *
75 | * @since 3.7
76 | *
77 | * @return string
78 | */
79 | protected function get_screen_name(): string {
80 | return 'post';
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/modules/frontend-filter-template/filter-template-page.php:
--------------------------------------------------------------------------------
1 | model->post->get( $object->ID, $this->default_language );
27 | $def_lang_object = get_post( $def_lang_id );
28 | if ( ! $def_lang_object instanceof WP_Post ) {
29 | return $templates;
30 | }
31 | return $this->prepend_templates( $templates, $def_lang_object );
32 | }
33 |
34 | /**
35 | * Returns the language of the given post.
36 | *
37 | * @since 3.7
38 | *
39 | * @param object $object The post object.
40 | * @return PLL_Language|false Post language, `false` if none found.
41 | */
42 | protected function get_object_language( object $object ) {
43 | if ( ! $object instanceof WP_Post ) {
44 | return false;
45 | }
46 |
47 | return $this->model->post->get_language( $object->ID );
48 | }
49 |
50 | /**
51 | * Prepends templates for the given post to the given array.
52 | *
53 | * @since 3.7
54 | *
55 | * @param array $templates Array of templates.
56 | * @param WP_Post $post Post object to use.
57 | * @return array Array of templates with prepended ones.
58 | */
59 | protected function prepend_templates( array $templates, WP_Post $post ): array {
60 | array_unshift( $templates, "page-{$post->ID}.php" );
61 | array_unshift( $templates, "page-{$post->post_name}.php" );
62 |
63 | return $templates;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/modules/full-site-editing/fse-post-types.php:
--------------------------------------------------------------------------------
1 | model->term->get( $object->term_id, $this->default_language );
27 | $def_lang_object = get_term( $def_lang_id );
28 | if ( ! $def_lang_object instanceof WP_Term ) {
29 | return $templates;
30 | }
31 |
32 | return $this->prepend_templates( $templates, $def_lang_object );
33 | }
34 |
35 | /**
36 | * Returns the language of the given term.
37 | *
38 | * @since 3.7
39 | *
40 | * @param object $object The term object.
41 | * @return PLL_Language|false Term language, `false` if none found.
42 | */
43 | protected function get_object_language( object $object ) {
44 | if ( ! $object instanceof WP_Term ) {
45 | return false;
46 | }
47 |
48 | return $this->model->term->get_language( $object->term_id );
49 | }
50 |
51 | /**
52 | * Prepends templates for the given term to the given array.
53 | *
54 | * @since 3.7
55 | *
56 | * @param array $templates Array of templates.
57 | * @param WP_Term $term Term object to use.
58 | * @return array Array of templates with prepended ones.
59 | */
60 | protected function prepend_templates( array $templates, WP_Term $term ): array {
61 | $type = 'post_tag' === $term->taxonomy ? 'tag' : $term->taxonomy;
62 | array_unshift( $templates, "{$type}-{$term->term_id}.php" );
63 | array_unshift( $templates, "{$type}-{$term->slug}.php" );
64 |
65 | return $templates;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/services/exporter/export-data-from-strings.php:
--------------------------------------------------------------------------------
1 | model = $model;
28 | }
29 |
30 | /**
31 | * Prepares and exports the selected strings translations.
32 | *
33 | * @since 3.6
34 | *
35 | * @param PLL_Export_Container $container Export container.
36 | * @param array $sources Currated list of strings to export.
37 | * @param PLL_Language $target_language The target language.
38 | * @param bool $no_update Whether to remove already translated strings. Default to false.
39 | * @return WP_Error A `WP_Error` object. Note: an "empty" `WP_Error` object is returned on success.
40 | */
41 | public function send_to_export( PLL_Export_Container $container, array $sources, PLL_Language $target_language, bool $no_update = false ): WP_Error {
42 | $source_language = $this->model->get_default_language();
43 |
44 | if ( empty( $source_language ) ) {
45 | return new WP_Error( 'pll_export_no_source_language', __( 'Error: Default language not defined.', 'polylang-pro' ) );
46 | }
47 |
48 | if ( $no_update ) {
49 | $mo = new PLL_MO();
50 | $mo->import_from_db( $target_language );
51 | $sources = array_filter(
52 | $sources,
53 | function ( $source ) use ( $mo ) {
54 | return empty( $mo->translate_if_any( $source['string'] ) );
55 | }
56 | );
57 | }
58 |
59 | if ( empty( $sources ) ) {
60 | return new WP_Error( 'pll_export_no_strings', __( 'Error: No strings found.', 'polylang-pro' ) );
61 | }
62 |
63 | ( new PLL_Export_Strings( $this->model ) )->add_items( $container, $sources, $target_language );
64 |
65 | return new WP_Error();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/modules/media/settings-advanced-media.php:
--------------------------------------------------------------------------------
1 | 'advanced_media',
32 | 'title' => __( 'Media', 'polylang-pro' ),
33 | 'description' => __( 'Activate languages and translations for media. Provides options for multilingual media management.', 'polylang-pro' ),
34 | 'active_option' => 'media_support',
35 | )
36 | );
37 | }
38 |
39 | /**
40 | * Displays the settings form
41 | *
42 | * @since 1.9
43 | *
44 | * @return void
45 | */
46 | protected function form() {
47 | printf(
48 | '',
49 | checked( empty( $this->options['media']['duplicate'] ), false, false ),
50 | esc_html__( 'Automatically duplicate media in all languages when uploading a new file.', 'polylang-pro' )
51 | );
52 | }
53 |
54 | /**
55 | * Prepare the received data before saving.
56 | *
57 | * @since 3.7
58 | *
59 | * @param array $options Raw values to save.
60 | * @return array
61 | */
62 | protected function prepare_raw_data( array $options ): array {
63 | $newoptions = array( 'media' => array( 'duplicate' => ! empty( $options['media']['duplicate'] ) ? 1 : 0 ) );
64 | return $newoptions; // Take care to return only validated options.
65 | }
66 |
67 | /**
68 | * Get the row actions
69 | *
70 | * @since 1.9
71 | *
72 | * @return string[]
73 | */
74 | protected function get_actions() {
75 | return empty( $this->options['media_support'] ) ? array( 'activate' ) : array( 'configure', 'deactivate' );
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/modules/import-export/xliff/xliff-format.php:
--------------------------------------------------------------------------------
1 | 'text/xml' );
23 |
24 | /**
25 | * PLL_Xliff_Format constructor.
26 | *
27 | * @since 3.1
28 | */
29 | public function __construct() {
30 | // MIME type does not use the same string for PHP versions < 7.2.
31 | if ( version_compare( phpversion(), '7.2', '<' ) ) {
32 | $this->mime_type = array( 'xlf|xliff' => 'application/xml' );
33 | }
34 | }
35 |
36 | /**
37 | * Whether the xliff format is supported or not by the current environment.
38 | *
39 | * @since 3.1
40 | *
41 | * @return true|WP_Error
42 | */
43 | public function is_supported() {
44 | if ( ! extension_loaded( 'libxml' ) ) {
45 | return new WP_Error( 'pll_libxml_missing', __( 'Your PHP installation appears to be missing the libxml extension which is required by the importer.', 'polylang-pro' ) );
46 | }
47 |
48 | return true;
49 | }
50 |
51 | /**
52 | * Returns the associated import class.
53 | *
54 | * @since 3.1
55 | *
56 | * @return PLL_Xliff_Import
57 | */
58 | public function get_import() {
59 | return new PLL_Xliff_Import();
60 | }
61 |
62 | /**
63 | * Returns the associated export class.
64 | *
65 | * @since 3.6
66 | *
67 | * @param string $version Optional file format version.
68 | * @return string
69 | *
70 | * @phpstan-return class-string|class-string|class-string
71 | */
72 | public function get_export_class( $version = '' ): string {
73 | switch ( $version ) {
74 | case '20':
75 | $class_name = PLL_Xliff_Export_20::class;
76 | break;
77 | case '21':
78 | $class_name = PLL_Xliff_Export_21::class;
79 | break;
80 | default: // 1.2
81 | $class_name = PLL_Xliff_Export_12::class;
82 | break;
83 | }
84 | return $class_name;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/integrations/admin-columns/cpac.php:
--------------------------------------------------------------------------------
1 | model->get_translated_post_types() as $type ) {
23 | if ( isset( $_REQUEST['list_screen'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
24 | $filter = 'manage_' . ( 'attachment' === $type ? 'upload' : 'edit-' . $type ) . '_columns';
25 | add_filter( $filter, array( $this, 'remove_filter_lang' ), 90 ); // Before Polylang.
26 | }
27 |
28 | $filter = 'option_cpac_options_' . ( 'attachment' === $type ? 'wp-media' : $type ) . '__default';
29 | add_filter( $filter, array( $this, 'filter_default_columns' ) );
30 | }
31 | }
32 |
33 | /**
34 | * Deactivates the admin language filter on Admin Columns settings page.
35 | *
36 | * @since 2.4
37 | *
38 | * @param array $columns List of table columns.
39 | * @return array
40 | */
41 | public function remove_filter_lang( $columns ) {
42 | PLL()->filters_columns->filter_lang = '';
43 | return $columns;
44 | }
45 |
46 | /**
47 | * Fixes the Polylang columns in default columns.
48 | *
49 | * @since 2.4
50 | *
51 | * @param array $columns List of table columns.
52 | * @return array
53 | */
54 | public function filter_default_columns( $columns ) {
55 | $screen = get_current_screen();
56 |
57 | if ( isset( $screen->base ) ) {
58 | $is_post_type = 'edit' === $screen->base && has_filter( 'manage_edit-' . $screen->post_type . '_columns', array( PLL()->filters_columns, 'add_post_column' ) );
59 | $is_media = 'upload' === $screen->base && has_filter( 'manage_upload_columns', array( PLL()->filters_columns, 'add_post_column' ) );
60 |
61 | if ( $is_post_type || $is_media ) {
62 | foreach ( pll_languages_list() as $lang ) {
63 | unset( $columns[ 'language_' . $lang ] );
64 | }
65 |
66 | $columns = PLL()->filters_columns->add_post_column( $columns );
67 | }
68 | }
69 |
70 | return $columns;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/modules/duplicate/duplicate-rest.php:
--------------------------------------------------------------------------------
1 | links = new PLL_Admin_Links( $polylang );
37 | $this->user_meta = new PLL_Toggle_User_Meta( PLL_Duplicate_Action::META_NAME );
38 |
39 | register_rest_field(
40 | 'user',
41 | $this->user_meta->get_meta_name(),
42 | array(
43 | 'get_callback' => array( $this->user_meta, 'get' ),
44 | 'update_callback' => array( $this->user_meta, 'update' ),
45 | )
46 | );
47 |
48 | add_filter( 'block_editor_settings_all', array( $this, 'remove_template' ), 10, 2 );
49 | }
50 |
51 | /**
52 | * Avoids that the post template overwrites our duplicated content.
53 | *
54 | * @since 3.2
55 | *
56 | * @param array $editor_settings Default editor settings.
57 | * @param WP_Block_Editor_Context $block_editor_context The current block editor context.
58 | * @return array
59 | */
60 | public function remove_template( $editor_settings, $block_editor_context ) {
61 | if ( empty( $block_editor_context->post ) || ! $block_editor_context->post instanceof WP_Post || empty( $block_editor_context->post->post_content ) ) {
62 | return $editor_settings;
63 | }
64 |
65 | $data = $this->links->get_data_from_new_post_translation_request( $block_editor_context->post->post_type );
66 |
67 | if ( empty( $data ) ) {
68 | return $editor_settings;
69 | }
70 |
71 | unset( $editor_settings['template'], $editor_settings['templateLock'] );
72 |
73 | return $editor_settings;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/integrations/acf/README.md:
--------------------------------------------------------------------------------
1 | # ACF Integration
2 |
3 | Integration with Advanced Custom Fields Pro, bootstraped in `acf/load.php` with `Main` main object.
4 | All names take place in `WP_Syntex\Polylang_Pro\Integrations\ACF` namespace.
5 |
6 | ## How field translation works
7 |
8 | ### For standard custom fields
9 |
10 | `Dispatcher` applies strategies to custom fields of `Entity\Abstract_Object` objects (posts or terms) as well as ACF blocks.
11 | These strategies follow the Strategy Pattern to make fields benefit from Polylang Pro core features such as:
12 |
13 | | Feature | Strategy |
14 | | --- | --- |
15 | | New post translation creation | `Strategy\Copy` |
16 | | Synchronization on post/term update | `Strategy\Synchronize` |
17 | | Bulk translate | `Strategy\Copy` or `Strategy\Copy_All` |
18 | | Export, import and machine translation | `Strategy\Export`, `Strategy\Import` and `Strategy\Abstract_Collect_Ids` |
19 |
20 | ### For block fields
21 |
22 | Import, export, machine translation and smart synchronization for fields containing IDs are supported thanks to `Entity\Blocks` class. This class is able to apply any strategy to a list of blocks thanks to `Entity\Blocks::apply_on_blocks()`.
23 |
24 | ### Note on language location
25 |
26 | To provide end users a way to have field groups displayed only for specific language, a custom location is provided with `Location\Language`.
27 |
28 | ## Translated labels
29 |
30 | Now that field groups are not translatable anymore, the only way to have them displayed in several languages is using strings translations.
31 | This new feature lays in `Labels\Field_Groups`.
32 | Note that the integration offers the same feature for ACF post types and taxonomies (`Labels\Abstract_Object_Type`).
33 |
34 | ## Editor
35 |
36 | Integration with editors UI can be found in `Ajax_Lang_Choice` and `acf/js/acf.js`.
37 |
38 | ## Migration from Polylang Pro prior to 3.7
39 |
40 | Field groups are not translated at all now. For sites having translated field groups with Polylang Pro < 3.7, a migration will occur on update.
41 | This migration will update each field groups with a location corresponding to the formerly assigned language.
42 | The related code can be found in `WP_Syntex\Polylang_Pro\Upgrade::upgrade_3_7()`.
43 |
--------------------------------------------------------------------------------
/modules/Machine_Translation/Posts/Button.php:
--------------------------------------------------------------------------------
1 | service = $service;
39 | $this->user_meta = new PLL_Toggle_User_Meta( sprintf( 'pll_machine_translation_%s', $this->service->get_slug() ) );
40 |
41 | $args = array(
42 | 'position' => 'before_post_translations',
43 | 'activate' => sprintf(
44 | /* translators: %s is the name of the machine translation service. */
45 | __( 'Activate %s machine translation', 'polylang-pro' ),
46 | $this->service->get_name()
47 | ),
48 | 'deactivate' => sprintf(
49 | /* translators: %s is the name of the machine translation service. */
50 | __( 'Deactivate %s machine translation', 'polylang-pro' ),
51 | $this->service->get_name()
52 | ),
53 | 'icon' => $this->service->get_icon(),
54 | 'priority' => 20,
55 | );
56 |
57 | parent::__construct( 'pll-machine-translation', $args );
58 |
59 | add_action( 'admin_notices', array( $this, 'display_errors' ) );
60 | }
61 |
62 | /**
63 | * Prints translation errors into the page.
64 | *
65 | * @since 3.6
66 | *
67 | * @return void
68 | */
69 | public function display_errors() {
70 | settings_errors( 'polylang' );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/modules/full-site-editing/fse-post-deletion.php:
--------------------------------------------------------------------------------
1 | delete_post()` (prio 10), so the data about the translations still exist.
36 | return $this;
37 | }
38 |
39 | /**
40 | * When a template in the default language is deleted, also delete its translations.
41 | *
42 | * @since 3.2
43 | *
44 | * @param int $post_id Post ID.
45 | * @param WP_Post $post Post object.
46 | * @return void
47 | */
48 | public function delete_translation_posts( $post_id, $post ) {
49 | if ( ! $post instanceof WP_Post || ! in_array( $post->post_type, PLL_FSE_Tools::get_translatable_post_types(), true ) ) {
50 | // Not a translated template post type.
51 | return;
52 | }
53 |
54 | $def_lang = $this->model->get_default_language();
55 | $post_lang = $this->model->post->get_language( $post->ID );
56 |
57 | if ( empty( $def_lang ) || empty( $post_lang ) || $def_lang->slug !== $post_lang->slug ) {
58 | // This one is not in the default language.
59 | return;
60 | }
61 |
62 | $translations = $this->model->post->get_translations( $post->ID );
63 | $translations = array_diff( $translations, array( $post->ID ) ); // Let's not create an infinite loop.
64 |
65 | if ( empty( $translations ) ) {
66 | // Nothing to delete.
67 | return;
68 | }
69 |
70 | foreach ( $translations as $translation_id ) {
71 | // Send it to Sovngarde.
72 | wp_delete_post( $translation_id, true );
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/modules/full-site-editing/fse-default-language-change.php:
--------------------------------------------------------------------------------
1 | model->get_language( $new_def_lang_slug );
53 | if ( empty( $new_def_lang ) ) {
54 | // Uh?
55 | return;
56 | }
57 |
58 | $old_def_lang = $this->model->get_language( $old_def_lang_slug );
59 | if ( empty( $old_def_lang ) ) {
60 | // Uh?
61 | return;
62 | }
63 |
64 | // Add a language suffix to the slugs belonging to templates in the current default language.
65 | $this->update_language_suffix_in_post_names( $old_def_lang );
66 |
67 | // Remove the language suffix from the slugs belonging to templates in the new default language.
68 | $this->remove_language_suffix_from_post_names( $new_def_lang );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/services/translation/translation-content.php:
--------------------------------------------------------------------------------
1 | translations = $translations;
36 | }
37 |
38 | /**
39 | * Translates the original's post title.
40 | *
41 | * @since 3.3
42 | *
43 | * @param string $from_post The post_content field of the original WP_Post.
44 | * @return string
45 | */
46 | public function translate_title( $from_post ) {
47 | return $this->translations->translate(
48 | $from_post,
49 | Context::to_string(
50 | array(
51 | Context::FIELD => PLL_Import_Export::POST_TITLE,
52 | )
53 | )
54 | );
55 | }
56 |
57 | /**
58 | * Uses a {@see PLL_Translation_Walker_Interface} subclass to iterate over each translatable part of the passed content, and applies a transformation callback to it. Then returns the transformed content.
59 | *
60 | * @since 3.3
61 | *
62 | * @param string $content The post_content field of the original WP_Post.
63 | * @return string
64 | */
65 | public function translate_content( $content ) {
66 | $walker = PLL_Translation_Walker_Factory::create_from( $content );
67 |
68 | return $walker->walk( array( $this->translations, 'translate_entry' ) );
69 | }
70 |
71 | /**
72 | * Translates the original post's excerpt.
73 | *
74 | * @since 3.3
75 | *
76 | * @param string $post_excerpt The post_excerpt field of the original WP_Post.
77 | * @return string
78 | */
79 | public function translate_excerpt( $post_excerpt ) {
80 | return $this->translations->translate(
81 | $post_excerpt,
82 | Context::to_string(
83 | array(
84 | Context::FIELD => PLL_Import_Export::POST_EXCERPT,
85 | )
86 | )
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/modules/Machine_Translation/Strings/Metabox.php:
--------------------------------------------------------------------------------
1 | model = $polylang->model;
39 | $this->action = new Action( $polylang, $service );
40 | }
41 |
42 | /**
43 | * Initializes the machine translations metabox.
44 | *
45 | * @since 3.7
46 | *
47 | * @return self Instance of the current class.
48 | */
49 | public function init(): self {
50 | add_action( 'load-languages_page_mlang_strings', array( $this, 'add' ) );
51 |
52 | /*
53 | * See the hook `mlang_action_{$action}` in `PLL_Settings::handle_actions()`.
54 | */
55 | add_action(
56 | 'mlang_action_machine-translations',
57 | array( $this->action, 'validate_form' )
58 | );
59 |
60 | return $this;
61 | }
62 |
63 | /**
64 | * Adds the machine translation metabox.
65 | *
66 | * @since 3.7
67 | *
68 | * @return void
69 | */
70 | public function add() {
71 | add_meta_box(
72 | 'pll-machine-strings-translations',
73 | __( 'Machine translations', 'polylang-pro' ),
74 | array( $this, 'render' ),
75 | 'languages_page_mlang_strings',
76 | 'normal'
77 | );
78 | }
79 |
80 | /**
81 | * Renders the machine translation metabox.
82 | *
83 | * @since 3.7
84 | *
85 | * @return void
86 | */
87 | public function render() {
88 | $model = $this->model;
89 | include POLYLANG_PRO_DIR . '/modules/Machine_Translation/Views/string-form.php';
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/modules/Machine_Translation/Views/string-form.php:
--------------------------------------------------------------------------------
1 | get_languages_list();
15 | $strings = PLL_Admin_Strings::get_strings();
16 | $groups = array_unique( wp_list_pluck( $strings, 'context' ) );
17 | ?>
18 |
19 |
60 |
61 |
--------------------------------------------------------------------------------
/modules/sync-post/sync-post-bulk-option.php:
--------------------------------------------------------------------------------
1 | do_synchronize = $args['do_synchronize'];
42 | $this->sync_model = $sync_model;
43 | }
44 |
45 | /**
46 | * Checks whether the option should be selectable by the user.
47 | *
48 | * @since 2.7
49 | *
50 | * @return bool
51 | */
52 | public function is_available() {
53 | $screen = get_current_screen();
54 |
55 | if ( $screen && 'edit' === $screen->base ) {
56 | $post_type = get_post_type_object( $screen->post_type );
57 | return $post_type && current_user_can( $post_type->cap->edit_posts );
58 | }
59 |
60 | return false;
61 | }
62 |
63 |
64 | /**
65 | * Duplicates or Synchronize the given post, depending on the value of {@see PLL_Sync_Post_Bulk_Option::$do_synchronize}
66 | *
67 | * @since 2.7
68 | *
69 | * @param int $object_id Identifies a post to duplicate or synchronize.
70 | * @param string $lang A language slug to translate into.
71 | */
72 | public function translate( $object_id, $lang ) {
73 | if ( false === $this->do_synchronize ) {
74 | $this->sync_model->save_group( $object_id, array() );
75 | $strategy = PLL_Sync_Post_Model::COPY;
76 | } else {
77 | $strategy = PLL_Sync_Post_Model::SYNC;
78 | }
79 |
80 | $this->sync_model->copy( $object_id, $lang, $strategy, $this->do_synchronize );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/modules/bulk-translate/view-bulk-translate.php:
--------------------------------------------------------------------------------
1 |
16 |
61 |
--------------------------------------------------------------------------------
/modules/blocks/language-switcher/language-switcher-block.php:
--------------------------------------------------------------------------------
1 | set_attributes_for_block( $attributes );
45 |
46 | $attributes['raw'] = false;
47 | $switcher = new PLL_Switcher();
48 | $switcher_output = $switcher->the_languages( $this->links, $attributes );
49 |
50 | if ( empty( $switcher_output ) ) {
51 | return '';
52 | }
53 |
54 | $aria_label = __( 'Choose a language', 'polylang-pro' );
55 | if ( $attributes['dropdown'] ) {
56 | $switcher_output = '' . $switcher_output;
57 |
58 | $wrap_tag = '%2$s';
59 | } else {
60 | $wrap_tag = '';
61 | }
62 |
63 | $wrap_attributes = get_block_wrapper_attributes();
64 |
65 | return sprintf( $wrap_tag, $wrap_attributes, $switcher_output );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/js/build/index.js:
--------------------------------------------------------------------------------
1 | /******/ "use strict";
2 | /******/ // The require scope
3 | /******/ var __webpack_require__ = {};
4 | /******/
5 | /************************************************************************/
6 | /******/ /* webpack/runtime/define property getters */
7 | /******/ (() => {
8 | /******/ // define getter functions for harmony exports
9 | /******/ __webpack_require__.d = (exports, definition) => {
10 | /******/ for(var key in definition) {
11 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
12 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
13 | /******/ }
14 | /******/ }
15 | /******/ };
16 | /******/ })();
17 | /******/
18 | /******/ /* webpack/runtime/hasOwnProperty shorthand */
19 | /******/ (() => {
20 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
21 | /******/ })();
22 | /******/
23 | /************************************************************************/
24 | var __webpack_exports__ = {};
25 | /* unused harmony export ajaxFilter */
26 | /**
27 | * @package Polylang
28 | */
29 |
30 | /**
31 | * Adds data to all ajax requests made with jQuery.
32 | *
33 | * @since 3.7
34 | *
35 | * @param {Object} data The data to add.
36 | * @returns {void}
37 | */
38 | function ajaxFilter( data ) {
39 | if ( 'undefined' === typeof jQuery || ! data ) {
40 | return;
41 | }
42 |
43 | const dataStr = jQuery.param( data );
44 |
45 | jQuery.ajaxPrefilter( function ( options ) {
46 | if ( -1 === options.url.indexOf( ajaxurl ) && -1 === ajaxurl.indexOf( options.url ) ) {
47 | return;
48 | }
49 |
50 | if (
51 | 'undefined' === typeof options.data ||
52 | null === options.data ||
53 | 'string' === typeof options.data && '' === options.data.trim()
54 | ) {
55 | // An empty string or null/undefined.
56 | options.data = dataStr;
57 | } else if ( 'string' === typeof options.data ) {
58 | // A non-empty string: can be a JSON string or a query string.
59 | try {
60 | options.data = JSON.stringify( Object.assign( JSON.parse( options.data ), data ) );
61 | } catch ( exception ) {
62 | // A non-empty non-JSON string is considered a query string.
63 | options.data = `${ options.data }&${ dataStr }`;
64 | }
65 | } else if ( jQuery.isPlainObject( options.data ) ) {
66 | // An object.
67 | options.data = Object.assign( options.data, data );
68 | }
69 | } );
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/modules/wizard/wizard-pro.php:
--------------------------------------------------------------------------------
1 | model = &$polylang->model;
32 | $this->sync_model = &$polylang->sync_post_model;
33 |
34 | // See pll_wizard_create_home_page_translations filter in PLL_Wizard class.
35 | add_filter( 'pll_wizard_create_home_page_translations', array( $this, 'replace_create_home_page_translations' ) );
36 | }
37 |
38 | /**
39 | * Replace function to apply to process the home page translations creation.
40 | *
41 | * @since 2.7
42 | *
43 | * @return callable
44 | */
45 | public function replace_create_home_page_translations() {
46 | return array( $this, 'create_home_page_translations' );
47 | }
48 |
49 | /**
50 | * Create home page translations for each language defined with duplicating content.
51 | *
52 | * @since 2.7
53 | *
54 | * @param string $default_language slug of the default language; null if no default language is defined.
55 | * @param int $home_page post_id of the home page if it's defined, false otherwise.
56 | * @param string $home_page_title home page title if it's defined, 'Homepage' otherwise.
57 | * @param string $home_page_language slug of the home page if it's defined, false otherwise.
58 | * @param array $untranslated_languages array of languages which needs to have a home page translated.
59 | * @return void
60 | */
61 | public function create_home_page_translations( $default_language, $home_page, $home_page_title, $home_page_language, $untranslated_languages ) {
62 | global $wpdb;
63 |
64 | foreach ( $untranslated_languages as $language ) {
65 | $translated_post_id = $this->sync_model->copy( $home_page, $language );
66 | $language_properties = $this->model->get_language( $language );
67 | $wpdb->update(
68 | $wpdb->posts,
69 | array( 'post_title' => $home_page_title . ' - ' . $language_properties->name ),
70 | array( 'ID' => $translated_post_id )
71 | ); // Don't use wp_update_post to ensure not redo save post process.
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/modules/frontend-filter-template/abstract-filter-template.php:
--------------------------------------------------------------------------------
1 | model = $model;
35 | /** @phpstan-var PLL_Language $default_language */
36 | $default_language = $this->model->get_default_language();
37 | $this->default_language = $default_language;
38 | }
39 |
40 | /**
41 | * Filters templates according to the current queried object.
42 | *
43 | * @since 3.7
44 | *
45 | * @param array $templates Array of templates guessed from the hierarchy.
46 | * @return array Filtered array of templates.
47 | */
48 | public function filter( $templates ) {
49 | if ( ! is_array( $templates ) ) {
50 | // Something bad happened.
51 | return $templates;
52 | }
53 |
54 | $object = get_queried_object();
55 | if ( ! is_object( $object ) ) {
56 | return $templates;
57 | }
58 |
59 | $language = $this->get_object_language( $object );
60 | if ( ! $language instanceof PLL_Language ) {
61 | return $templates;
62 | }
63 |
64 | if ( $language->slug === $this->default_language->slug ) {
65 | return $templates;
66 | }
67 |
68 | return $this->add_def_lang_templates_from_object( $templates, $object );
69 | }
70 |
71 | /**
72 | * Adds templates of the default language from an object.
73 | *
74 | * @since 3.7
75 | *
76 | * @param array $templates Array of templates guessed from the hierarchy.
77 | * @param object $object Object to use to guess templates.
78 | * @return array Array of templates with added ones.
79 | */
80 | abstract protected function add_def_lang_templates_from_object( array $templates, object $object ): array;
81 |
82 | /**
83 | * Returns the language of the given object.
84 | *
85 | * @since 3.7
86 | *
87 | * @param object $object The object (e.g. `WP_Post` or `WP_Term`).
88 | * @return PLL_Language|false Object language, `false` if none found.
89 | */
90 | abstract protected function get_object_language( object $object );
91 | }
92 |
--------------------------------------------------------------------------------
/css/build/machine-translation-settings.css:
--------------------------------------------------------------------------------
1 | .pll-settings .pll-inner-notice {
2 | margin: 5px 0 15px;
3 | border: 1px solid #c3c4c7;
4 | border-left-width: 4px;
5 | padding: 1px 12px;
6 | background: #fff;
7 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
8 | }
9 |
10 | .form-table .pll-inner-notice {
11 | margin-bottom: 5px;
12 | }
13 |
14 | .pll-settings .notice-success {
15 | border-left-color: #00a32a;
16 | }
17 |
18 | .pll-settings .notice-warning {
19 | border-left-color: #dba617;
20 | }
21 |
22 | .pll-settings .notice-error {
23 | border-left-color: #d63638;
24 | }
25 |
26 | .pll-settings .pll-inner-notice p {
27 | margin: 0.5em 0;
28 | padding: 2px;
29 | }
30 |
31 | .pll-settings .pll-message:not(.pll-origin-message),
32 | .pll-settings .notice-success .pll-origin-message,
33 | .pll-settings .notice-warning .pll-origin-message,
34 | .pll-settings .notice-error .pll-origin-message {
35 | display: none;
36 | }
37 |
38 | .pll-settings .notice-success .pll-success-message,
39 | .pll-settings .notice-warning .pll-warning-message.pll-message-shown,
40 | .pll-settings .notice-error .pll-error-message.pll-message-shown {
41 | display: block;
42 | }
43 |
44 | .pll-settings [disabled] + .spinner,
45 | .pll-progress-bar-wrapper .spinner {
46 | visibility: visible;
47 | }
48 |
49 | .pll-success-message .pll-icon {
50 | color: rgb(18, 91, 145);
51 | }
52 |
53 | .pll-error-message .pll-icon,
54 | .pll-warning-message .pll-icon {
55 | color: rgb(145, 30, 31);
56 | }
57 |
58 | .pll-icon {
59 | font-size: 1.8em;
60 | margin-right: 3px;
61 | margin-left: 1px;
62 | vertical-align: -2px;
63 | }
64 |
65 | .pll-progress-bar-wrapper {
66 | position: relative;
67 | max-width: 500px;
68 | height: 2em;
69 | line-height: 2em;
70 | vertical-align: middle;
71 | text-align: left;
72 | font-size: 2em;
73 | border: 1px solid rgb(64, 70, 72);
74 | border-radius: 4px;
75 | overflow: hidden;
76 | white-space: nowrap;
77 | color: rgb(23, 114, 181);
78 | text-indent: 1em;
79 | }
80 |
81 | .pll-progress-bar-wrapper div {
82 | position: absolute;
83 | height: 100%;
84 | top: 0;
85 | left: 0;
86 | overflow: hidden;
87 | background-color: rgb(23, 114, 181);
88 | color: rgb(232, 230, 227);
89 | }
90 |
91 | .pll-settings [type="password"] + .button {
92 | margin-left: 20px;
93 | margin-right: 0;
94 | }
95 |
96 | .pll-settings [type="password"] + .button + .spinner {
97 | float: none;
98 | }
99 |
100 | .pll-progress-bar-wrapper .spinner {
101 | float: none;
102 | margin: 0;
103 | }
104 |
--------------------------------------------------------------------------------
/js/build/metabox-autocomplete.js:
--------------------------------------------------------------------------------
1 | /******/ "use strict";
2 | /******/ // The require scope
3 | /******/ var __webpack_require__ = {};
4 | /******/
5 | /************************************************************************/
6 | /******/ /* webpack/runtime/define property getters */
7 | /******/ (() => {
8 | /******/ // define getter functions for harmony exports
9 | /******/ __webpack_require__.d = (exports, definition) => {
10 | /******/ for(var key in definition) {
11 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
12 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
13 | /******/ }
14 | /******/ }
15 | /******/ };
16 | /******/ })();
17 | /******/
18 | /******/ /* webpack/runtime/hasOwnProperty shorthand */
19 | /******/ (() => {
20 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
21 | /******/ })();
22 | /******/
23 | /************************************************************************/
24 | var __webpack_exports__ = {};
25 | /* unused harmony export initMetaboxAutoComplete */
26 | /**
27 | * @package Polylang
28 | */
29 |
30 | // Translations autocomplete input box.
31 | function initMetaboxAutoComplete() {
32 | jQuery('.tr_lang').each(
33 | function () {
34 | var tr_lang = jQuery(this).attr('id').substring(8);
35 | var td = jQuery(this).parent().parent().siblings('.pll-edit-column');
36 |
37 | jQuery(this).autocomplete(
38 | {
39 | minLength: 0,
40 | source: ajaxurl + '?action=pll_posts_not_translated' +
41 | '&post_language=' + jQuery('.post_lang_choice').val() +
42 | '&translation_language=' + tr_lang +
43 | '&post_type=' + jQuery('#post_type').val() +
44 | '&_pll_nonce=' + jQuery('#_pll_nonce').val(),
45 | select: function (event, ui) {
46 | jQuery('#htr_lang_' + tr_lang).val(ui.item.id);
47 | // ui.item.link is built and come from server side and is well escaped when necessary
48 | td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
49 | },
50 | }
51 | );
52 |
53 | // when the input box is emptied
54 | jQuery(this).on(
55 | 'blur',
56 | function () {
57 | if ( ! jQuery(this).val() ) {
58 | jQuery('#htr_lang_' + tr_lang).val(0);
59 | // Value is retrieved from HTML already generated server side
60 | td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
61 | }
62 | }
63 | );
64 | }
65 | );
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/include/upgrade.php:
--------------------------------------------------------------------------------
1 | options = $options;
33 | }
34 |
35 | /**
36 | * Runs upgrade process.
37 | *
38 | * @since 3.7
39 | *
40 | * @return void
41 | */
42 | public function upgrade() {
43 | foreach ( array( '3.7' ) as $version ) {
44 | if ( version_compare( $this->options->get( 'version' ), $version, '<' ) ) {
45 | $method_to_call = array( $this, 'upgrade_' . str_replace( '.', '_', $version ) );
46 | if ( is_callable( $method_to_call ) ) {
47 | call_user_func( $method_to_call );
48 | }
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * Migrates translated field groups to the new ACF integration.
55 | * Transforms language taxonomy to group location.
56 | *
57 | * @since 3.7
58 | *
59 | * @return void
60 | */
61 | private function upgrade_3_7() {
62 | if ( ! ACF_Main::can_use() ) {
63 | return;
64 | }
65 |
66 | if ( ! in_array( 'acf-field-group', $this->options->get( 'post_types' ), true ) ) {
67 | return;
68 | }
69 |
70 | $this->options->set(
71 | 'post_types',
72 | array_diff(
73 | $this->options->get( 'post_types' ),
74 | array( 'acf-field-group' )
75 | )
76 | );
77 | $this->options->save();
78 |
79 | foreach ( acf_get_field_groups() as $group ) {
80 | if ( empty( $group['ID'] ) ) {
81 | continue;
82 | }
83 |
84 | $group_language = wp_get_object_terms( $group['ID'], 'language' );
85 |
86 | if ( empty( $group_language ) || is_wp_error( $group_language ) || 1 !== count( $group_language ) ) {
87 | continue;
88 | }
89 |
90 | $group_language = $group_language[0];
91 | $new_location = array(
92 | 'param' => 'language',
93 | 'operator' => '==',
94 | 'value' => $group_language->slug,
95 | );
96 |
97 | foreach ( $group['location'] as &$location ) {
98 | $location[] = $new_location;
99 | }
100 |
101 | acf_update_field_group( $group );
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/js/build/nav-menu.min.js:
--------------------------------------------------------------------------------
1 | const pllNavMenu={wrapper:null,init:()=>{"loading"!==document.readyState?pllNavMenu.ready():document.addEventListener("DOMContentLoaded",pllNavMenu.ready)},ready:()=>{pllNavMenu.wrapper=document.getElementById("menu-to-edit"),pllNavMenu.wrapper&&(pllNavMenu.wrapper.addEventListener("click",pllNavMenu.printMetabox),pllNavMenu.wrapper.addEventListener("change",pllNavMenu.ensureContent),pllNavMenu.wrapper.addEventListener("change",pllNavMenu.showHideRows))},printMetabox:{handleEvent:e=>{if(!e.target.classList.contains("item-edit"))return;const t=e.target.closest(".menu-item").querySelector(".menu-item-settings");if(!t?.id)return;if(!t.querySelectorAll('input[value="#pll_switcher"][type=text]').length)return;[...t.children].forEach((e=>{"P"!==e.nodeName||e.classList.contains("field-move")||e.remove()}));const n=pllNavMenu.printMetabox,a=Number(t.id.replace("menu-item-settings-",""));t.append(n.createHiddenInput("title",a,pll_data.title)),t.append(n.createHiddenInput("url",a,"#pll_switcher")),t.append(n.createHiddenInput("pll-detect",a,1));const r=Array("hide_if_no_translation","hide_current","force_home","show_flags","show_names","dropdown"),d=void 0!==pll_data.val[a];r.forEach((e=>{const r=n.createElement("p",{class:"description"});"hide_current"===e&&d&&1===pll_data.val[a].dropdown&&r.classList.add("hidden"),t.prepend(r);const l=`edit-menu-item-${e}-${a}`,i=n.createElement("label",{for:l});i.innerText=` ${pll_data.strings[e]}`,r.append(i);const c=n.createElement("input",{type:"checkbox",id:l,name:`menu-item-${e}[${a}]`,value:1});(d&&1===pll_data.val[a][e]||!d&&"show_names"===e)&&(c.checked=!0),i.prepend(c)}))},createHiddenInput:(e,t,n)=>pllNavMenu.printMetabox.createElement("input",{type:"hidden",id:`edit-menu-item-${e}-${t}`,name:`menu-item-${e}[${t}]`,value:n}),createElement:(e,t)=>{const n=document.createElement(e);for(const[e,a]of Object.entries(t))n.setAttribute(e,a);return n}},ensureContent:{regExpr:new RegExp(/^edit-menu-item-show_(names|flags)-(\d+)$/),handleEvent:e=>{if(!e.target.id||e.target.checked)return;const t=e.target.id.match(pllNavMenu.ensureContent.regExpr);if(!t)return;const[,n,a]=t,r="names"===n?"flags":"names";document.getElementById(`edit-menu-item-show_${r}-${a}`).checked=!0}},showHideRows:{regExpr:new RegExp(/^edit-menu-item-dropdown-(\d+)$/),handleEvent:e=>{if(!e.target.id)return;const t=e.target.id.match(pllNavMenu.showHideRows.regExpr);if(!t)return;const n=document.getElementById(`edit-menu-item-hide_current-${t[1]}`);if(!n)return;n.closest(".description").classList.toggle("hidden",e.target.checked),e.target.checked&&(n.checked=!1,n.dispatchEvent(new Event("change")))}}};pllNavMenu.init();
--------------------------------------------------------------------------------
/modules/Machine_Translation/css/machine-translation-settings.css:
--------------------------------------------------------------------------------
1 | .pll-settings .pll-inner-notice {
2 | margin: 5px 0 15px;
3 | border: 1px solid #c3c4c7;
4 | border-left-width: 4px;
5 | padding: 1px 12px;
6 | background: #fff;
7 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
8 | }
9 |
10 | .form-table .pll-inner-notice {
11 | margin-bottom: 5px;
12 | }
13 |
14 | .pll-settings .notice-success {
15 | border-left-color: #00a32a;
16 | }
17 |
18 | .pll-settings .notice-warning {
19 | border-left-color: #dba617;
20 | }
21 |
22 | .pll-settings .notice-error {
23 | border-left-color: #d63638;
24 | }
25 |
26 | .pll-settings .pll-inner-notice p {
27 | margin: 0.5em 0;
28 | padding: 2px;
29 | }
30 |
31 | .pll-settings .pll-message:not(.pll-origin-message),
32 | .pll-settings .notice-success .pll-origin-message,
33 | .pll-settings .notice-warning .pll-origin-message,
34 | .pll-settings .notice-error .pll-origin-message {
35 | display: none;
36 | }
37 |
38 | .pll-settings .notice-success .pll-success-message,
39 | .pll-settings .notice-warning .pll-warning-message.pll-message-shown,
40 | .pll-settings .notice-error .pll-error-message.pll-message-shown {
41 | display: block;
42 | }
43 |
44 | .pll-settings [disabled] + .spinner,
45 | .pll-progress-bar-wrapper .spinner {
46 | visibility: visible;
47 | }
48 |
49 | .pll-success-message .pll-icon {
50 | color: rgb(18, 91, 145);
51 | }
52 |
53 | .pll-error-message .pll-icon,
54 | .pll-warning-message .pll-icon {
55 | color: rgb(145, 30, 31);
56 | }
57 |
58 | .pll-icon {
59 | font-size: 1.8em;
60 | margin-right: 3px;
61 | margin-left: 1px;
62 | vertical-align: -2px;
63 | }
64 |
65 | .pll-progress-bar-wrapper {
66 | position: relative;
67 | max-width: 500px;
68 | height: 2em;
69 | line-height: 2em;
70 | vertical-align: middle;
71 | text-align: left;
72 | font-size: 2em;
73 | border: 1px solid rgb(64, 70, 72);
74 | border-radius: 4px;
75 | overflow: hidden;
76 | white-space: nowrap;
77 | color: rgb(23, 114, 181);
78 | text-indent: 1em;
79 | }
80 |
81 | .pll-progress-bar-wrapper div {
82 | position: absolute;
83 | height: 100%;
84 | top: 0;
85 | left: 0;
86 | overflow: hidden;
87 | background-color: rgb(23, 114, 181);
88 | color: rgb(232, 230, 227);
89 | }
90 |
91 | .pll-settings [type="password"] + .button {
92 | margin-left: 20px;
93 | margin-right: 0;
94 | }
95 |
96 | .pll-settings [type="password"] + .button + .spinner {
97 | float: none;
98 | }
99 |
100 | .pll-progress-bar-wrapper .spinner {
101 | float: none;
102 | margin: 0;
103 | }
104 |
--------------------------------------------------------------------------------
/modules/share-slug/settings-share-slug.php:
--------------------------------------------------------------------------------
1 | 'none' ) );
21 |
22 | if ( get_option( 'permalink_structure' ) ) {
23 | add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) );
24 | }
25 | }
26 |
27 | /**
28 | * Returns the module description.
29 | *
30 | * @since 3.1
31 | *
32 | * @return string
33 | */
34 | protected function get_description() {
35 | return parent::get_description() . ' ' . __( 'The module is automatically deactivated when using plain permalinks or when the language is set from the content in the URL modifications.', 'polylang-pro' );
36 | }
37 |
38 | /**
39 | * Tells if the module is active.
40 | *
41 | * @since 1.9
42 | *
43 | * @return bool
44 | */
45 | public function is_active() {
46 | return $this->options['force_lang'] && get_option( 'permalink_structure' );
47 | }
48 |
49 | /**
50 | * Displays the javascript to handle dynamically the change in url modifications
51 | * as sharing slugs is not possible when the language is set from the content
52 | *
53 | * @since 1.9
54 | *
55 | * @return void
56 | */
57 | public function print_js() {
58 | wp_enqueue_script( 'jquery' );
59 |
60 | $activated = sprintf( '%s', $this->action_links['activated'] );
61 | $deactivated = sprintf( '%s', $this->action_links['deactivated'] );
62 |
63 | ?>
64 |
79 |
12 | */
13 | class PLL_Export_Container implements IteratorAggregate, Countable {
14 |
15 | /**
16 | * Name of the class defining an individual export.
17 | *
18 | * @var string
19 | *
20 | * @phpstan-var class-string
21 | */
22 | private $class_name;
23 |
24 | /**
25 | * Contains all the exports.
26 | * Each export is referenced with a key composed of its source and target languages.
27 | *
28 | * @var PLL_Export_Data[]
29 | *
30 | * @phpstan-var array
31 | */
32 | private $exports = array();
33 |
34 | /**
35 | * Constructor.
36 | *
37 | * @since 3.6
38 | *
39 | * @param string $class_name Name of the class that defines an individual export. The class must implement
40 | * the interface `PLL_Export_Data`.
41 | *
42 | * @phpstan-param class-string $class_name
43 | */
44 | public function __construct( string $class_name ) {
45 | $this->class_name = $class_name;
46 | }
47 |
48 | /**
49 | * Returns an export object for the given source/target languages pair.
50 | *
51 | * @since 3.6
52 | *
53 | * @param PLL_Language $source_language The export's source language.
54 | * @param PLL_Language $target_language The export's target language.
55 | * @return PLL_Export_Data
56 | */
57 | public function get( PLL_Language $source_language, PLL_Language $target_language ): PLL_Export_Data {
58 | $export_key = "{$source_language->slug}/{$target_language->slug}";
59 | $class_name = $this->class_name;
60 |
61 | if ( ! array_key_exists( $export_key, $this->exports ) ) {
62 | $this->exports[ $export_key ] = new $class_name( $source_language, $target_language );
63 | }
64 |
65 | return $this->exports[ $export_key ];
66 | }
67 |
68 | /**
69 | * Returns an exports iterator.
70 | * Needed for the interface `IteratorAggregate`.
71 | *
72 | * @since 3.6
73 | *
74 | * @return ArrayIterator
75 | *
76 | * @phpstan-return ArrayIterator
77 | */
78 | public function getIterator(): ArrayIterator {
79 | return new ArrayIterator( $this->exports );
80 | }
81 |
82 | /**
83 | * Returns the number of exports.
84 | * Needed for the interface `Countable`.
85 | *
86 | * @since 3.6
87 | *
88 | * @return int
89 | */
90 | public function count(): int {
91 | return count( $this->exports );
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/services/metabox-button/toggle-user-meta.php:
--------------------------------------------------------------------------------
1 | meta_name = $meta_name;
30 | }
31 |
32 | /**
33 | * Returns the user meta name storing the enabled/disabled statuses of the action per post type.
34 | *
35 | * @since 3.6
36 | *
37 | * @return string The user meta name.
38 | */
39 | public function get_meta_name(): string {
40 | return $this->meta_name;
41 | }
42 |
43 | /**
44 | * Tells whether the button is active or not.
45 | *
46 | * @since 2.1
47 | *
48 | * @global $post
49 | *
50 | * @return bool
51 | */
52 | public function is_active() {
53 | global $post;
54 | $user_meta = $this->get();
55 | return ! empty( $user_meta[ $post->post_type ] );
56 | }
57 |
58 | /**
59 | * Returns the user meta value.
60 | *
61 | * @since 3.6
62 | *
63 | * @return bool[]
64 | */
65 | public function get() {
66 | $user_meta = get_user_meta( (int) get_current_user_id(), $this->get_meta_name(), true );
67 | return is_array( $user_meta ) ? $user_meta : array();
68 | }
69 |
70 | /**
71 | * Updates the user meta.
72 | *
73 | * @since 3.6
74 | *
75 | * @param bool[] $user_meta An array with post type as key and boolean as value.
76 | * @param WP_User|null $user An instance of `WP_User`.
77 | * @return bool
78 | */
79 | public function update( $user_meta, $user = null ) {
80 | if ( ! $user instanceof WP_User ) {
81 | $user = wp_get_current_user();
82 | }
83 |
84 | return (bool) update_user_meta( (int) $user->ID, $this->get_meta_name(), $user_meta );
85 | }
86 |
87 | /**
88 | * Saves the button state.
89 | *
90 | * @since 2.1
91 | *
92 | * @param string $post_type Current post type.
93 | * @param bool $active New requested button state.
94 | * @return bool Whether the new button state is accepted or not.
95 | */
96 | public function toggle_option( $post_type, $active ) {
97 | $user_meta = $this->get();
98 | $user_meta[ $post_type ] = (bool) $active;
99 |
100 | return $this->update( $user_meta );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/include/Options/Business/Machine_Translation_Services.php:
--------------------------------------------------------------------------------
1 | ,
66 | * additionalProperties: false
67 | * }
68 | */
69 | protected function get_data_structure(): array {
70 | $structure = array(
71 | 'type' => 'object', // Correspond to associative array in PHP, @see{https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#primitive-types}.
72 | 'properties' => array(),
73 | 'additionalProperties' => false,
74 | );
75 |
76 | foreach ( Factory::get_classnames() as $service ) {
77 | $structure['properties'][ $service::get_slug() ] = array(
78 | 'type' => 'object',
79 | 'properties' => $service::get_option_schema(),
80 | 'additionalProperties' => false,
81 | );
82 | }
83 |
84 | return $structure;
85 | }
86 |
87 | /**
88 | * Returns the description used in the JSON schema.
89 | *
90 | * @since 3.7
91 | *
92 | * @return string
93 | */
94 | protected function get_description(): string {
95 | return __( 'Settings for machine translation services: DeepL\'s API key and formality for now.', 'polylang-pro' );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/modules/full-site-editing/fse-language-slug-change.php:
--------------------------------------------------------------------------------
1 | slug === $args['slug'] ) {
59 | // The slug hasn't changed.
60 | return;
61 | }
62 |
63 | /**
64 | * At this point:
65 | * - the language cache has been cleared: `PLL_Model->clean_languages_cache()` is hooked to
66 | * 'edited_term_taxonomy'.
67 | * - `$this->options['default_lang']` has been updated in `PLL_Admin_Model->update_language()`.
68 | */
69 | $def_lang = $this->model->get_default_language();
70 |
71 | if ( empty( $def_lang ) || $def_lang->slug === $args['slug'] ) {
72 | // Templates in the default language don't have the language suffix: nothing to update then.
73 | return;
74 | }
75 |
76 | // At this point, we're modifying the slug of a non-default language.
77 | $this->update_language_suffix_in_post_names( $lang, $args['slug'] );
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/integrations/acf/js/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * WordPress dependencies.
3 | */
4 | import apiFetch from '@wordpress/api-fetch';
5 |
6 | document.addEventListener( 'onPostLangChoice', ( e ) => {
7 | const fields = [];
8 |
9 | // Adds relationship fields to the fields to be refreshed.
10 | const relationshipFields = document.querySelectorAll(
11 | '.acf-field-relationship'
12 | );
13 | relationshipFields.forEach( function ( relationshipField ) {
14 | const field = relationshipField.getAttribute( 'data-key' );
15 | fields.push( field );
16 | } );
17 |
18 | // Adds post object fields to the fields to be refreshed.
19 | const postObjectFields = document.querySelectorAll(
20 | '.acf-field-post-object'
21 | );
22 | postObjectFields.forEach( function ( postObjectField ) {
23 | const field = postObjectField.getAttribute( 'data-key' );
24 | fields.push( field );
25 | } );
26 |
27 | // Adds taxonomy fields to the fields to be refreshed.
28 | const taxonomyFields = document.querySelectorAll( '.acf-field-taxonomy' );
29 | taxonomyFields.forEach( function ( taxonomyField ) {
30 | const field = taxonomyField.getAttribute( 'data-key' );
31 | fields.push( field );
32 | } );
33 |
34 | if ( 0 < fields.length ) {
35 | const postId = document
36 | .getElementById( 'post_ID' )
37 | .getAttribute( 'value' );
38 |
39 | let nonce = document.querySelector( '#_pll_nonce' )?.value; // Classic editor.
40 | if ( undefined === nonce ) {
41 | // Block editor.
42 | nonce = pll_block_editor_plugin_settings.nonce;
43 | }
44 | const data = new FormData();
45 | data.set( 'action', 'acf_post_lang_choice' );
46 | data.set( 'lang', encodeURI( e.detail.lang.slug ) );
47 | data.set( 'fields', fields );
48 | data.set( 'post_id', postId );
49 | data.set( '_pll_nonce', nonce );
50 |
51 | apiFetch( {
52 | url: ajaxurl,
53 | method: 'POST',
54 | body: data,
55 | } ).then( ( response ) => {
56 | response.forEach( function ( res ) {
57 | // Data comes from ACF field and server side.
58 | const field = document.querySelector( '.acf-' + res.field_key );
59 |
60 | field.outerHTML = res.field_data;
61 | acf.do_action(
62 | 'ready_field/type=' + field.getAttribute( 'data-type' ),
63 | field
64 | );
65 | } );
66 |
67 | if ( 0 < relationshipFields.length ) {
68 | // We need to reload the choices list for relationship fields (otherwise it remains empty).
69 | relationshipFields.forEach( function ( relationshipField ) {
70 | acf.getField(
71 | relationshipField.getAttribute( 'data-key' )
72 | ).fetch();
73 | } );
74 | }
75 |
76 | // Reloads the list of posts in `post_object` fields.
77 | acf.getFields( { type: 'post_object' } );
78 | } );
79 | }
80 | } );
81 |
--------------------------------------------------------------------------------
/modules/import-export/export/view-tab-export-strings.php:
--------------------------------------------------------------------------------
1 | get_languages_list();
15 | $default_language = $model->get_default_language();
16 | $strings = PLL_Admin_Strings::get_strings();
17 | $groups = array_unique( wp_list_pluck( $strings, 'context' ) );
18 | $supported_formats = ( new PLL_File_Format_Factory() )->get_supported_formats( 'strings' ); // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
19 | ?>
20 |
21 |
68 |
69 |
--------------------------------------------------------------------------------
/modules/full-site-editing/fse-language.php:
--------------------------------------------------------------------------------
1 | get_site_editor_language();
53 |
54 | if ( empty( $editor_lang ) ) {
55 | return false;
56 | }
57 |
58 | return $editor_lang;
59 | }
60 |
61 | /**
62 | * Returns the language object to use in the site editor.
63 | *
64 | * @since 3.2
65 | * @since 3.5 Removed `$model` parameter.
66 | *
67 | * @return PLL_Language|false
68 | */
69 | private function get_site_editor_language() {
70 | if ( empty( $_GET['postType'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
71 | return $this->model->get_default_language();
72 | }
73 |
74 | $post = null;
75 |
76 | if ( PLL_FSE_Tools::is_template_post_type( sanitize_key( $_GET['postType'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
77 | $post = PLL_FSE_Tools::get_template_post();
78 | } elseif ( ! empty( $_GET['postId'] ) && is_numeric( sanitize_key( $_GET['postId'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
79 | $post = get_post( (int) $_GET['postId'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
80 | }
81 |
82 | if ( empty( $post ) ) {
83 | return $this->model->get_default_language();
84 | }
85 |
86 | $post_lang = $this->model->post->get_language( $post->ID );
87 |
88 | if ( empty( $post_lang ) ) {
89 | return $this->model->get_default_language();
90 | }
91 |
92 | return $post_lang;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/modules/Editors/Screens/Widget.php:
--------------------------------------------------------------------------------
1 | base || parent::can_enqueue_style( $screen );
38 | }
39 |
40 | /**
41 | * Method that allows legacy widgets in widget block editor previously removed by WP and hide legacy Polylang widget.
42 | *
43 | * @since 3.2
44 | *
45 | * @param array $widget_ids An array of hidden widget ids.
46 | * @return array
47 | */
48 | public function filter_legacy_widgets( $widget_ids ) {
49 | $widgets_to_show = array( 'custom_html' );
50 | $widget_ids = array_diff( $widget_ids, $widgets_to_show );
51 |
52 | $widgets_to_hide = array( 'polylang' );
53 | $widget_ids = array_merge( $widget_ids, $widgets_to_hide );
54 |
55 | return $widget_ids;
56 | }
57 |
58 |
59 | /**
60 | * Tells whether the given screen is the Widget edtitor or not.
61 | *
62 | * @since 3.7
63 | *
64 | * @param WP_Screen $screen The current screen.
65 | * @return bool True if Widget editor screen, false otherwise.
66 | */
67 | protected function screen_matches( WP_Screen $screen ): bool {
68 | return (
69 | 'widgets' === $screen->base
70 | && function_exists( 'wp_use_widgets_block_editor' )
71 | && wp_use_widgets_block_editor()
72 | && method_exists( $screen, 'is_block_editor' )
73 | && $screen->is_block_editor()
74 | );
75 | }
76 |
77 | /**
78 | * Returns the language to use in the Widget editor.
79 | *
80 | * @since 3.7
81 | *
82 | * @return PLL_Language|null
83 | */
84 | protected function get_language(): ?PLL_Language {
85 | $language = $this->model->languages->get_default();
86 |
87 | return $language instanceof PLL_Language ? $language : null;
88 | }
89 |
90 | /**
91 | * Returns the screen name for the Widget editor to use across all process.
92 | *
93 | * @since 3.7
94 | *
95 | * @return string
96 | */
97 | protected function get_screen_name(): string {
98 | return 'widget';
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/modules/Machine_Translation/Posts/Button_REST.php:
--------------------------------------------------------------------------------
1 | service = $service;
46 | $this->user_meta = new PLL_Toggle_User_Meta( sprintf( 'pll_machine_translation_%s', $this->service->get_slug() ) );
47 |
48 | register_rest_field(
49 | 'user',
50 | $this->user_meta->get_meta_name(),
51 | array(
52 | 'get_callback' => array( $this->user_meta, 'get' ),
53 | 'update_callback' => array( $this->user_meta, 'update' ),
54 | )
55 | );
56 |
57 | add_filter( 'pll_block_editor_plugin_settings', array( $this, 'get_service_settings' ) );
58 | add_filter( 'pll_block_editor_plugin_settings', array( $this, 'get_settings_errors' ) );
59 | }
60 |
61 | /**
62 | * Adds service properties in UI settings.
63 | *
64 | * @since 3.6
65 | *
66 | * @param array $settings UI settings.
67 | * @return array Updated UI settings.
68 | */
69 | public function get_service_settings( $settings ) {
70 | $settings['machine_translation'] = array(
71 | 'slug' => $this->service::get_slug(),
72 | 'name' => $this->service->get_name(),
73 | 'icon' => $this->service->get_icon_properties(),
74 | 'isActive' => $this->service->is_active(),
75 | );
76 | return $settings;
77 | }
78 |
79 | /**
80 | * Adds machine translation errors in UI settings.
81 | *
82 | * @since 3.6
83 | *
84 | * @param array $settings UI settings.
85 | * @return array Updated UI settings.
86 | */
87 | public function get_settings_errors( $settings ) {
88 | $settings_errors = get_settings_errors( 'polylang' );
89 |
90 | if ( empty( $settings_errors ) ) {
91 | return $settings;
92 | }
93 |
94 | $settings['machine_translation']['errors'] = $settings_errors;
95 |
96 | return $settings;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/modules/Editors/Screens/Site.php:
--------------------------------------------------------------------------------
1 | curlang = &$polylang->curlang;
34 | }
35 |
36 | /**
37 | * Adds required hooks.
38 | *
39 | * @since 3.7
40 | *
41 | * @return static
42 | */
43 | public function init() {
44 | parent::init();
45 | add_filter( 'pll_admin_ajax_params', array( $this, 'ajax_filter' ) );
46 |
47 | return $this;
48 | }
49 |
50 | /**
51 | * Adds the language to the data added to all AJAX requests.
52 | *
53 | * @since 3.7
54 | *
55 | * @param array $params List of parameters to add to the admin ajax request.
56 | * @return array
57 | */
58 | public function ajax_filter( $params ) {
59 | $screen = get_current_screen();
60 |
61 | if ( empty( $screen ) ) {
62 | return $params;
63 | }
64 |
65 | if ( ! $this->screen_matches( $screen ) ) {
66 | return $params;
67 | }
68 |
69 | $editor_lang = $this->get_language();
70 |
71 | if ( empty( $editor_lang ) ) {
72 | return $params;
73 | }
74 |
75 | $params['lang'] = $editor_lang->slug;
76 | return $params;
77 | }
78 |
79 |
80 | /**
81 | * Tells whether the given screen is the Site edtitor or not.
82 | *
83 | * @since 3.7
84 | *
85 | * @param WP_Screen $screen The current screen.
86 | * @return bool True if Site editor screen, false otherwise.
87 | */
88 | protected function screen_matches( WP_Screen $screen ): bool {
89 | return (
90 | 'site-editor' === $screen->base
91 | && $this->model->post_types->is_translated( 'wp_template_part' )
92 | && method_exists( $screen, 'is_block_editor' )
93 | && $screen->is_block_editor()
94 | );
95 | }
96 |
97 | /**
98 | * Returns the language to use in the Site editor.
99 | *
100 | * @since 3.7
101 | *
102 | * @return PLL_Language|null
103 | */
104 | protected function get_language(): ?PLL_Language {
105 | if ( ! empty( $this->curlang ) && PLL_FSE_Tools::is_site_editor() ) {
106 | return $this->curlang;
107 | }
108 |
109 | return null;
110 | }
111 |
112 | /**
113 | * Returns the screen name for the Site editor to use across all process.
114 | *
115 | * @since 3.7
116 | *
117 | * @return string
118 | */
119 | protected function get_screen_name(): string {
120 | return 'site';
121 | }
122 | }
123 |
--------------------------------------------------------------------------------