Plugin Directory

Changeset 3042028 for polylang


Ignore:
Timestamp:
02/27/2024 03:23:17 PM (2 years ago)
Author:
Chouby
Message:

Version 3.6-beta1

Location:
polylang/trunk
Files:
3 added
99 edited

Legend:

Unmodified
Added
Removed
  • polylang/trunk/admin/admin-base.php

    r2974283 r3042028  
    329329                                        /*
    330330                                         * In some cases data could be a JSON string like in third party plugins.
    331                                          * So we need not to break their process by adding polylang parameters as valid JSON datas.
     331                                         * So we need not to break their process by adding polylang parameters as valid JSON data.
    332332                                         */
    333333                                        try {
  • polylang/trunk/admin/admin-filters-columns.php

    r2974283 r3042028  
    307307        // Link to edit term ( or a translation )
    308308        if ( ( $id = $this->model->term->get( $term_id, $language ) ) && $term = get_term( $id, $taxonomy ) ) {
    309             if ( $link = get_edit_term_link( $id, $taxonomy, $post_type ) ) {
     309            if ( $term instanceof WP_Term && $link = get_edit_term_link( $id, $taxonomy, $post_type ) ) {
    310310                $flag = '';
    311311                if ( $id === $term_id ) {
     
    423423        foreach ( $translations as $term_id ) {
    424424            $level = is_taxonomy_hierarchical( $taxonomy ) ? count( get_ancestors( $term_id, $taxonomy ) ) : 0;
    425             if ( $tag = get_term( $term_id, $taxonomy ) ) {
    426                 ob_start();
    427                 $wp_list_table->single_row( $tag, $level );
    428                 $data = ob_get_clean();
    429                 $x->add( array( 'what' => 'row', 'data' => $data, 'supplemental' => array( 'term_id' => $term_id ) ) );
     425            $tag   = get_term( $term_id, $taxonomy );
     426
     427            if ( ! $tag instanceof WP_Term ) {
     428                continue;
    430429            }
     430
     431            ob_start();
     432            $wp_list_table->single_row( $tag, $level );
     433            $data = ob_get_clean();
     434            $x->add( array( 'what' => 'row', 'data' => $data, 'supplemental' => array( 'term_id' => $term_id ) ) );
    431435        }
    432436
     
    435439
    436440    /**
    437      * Returns the language flag or teh language slug if there is no flag.
     441     * Returns the language flag or the language slug if there is no flag.
    438442     *
    439443     * @since 2.8
  • polylang/trunk/admin/admin-filters-term.php

    r2974283 r3042028  
    303303
    304304                $this->model->term->set_language( $term_id, $language );
    305                 $term = get_term( $term_id, $taxonomy );
     305                $term  = get_term( $term_id, $taxonomy );
     306                $terms = array();
    306307
    307308                // Get all terms with the same name
     
    310311                // $terms = get_terms( $taxonomy, array( 'name' => $term->name, 'hide_empty' => false, 'fields' => 'ids' ) ); should be OK in 4.2
    311312                // I may need to rework the loop below
    312                 $terms = $wpdb->get_results(
    313                     $wpdb->prepare(
    314                         "SELECT t.term_id FROM $wpdb->terms AS t
    315                         INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
    316                         WHERE tt.taxonomy = %s AND t.name = %s",
    317                         $taxonomy,
    318                         $term->name
    319                     )
    320                 );
     313                if ( $term instanceof WP_Term ) {
     314                    $terms = $wpdb->get_results(
     315                        $wpdb->prepare(
     316                            "SELECT t.term_id FROM $wpdb->terms AS t
     317                            INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
     318                            WHERE tt.taxonomy = %s AND t.name = %s",
     319                            $taxonomy,
     320                            $term->name
     321                        )
     322                    );
     323                }
    321324
    322325                // If we have several terms with the same name, they are translations of each other
     
    332335            }
    333336
    334             else {
    335                 if ( current_user_can( 'edit_term', $term_id ) ) {
    336                     $this->model->term->set_language( $term_id, $this->model->get_language( sanitize_key( $_GET['inline_lang_choice'] ) ) );
    337                 }
     337            elseif ( current_user_can( 'edit_term', $term_id ) ) {
     338                $this->model->term->set_language( $term_id, $this->model->get_language( sanitize_key( $_GET['inline_lang_choice'] ) ) );
    338339            }
    339340        }
     
    478479                }
    479480
    480                 if ( $tag_cloud = wp_tag_cloud( $args ) ) {
     481                $tag_cloud = wp_tag_cloud( $args );
     482
     483                if ( ! empty( $tag_cloud ) ) {
     484                    /** @phpstan-var non-falsy-string $tag_cloud */
    481485                    $html = sprintf( '<div class="tagcloud"><h2>%1$s</h2>%2$s</div>', esc_html( $tax->labels->popular_items ), $tag_cloud );
    482486                    $x->Add( array( 'what' => 'tag_cloud', 'data' => $html ) );
     
    559563            $return[] = array(
    560564                'id'    => $term->term_id,
    561                 'value' => rtrim( $parents_list, ' >' ), // Trim the seperator added at the end by WP.
     565                'value' => rtrim( $parents_list, ' >' ), // Trim the separator added at the end by WP.
    562566                'link'  => $this->links->edit_term_translation_link( $term->term_id, $term->taxonomy, $post_type ),
    563567            );
     
    603607            }
    604608            else {
    605                 $tr_term       = get_term( $tr_id, $taxonomy );
     609                $tr_term = get_term( $tr_id, $taxonomy );
     610
     611                if ( ! $tr_term instanceof WP_Term ) {
     612                    continue;
     613                }
     614
    606615                $split_term_id = _split_shared_term( $tr_id, $tr_term->term_taxonomy_id );
    607616
  • polylang/trunk/admin/admin-filters-widgets-options.php

    r2557081 r3042028  
    3232        }
    3333    }
    34 
    3534}
  • polylang/trunk/admin/admin-model.php

    r2907847 r3042028  
    133133
    134134        // Delete users options
    135         foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
    136             delete_user_meta( $user_id, 'pll_filter_content', $lang->slug );
    137             delete_user_meta( $user_id, 'description_' . $lang->slug );
    138         }
     135        delete_metadata( 'user', 0, 'pll_filter_content', '', true );
     136        delete_metadata( 'user', 0, "description_{$lang->slug}", '', true );
    139137
    140138        // Delete domain
     
    269267         *   @type string $flag           Optional, country code, @see flags.php.
    270268         * }
    271          * @param PLL_Language $lang Previous value of the language beeing edited.
     269         * @param PLL_Language $lang Previous value of the language being edited.
    272270         */
    273271        do_action( 'pll_update_language', $args, $lang );
     
    315313        /**
    316314         * Allow to add data to store for a language.
    317          * `$locale`, `$rtl`, and `$flag_code` cannot be overwriten.
     315         * `$locale`, `$rtl`, and `$flag_code` cannot be overwritten.
    318316         *
    319317         * @since 3.4
     
    346344        $new_data = array_merge( $old_data, $add_data, $new_data );
    347345
    348         /** @var non-empty-string $serialized maybe_serialize() cannot return anything else than a string when feeded by an array. */
     346        /** @var non-empty-string $serialized maybe_serialize() cannot return anything else than a string when fed by an array. */
    349347        $serialized = maybe_serialize( $new_data );
    350348        return $serialized;
  • polylang/trunk/admin/admin-nav-menu.php

    r2974283 r3042028  
    195195     */
    196196    public function pre_update_option_theme_mods( $mods ) {
    197         if ( current_user_can( 'edit_theme_options' ) && isset( $mods['nav_menu_locations'] ) ) {
     197        if ( current_user_can( 'edit_theme_options' ) && is_array( $mods ) && isset( $mods['nav_menu_locations'] ) ) {
    198198
    199199            // Manage Locations tab in Appearance -> Menus
  • polylang/trunk/admin/view-translations-media.php

    r2340428 r3042028  
    99if ( ! defined( 'ABSPATH' ) ) {
    1010    exit; // Don't access directly
    11 };
     11}
    1212?>
    1313<p><strong><?php esc_html_e( 'Translations', 'polylang' ); ?></strong></p>
  • polylang/trunk/admin/view-translations-post.php

    r2549758 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111?>
    1212<p><strong><?php esc_html_e( 'Translations', 'polylang' ); ?></strong></p>
  • polylang/trunk/admin/view-translations-term.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212if ( isset( $term_id ) ) {
  • polylang/trunk/changelog.txt

    r3008143 r3042028  
    5757* Pro: Fix deactivated language re-activated when it is edited.
    5858* Pro: Fix language switcher in legacy widget menu not correctly rendered in widget block editor
    59 * Pro: Fix error 404 for untranslated attached attachement
     59* Pro: Fix error 404 for untranslated attached attachment
    6060* Pro: Fix a deprecated notice in ACF integration
    6161* Pro: Fix update compatibility with WP Umbrella
     
    7070* Fix a PHP warning `Attempt to read property "home_url" on bool` #1206
    7171* Fix a conflict leading to a performance issue when translating the theme Astra options #1196
    72 * Fix related translations resetted when updating Yoast SEO titles settings #1111
     72* Fix related translations reset when updating Yoast SEO titles settings #1111
    7373* Fix a fatal error in case the registered strings option is corrupted #1264
    7474* Fix the language extraction from the URL in plain permalinks #1270
     
    168168* Pro: Fix a fatal error when inserting a term
    169169* Pro: Fix translation of the block cover when duplicating a post
    170 * Pro: Fix a CSS issue in bulk tranlate form introduced by WP 6.0
     170* Pro: Fix a CSS issue in bulk translate form introduced by WP 6.0
    171171* Pro: Fix a CSS issue in string import/export metaboxes.
    172172* Prevent random languages order in WP 6.0 #1041
     
    176176= 3.2.2 (2022-04-25) =
    177177
    178 * Pro: Fix redirect occuring for tags sharing the same slug as their translations
     178* Pro: Fix redirect occurring for tags sharing the same slug as their translations
    179179* Fix quick edit allowing to modify the language of the default category when it should not #1018
    180180
     
    183183* Pro: Fix users with editor role not able to save or publish posts
    184184* Pro: Fix FSE compatibility not loaded when the plugin Gütenberg is active
    185 * Pro: Fix a fatal error occuring with Yoast SEO Premium
     185* Pro: Fix a fatal error occurring with Yoast SEO Premium
    186186* Pro: Fix a fatal error with ACF when no language is defined
    187187
     
    211211* Fix some PHP 8.1 deprecations #949 #985
    212212* Fix a fatal error in PHP 8.1 #987
    213 * Fix category feed not redirected when the langage code is wrong #887
     213* Fix category feed not redirected when the language code is wrong #887
    214214* Fix default category not created for secondary languages (introduced in 3.1) #997
    215215* Fix parent page when the parent post type is not translatable #1001
     
    229229* Fix empty search not handled correctly. Props Dominik Schilling #937
    230230* Fix warning occurring when a 3rd party plugin attempts to register anything else than a string using the WPML API #942
    231 * Fix Yoast SEO columns not corectly drawn when quick editing a post #943
     231* Fix Yoast SEO columns not correctly drawn when quick editing a post #943
    232232
    233233= 3.1.2 (2021-10-11) =
     
    235235* Pro: Fix parent page not filtered by language in the block editor since WP 5.6
    236236* Pro: Fix XLIFF mime type for PHP 7.0 and PHP 7.1
    237 * Fix settings page displaying the media modules whne no language are defined
     237* Fix settings page displaying the media modules when no language are defined
    238238* Enforce Yoast SEO to use dynamic permalinks #882
    239239* Yoast SEO: Fix static front page and blog page breadcrumb
     
    256256* Add a warning section to the site health for posts and terms without languages #825
    257257* Require the simplexml extension in the site health if a wpml-config.xml is found #827
    258 * Remove the information about the WPML compabitility mode in settings #843
     258* Remove the information about the WPML compatibility mode in settings #843
    259259* The browser preferred language detection is now deactivated by default
    260260* The media are now untranslated by default
     
    328328* Improve browser language detection #591
    329329* Improve robustness and documentation of code
    330 * Fix media library after the language has been chnaged in the editor metabox
     330* Fix media library after the language has been changed in the editor metabox
    331331* Fix duplicated title attribute on flag link in posts list
    332332* Fix legacy block editor language metabox compatibility with WordPress 5.6
     
    406406* Pro: Fix fatal error with WP 4.9
    407407* Fix pll_the_languages() with 'raw' option returning html flag instead of flag url #558
    408 * Fix compatibility with Duplicate Posts not correcly loaded #557
     408* Fix compatibility with Duplicate Posts not correctly loaded #557
    409409* Fix custom flag size in admin bar language switcher #559
    410410* Fix tag clouds mixed in the classic editor #561
     
    495495* Allow to translate the Twenty Seventeen header video Youtube url #460
    496496* Notices are now dismissed per site instead of per user #478
    497 * Fix terms not visible in the quick edit when only one language is defined and teh admin language filter is active
     497* Fix terms not visible in the quick edit when only one language is defined and the admin language filter is active
    498498* Fix post state not displayed for translations of the privacy policy page #395
    499499* Fix wildcards not correctly interpreted in wpml-config.xml
     
    588588* Pro: Fix PHP warning with ACF Pro 5.8.1
    589589* Pro: Fix ACF clone fields not translated in repeaters
    590 * Better management of user capablities when synchronizing taxonomies terms and custom fields
     590* Better management of user capabilities when synchronizing taxonomies terms and custom fields
    591591* Extend string translations search to translated strings #207
    592592* Update plugin updater to 1.6.18
     
    10181018* Pro: Fix shared term slugs broken by a late change in WP 4.7 #73
    10191019* Pro: Fix media taxonomies lost when creating a media translation when taxonomies sync is activated #72
    1020 * Fix fatal error in customizer when Twenty Seventen is activated and another theme is previewed #71
     1020* Fix fatal error in customizer when Twenty Seventeen is activated and another theme is previewed #71
    10211021* Fix wrong plugin language on admin if user locale is different from site locale in WP 4.7
    10221022
  • polylang/trunk/frontend/canonical.php

    r2802032 r3042028  
    247247     */
    248248    protected function redirect_canonical( $url, $language ) {
     249        /**
     250         * @var WP_Query
     251         */
    249252        global $wp_query;
    250253
  • polylang/trunk/frontend/frontend-filters-links.php

    r2974283 r3042028  
    1919     * Our internal non persistent cache object
    2020     *
    21      * @var PLL_Cache
     21     * @var PLL_Cache<string>
    2222     */
    2323    public $cache;
  • polylang/trunk/frontend/frontend-filters-widgets.php

    r2974283 r3042028  
    1313     * Internal non persistent cache object.
    1414     *
    15      * @var PLL_Cache
     15     * @var PLL_Cache<array>
    1616     */
    1717    public $cache;
     
    5555        }
    5656
    57         $cache_key         = md5( maybe_serialize( $sidebars_widgets ) );
    58         $_sidebars_widgets = $this->cache->get( "sidebars_widgets_{$cache_key}" );
     57        $cache_key         = $this->cache->get_unique_key( 'sidebars_widgets_', $sidebars_widgets );
     58        $_sidebars_widgets = $this->cache->get( $cache_key );
    5959
    6060        if ( false !== $_sidebars_widgets ) {
     
    6464        $sidebars_widgets = $this->filter_widgets_sidebars( $sidebars_widgets, $wp_registered_widgets );
    6565
    66         $this->cache->set( "sidebars_widgets_{$cache_key}", $sidebars_widgets );
    67 
    68         return $sidebars_widgets;
     66        return $this->cache->set( $cache_key, $sidebars_widgets );
    6967    }
    7068
  • polylang/trunk/frontend/frontend-links.php

    r2974283 r3042028  
    1414     * Internal non persistent cache object.
    1515     *
    16      * @var PLL_Cache
     16     * @var PLL_Cache<string>
    1717     */
    1818    public $cache;
     
    3030        $this->curlang = &$polylang->curlang;
    3131        $this->cache = new PLL_Cache();
    32 
    3332    }
    3433
     
    9089                                if ( $term_id && $term_id = $this->model->term->get_translation( $term_id, $language ) ) { // Get the translated term_id
    9190                                    $term = get_term( $term_id, $tax->name );
     91
     92                                    if ( ! $term instanceof WP_Term ) {
     93                                        continue;
     94                                    }
     95
    9296                                    $url = str_replace( $slug, $term->slug, $url );
    9397                                }
     
    108112
    109113                elseif ( $tr_id = $this->model->term->get_translation( $term->term_id, $language ) ) {
    110                     if ( $tr_term = get_term( $tr_id, $term->taxonomy ) ) {
     114                    $tr_term = get_term( $tr_id, $term->taxonomy );
     115                    if ( $tr_term instanceof WP_Term ) {
    111116                        // Check if translated term ( or children ) have posts
    112117                        $count = $tr_term->count || ( is_taxonomy_hierarchical( $term->taxonomy ) && array_sum( wp_list_pluck( get_terms( array( 'taxonomy' => $term->taxonomy, 'child_of' => $tr_term->term_id, 'lang' => $language->slug ) ), 'count' ) ) );
     
    171176         * @param string      $language The language code of the translation
    172177         */
    173         $translation_url = apply_filters( 'pll_translation_url', $url, $language->slug );
     178        $translation_url = (string) apply_filters( 'pll_translation_url', $url, $language->slug );
    174179
    175180        // Don't cache before template_redirect to avoid a conflict with Barrel + WP Bakery Page Builder
  • polylang/trunk/frontend/frontend-nav-menu.php

    r3008143 r3042028  
    125125                    $item->menu_order += $offset;
    126126                    $new_items[] = $item;
    127                     $offset++;
     127                    ++$offset;
    128128                }
    129129
    130130                $i = 0; // for incrementation of menu order only in case of dropdown
    131131                foreach ( $the_languages as $lang ) {
    132                     $i++;
     132                    ++$i;
    133133                    $lang_item = clone $item;
    134134                    $lang_item->ID = $lang_item->ID . '-' . $lang['slug']; // A unique ID
     
    146146                    }
    147147                    $new_items[] = $lang_item;
    148                     $offset++;
    149                 }
    150                 $offset--;
     148                    ++$offset;
     149                }
     150                --$offset;
    151151            } else {
    152152                $item->menu_order += $offset;
  • polylang/trunk/frontend/frontend-static-pages.php

    r2974283 r3042028  
    227227     */
    228228    public function page_for_posts_query( $lang, $query ) {
    229         if ( empty( $lang ) && $this->page_for_posts ) {
    230             $page_id = $this->get_page_id( $query );
    231 
    232             if ( ! empty( $page_id ) && in_array( $page_id, $pages = $this->model->get_languages_list( array( 'fields' => 'page_for_posts' ) ) ) ) {
    233                 // Fill the cache with all pages for posts to avoid one query per page later
    234                 // The posts_per_page limit is a trick to avoid splitting the query
    235                 get_posts( array( 'posts_per_page' => 99, 'post_type' => 'page', 'post__in' => $pages, 'lang' => '' ) );
    236 
    237                 $lang = $this->model->post->get_language( $page_id );
    238                 $query->is_singular = $query->is_page = false;
    239                 $query->is_home = $query->is_posts_page = true;
    240             }
    241         }
     229        if ( ! empty( $lang ) || ! $this->page_for_posts ) {
     230            return $lang;
     231        }
     232
     233        $page_id = $this->get_page_id( $query );
     234
     235        if ( empty( $page_id ) ) {
     236            return $lang;
     237        }
     238
     239        $pages = $this->model->get_languages_list( array( 'fields' => 'page_for_posts' ) );
     240        $pages = array_filter( $pages );
     241
     242        if ( in_array( $page_id, $pages ) ) {
     243            _prime_post_caches( $pages ); // Fill the cache with all pages for posts to avoid one query per page later.
     244
     245            $lang = $this->model->post->get_language( $page_id );
     246            $query->is_singular = $query->is_page = false;
     247            $query->is_home = $query->is_posts_page = true;
     248        }
     249
    242250        return $lang;
    243251    }
  • polylang/trunk/include/base.php

    r3008143 r3042028  
    163163     * @return bool
    164164     */
    165     protected function is_active_on_current_site() : bool {
     165    protected function is_active_on_current_site(): bool {
    166166        return pll_is_plugin_active( POLYLANG_BASENAME ) && get_option( 'polylang' );
    167167    }
     
    206206        $floor = 0;
    207207        if ( ! empty( $this->nav_menu ) && (bool) $wp_filter['customize_register']->has_filter( 'customize_register', array( $this->nav_menu, 'create_nav_menu_locations' ) ) ) {
    208             $floor++;
     208            ++$floor;
    209209        }
    210210
    211211        if ( ! empty( $this->static_pages ) && (bool) $wp_filter['customize_register']->has_filter( 'customize_register', array( $this->static_pages, 'filter_customizer' ) ) ) {
    212             $floor++;
     212            ++$floor;
    213213        }
    214214
  • polylang/trunk/include/cache.php

    r2974283 r3042028  
    88 *
    99 * @since 1.7
     10 *
     11 * @template TCacheData
    1012 */
    1113class PLL_Cache {
     
    2123     *
    2224     * @var array
     25     *
     26     * @phpstan-var array<int, array<non-empty-string, TCacheData>>
    2327     */
    2428    protected $cache = array();
     
    4751
    4852    /**
    49      * Add a value in cache.
     53     * Adds a value in cache.
    5054     *
    5155     * @since 1.7
     56     * @since 3.6 Returns the cached value.
    5257     *
    5358     * @param string $key  Cache key.
    5459     * @param mixed  $data The value to add to the cache.
    55      * @return void
     60     * @return mixed
     61     *
     62     * @phpstan-param non-empty-string $key
     63     * @phpstan-param TCacheData $data
     64     * @phpstan-return TCacheData
    5665     */
    5766    public function set( $key, $data ) {
    58         $this->cache[ $this->blog_id ][ $key ] = $data;
     67        if ( ! doing_action( 'switch_blog' ) ) {
     68            $this->cache[ $this->blog_id ][ $key ] = $data;
     69        }
     70        return $data;
    5971    }
    6072
    6173    /**
    62      * Get value from cache.
     74     * Returns value from cache.
    6375     *
    6476     * @since 1.7
     
    6678     * @param string $key Cache key.
    6779     * @return mixed
     80     *
     81     * @phpstan-param non-empty-string $key
     82     * @phpstan-return TCacheData|false
    6883     */
    6984    public function get( $key ) {
     
    7287
    7388    /**
    74      * Clean the cache (for this blog only).
     89     * Cleans the cache (for this blog only).
    7590     *
    7691     * @since 1.7
    7792     *
    78      * @param string $key Cache key.
     93     * @param string $key Optional. Cache key. An empty string to clean the whole cache for the current blog.
     94     *                    Default is an empty string.
    7995     * @return void
    8096     */
    8197    public function clean( $key = '' ) {
    82         if ( empty( $key ) ) {
     98        if ( '' === $key ) {
    8399            unset( $this->cache[ $this->blog_id ] );
    84100        } else {
     
    86102        }
    87103    }
     104
     105    /**
     106     * Generates and returns a "unique" cache key, depending on `$data` and prefixed by `$prefix`.
     107     *
     108     * @since 3.6
     109     *
     110     * @param string              $prefix String to prefix the cache key.
     111     * @param string|array|object $data   Data.
     112     * @return string
     113     *
     114     * @phpstan-param non-empty-string $prefix
     115     * @phpstan-return non-empty-string
     116     */
     117    public function get_unique_key( string $prefix, $data ): string {
     118        /** @var scalar */
     119        $serialized = maybe_serialize( $data );
     120        return $prefix . md5( (string) $serialized );
     121    }
    88122}
  • polylang/trunk/include/class-polylang.php

    r2974283 r3042028  
    66if ( ! defined( 'ABSPATH' ) ) {
    77    exit; // Don't access directly
    8 };
     8}
    99
    1010// Default directory to store user data such as custom flags
     
    2222 *
    2323 * @since 0.1
     24 *
     25 * @template TPLLClass of PLL_Base
    2426 */
    2527class Polylang {
     
    163165     */
    164166    public function init() {
    165         global $polylang;
    166 
    167167        self::define_constants();
    168168        $options = get_option( 'polylang' );
     
    225225
    226226        if ( ! empty( $class ) ) {
    227             $links_model = $model->get_links_model();
    228             $polylang    = new $class( $links_model );
    229 
    230             /**
    231              * Fires after Polylang's model init.
    232              * This is the best place to register a custom table (see `PLL_Model`'s constructor).
    233              * /!\ This hook is fired *before* the $polylang object is available.
    234              * /!\ The languages are also not available yet.
    235              *
    236              * @since 3.4
    237              *
    238              * @param PLL_Model $model Polylang model.
    239              */
    240             do_action( 'pll_model_init', $model );
    241 
    242             $model->maybe_create_language_terms();
    243 
    244             /**
    245              * Fires after the $polylang object is created and before the API is loaded
    246              *
    247              * @since 2.0
    248              *
    249              * @param object $polylang
    250              */
    251             do_action_ref_array( 'pll_pre_init', array( &$polylang ) );
    252 
    253             require_once __DIR__ . '/api.php'; // Loads the API
    254 
    255             // Loads the modules.
    256             $load_scripts = glob( POLYLANG_DIR . '/modules/*/load.php', GLOB_NOSORT );
    257             if ( is_array( $load_scripts ) ) {
    258                 foreach ( $load_scripts as $load_script ) {
    259                     require_once $load_script; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
    260                 }
     227            /** @phpstan-var class-string<TPLLClass> $class */
     228            $this->init_context( $class, $model );
     229        }
     230    }
     231
     232    /**
     233     * Polylang initialization.
     234     * Setups the Polylang Context, loads the modules and init Polylang.
     235     *
     236     * @since 3.6
     237     *
     238     * @param string    $class The class name.
     239     * @param PLL_Model $model Instance of PLL_Model.
     240     * @return PLL_Base
     241     *
     242     * @phpstan-param class-string<TPLLClass> $class
     243     * @phpstan-return TPLLClass
     244     */
     245    public function init_context( string $class, PLL_Model $model ): PLL_Base {
     246        global $polylang;
     247
     248        $links_model = $model->get_links_model();
     249        $polylang    = new $class( $links_model );
     250
     251        /**
     252         * Fires after Polylang's model init.
     253         * This is the best place to register a custom table (see `PLL_Model`'s constructor).
     254         * /!\ This hook is fired *before* the $polylang object is available.
     255         * /!\ The languages are also not available yet.
     256         *
     257         * @since 3.4
     258         *
     259         * @param PLL_Model $model Polylang model.
     260         */
     261        do_action( 'pll_model_init', $model );
     262
     263        $model->maybe_create_language_terms();
     264
     265        /**
     266         * Fires after the $polylang object is created and before the API is loaded
     267         *
     268         * @since 2.0
     269         *
     270         * @param object $polylang
     271         */
     272        do_action_ref_array( 'pll_pre_init', array( &$polylang ) );
     273
     274        // Loads the API
     275        require_once POLYLANG_DIR . '/include/api.php';
     276
     277        // Loads the modules.
     278        $load_scripts = glob( POLYLANG_DIR . '/modules/*/load.php', GLOB_NOSORT );
     279        if ( is_array( $load_scripts ) ) {
     280            foreach ( $load_scripts as $load_script ) {
     281                require_once $load_script; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
    261282            }
    262 
    263             $polylang->init();
    264 
    265             /**
    266              * Fires after the $polylang object and the API is loaded
    267              *
    268              * @since 1.7
    269              *
    270              * @param object $polylang
    271              */
    272             do_action_ref_array( 'pll_init', array( &$polylang ) );
    273         }
    274     }
    275 }
     283        }
     284
     285        $polylang->init();
     286
     287        /**
     288         * Fires after the $polylang object and the API is loaded
     289         *
     290         * @since 1.7
     291         *
     292         * @param object $polylang
     293         */
     294        do_action_ref_array( 'pll_init', array( &$polylang ) );
     295
     296        return $polylang;
     297    }
     298}
  • polylang/trunk/include/crud-posts.php

    r3032046 r3042028  
    228228    /**
    229229     * Called when a post, page or media is deleted
    230      * Don't delete translations if this is a post revision thanks to AndyDeGroo who catched this bug
     230     * Don't delete translations if this is a post revision thanks to AndyDeGroo who caught this bug
    231231     * http://wordpress.org/support/topic/plugin-polylang-quick-edit-still-breaks-translation-linking-of-pages-in-072
    232232     *
  • polylang/trunk/include/filters-links.php

    r2974283 r3042028  
    201201    }
    202202}
    203 
  • polylang/trunk/include/filters-widgets-options.php

    r2974283 r3042028  
    4949        $dropdown_html = $dropdown->walk(
    5050            array_merge(
    51                 array( (object) array('slug' => 0, 'name' => __( 'All languages', 'polylang' )) ),
     51                array( (object) array( 'slug' => 0, 'name' => __( 'All languages', 'polylang' ) ) ),
    5252                $this->model->get_languages_list()
    5353            ),
     
    9090        return $instance;
    9191    }
    92 
    9392}
  • polylang/trunk/include/language.php

    r3008143 r3042028  
    232232     * @var array[] Array keys are language term names.
    233233     *
    234      * @exemple array(
     234     * @example array(
    235235     *     'language'       => array(
    236236     *         'term_id'          => 7,
     
    352352
    353353    /**
    354      * Returns the flag informations.
     354     * Returns the flag information.
    355355     *
    356356     * @since 2.6
     
    358358     * @param string $code Flag code.
    359359     * @return array {
    360      *   Flag informations.
     360     *   Flag information.
    361361     *
    362362     *   @type string $url    Flag url.
     
    392392
    393393        /**
    394          * Filters flag informations:
     394         * Filters flag information:
    395395         *
    396396         * @since 2.4
  • polylang/trunk/include/license.php

    r2974283 r3042028  
    8585        $this->api_url = empty( $api_url ) ? $this->api_url : $api_url;
    8686
    87         $licenses = get_option( 'polylang_licenses' );
    88         $this->license_key = empty( $licenses[ $this->id ]['key'] ) ? '' : $licenses[ $this->id ]['key'];
    89         if ( ! empty( $licenses[ $this->id ]['data'] ) ) {
    90             $this->license_data = $licenses[ $this->id ]['data'];
     87        $licenses          = (array) get_option( 'polylang_licenses', array() );
     88        $license           = isset( $licenses[ $this->id ] ) && is_array( $licenses[ $this->id ] ) ? $licenses[ $this->id ] : array();
     89        $this->license_key = ! empty( $license['key'] ) ? (string) $license['key'] : '';
     90
     91        if ( ! empty( $license['data'] ) ) {
     92            $this->license_data = (object) $license['data'];
    9193        }
    9294
     
    223225            // Save new license info
    224226            $licenses[ $this->id ] = array( 'key' => $this->license_key );
    225             $data = json_decode( wp_remote_retrieve_body( $response ) );
    226 
    227             if ( 'deactivated' !== $data->license ) {
     227            $data = (object) json_decode( wp_remote_retrieve_body( $response ) );
     228
     229            if ( isset( $data->license ) && 'deactivated' !== $data->license ) {
    228230                $licenses[ $this->id ]['data'] = $this->license_data = $data;
    229231            }
  • polylang/trunk/include/links-domain.php

    r2907847 r3042028  
    106106
    107107            // The function idn_to_ascii() is much faster than the WordPress method.
    108             if ( function_exists( 'idn_to_ascii' ) ) {
    109                 // The use of the constant is mandatory in PHP 7.2 and PHP 7.3 to avoid a deprecated notice.
    110                 $hosts[ $lang ] = defined( 'INTL_IDNA_VARIANT_UTS46' ) ? idn_to_ascii( $host, 0, INTL_IDNA_VARIANT_UTS46 ) : idn_to_ascii( $host );
     108            if ( function_exists( 'idn_to_ascii' ) && defined( 'INTL_IDNA_VARIANT_UTS46' ) ) {
     109                $hosts[ $lang ] = idn_to_ascii( $host, 0, INTL_IDNA_VARIANT_UTS46 );
    111110            } elseif ( class_exists( 'WpOrg\Requests\IdnaEncoder' ) ) {
    112111                // Since WP 6.2.
  • polylang/trunk/include/model.php

    r2974283 r3042028  
    1313     * Internal non persistent cache object.
    1414     *
    15      * @var PLL_Cache
     15     * @var PLL_Cache<mixed>
    1616     */
    1717    public $cache;
     
    187187        $languages = array_filter(
    188188            $languages,
    189             function( $lang ) use ( $args ) {
     189            function ( $lang ) use ( $args ) {
    190190                $keep_empty   = empty( $args['hide_empty'] ) || $lang->get_tax_prop( 'language', 'count' );
    191191                $keep_default = empty( $args['hide_default'] ) || ! $lang->is_default;
    192192                return $keep_empty && $keep_default;
    193 
    194193            }
    195194        );
     
    587586        }
    588587
    589         $cache_key = 'pll_count_posts_' . md5( maybe_serialize( $q ) );
    590         $counts = wp_cache_get( $cache_key, 'counts' );
     588        $cache_key = $this->cache->get_unique_key( 'pll_count_posts_', $q );
     589        $counts    = wp_cache_get( $cache_key, 'counts' );
    591590
    592591        if ( ! is_array( $counts ) ) {
     
    811810         * Keep track of types where we set the language:
    812811         * those are types where we may have more items to process if we have more than 1000 items in total.
    813          * This will prevent unecessary SQL queries in the next recursion: if we have 0 items in this recursion for
     812         * This will prevent unnecessary SQL queries in the next recursion: if we have 0 items in this recursion for
    814813         * a type, we'll still have 0 in the next one, no need for a new query.
    815814         */
     
    918917     * @param PLL_Language|null $language   Optional. A language object. Required to update the existing terms.
    919918     * @param string[]          $taxonomies Optional. List of language taxonomies to deal with. An empty value means
    920      *                                      all of them. Defauls to all taxonomies.
     919     *                                      all of them. Defaults to all taxonomies.
    921920     * @return void
    922921     *
  • polylang/trunk/include/rest-request.php

    r2907847 r3042028  
    55
    66/**
    7  * Main Polylang class for REST API requrests, accessible from @see PLL().
     7 * Main Polylang class for REST API requests, accessible from @see PLL().
    88 *
    99 * @since 2.6
  • polylang/trunk/include/translatable-object.php

    r2925389 r3042028  
    370370    /**
    371371     * Returns object IDs without language given a specific SQL query.
    372      * Can be overriden by child classes in case queried object doesn't use
     372     * Can be overridden by child classes in case queried object doesn't use
    373373     * `wp_cache_set_last_changed()` or another cache system.
    374374     *
     
    501501
    502502    /**
    503      * Returns database-related informations that can be used in some of this class methods.
     503     * Returns database-related information that can be used in some of this class methods.
    504504     * These are specific to the table containing the objects.
    505505     *
  • polylang/trunk/include/translate-option.php

    r2974283 r3042028  
    4141     * Cache for the translated values.
    4242     *
    43      * @var PLL_Cache
     43     * @var PLL_Cache<array|string>
    4444     */
    4545    private $cache;
     
    111111        $lang = $GLOBALS['l10n']['pll_string']->get_header( 'Language' );
    112112
     113        if ( ! is_string( $lang ) || '' === $lang ) {
     114            return $value;
     115        }
     116
    113117        $cache = $this->cache->get( $lang );
    114118        if ( false === $cache ) {
  • polylang/trunk/include/translated-post.php

    r2925389 r3042028  
    1414 */
    1515class PLL_Translated_Post extends PLL_Translated_Object implements PLL_Translatable_Object_With_Types_Interface {
    16 
    1716    use PLL_Translatable_Object_With_Types_Trait;
    1817
     
    146145             * @param bool     $is_settings True when displaying the list of custom post types in Polylang settings.
    147146             */
    148             $post_types = apply_filters( 'pll_get_post_types', $post_types, false );
     147            $post_types = (array) apply_filters( 'pll_get_post_types', $post_types, false );
    149148
    150149            if ( did_action( 'after_setup_theme' ) ) {
     
    376375
    377376    /**
    378      * Returns database-related informations that can be used in some of this class methods.
     377     * Returns database-related information that can be used in some of this class methods.
    379378     * These are specific to the table containing the objects.
    380379     *
  • polylang/trunk/include/translated-term.php

    r2925389 r3042028  
    1414 */
    1515class PLL_Translated_Term extends PLL_Translated_Object implements PLL_Translatable_Object_With_Types_Interface {
    16 
    1716    use PLL_Translatable_Object_With_Types_Trait;
    1817
     
    214213             * @param bool     $is_settings True when displaying the list of custom taxonomies in Polylang settings.
    215214             */
    216             $taxonomies = apply_filters( 'pll_get_taxonomies', $taxonomies, false );
     215            $taxonomies = (array) apply_filters( 'pll_get_taxonomies', $taxonomies, false );
    217216
    218217            if ( did_action( 'after_setup_theme' ) ) {
     
    316315
    317316    /**
    318      * Returns database-related informations that can be used in some of this class methods.
     317     * Returns database-related information that can be used in some of this class methods.
    319318     * These are specific to the table containing the objects.
    320319     *
  • polylang/trunk/install/install-base.php

    r2974283 r3042028  
    55
    66/**
    7  * A generic activation / de-activation class compatble with multisite
     7 * A generic activation / de-activation class compatible with multisite
    88 *
    99 * @since 1.7
     
    4040     * @since 1.7
    4141     *
    42      * @return bool true if the plugin is currently beeing deactivated
     42     * @return bool true if the plugin is currently being deactivated
    4343     */
    4444    public function is_deactivation() {
     
    9393     */
    9494    protected function _activate() {
    95         // Can be overriden in child class
     95        // Can be overridden in child class
    9696    }
    9797
     
    116116     */
    117117    protected function _deactivate() {
    118         // Can be overriden in child class
     118        // Can be overridden in child class
    119119    }
    120120
  • polylang/trunk/install/plugin-updater.php

    r2699056 r3042028  
    396396
    397397    /**
    398      * Calls the API and, if successfull, returns the object delivered by the API.
     398     * Calls the API and, if successful, returns the object delivered by the API.
    399399     *
    400400     * @uses get_bloginfo()
  • polylang/trunk/integrations/aqua-resizer/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212PLL_Integrations::instance()->aq_resizer = new PLL_Aqua_Resizer();
  • polylang/trunk/integrations/cache/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( pll_is_cache_active() ) {
    1616            add_action( 'pll_init', array( PLL_Integrations::instance()->cache_compat = new PLL_Cache_Compat(), 'init' ) );
     
    1919    0
    2020);
    21 
  • polylang/trunk/integrations/custom-field-template/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( class_exists( 'custom_field_template' ) ) {
    1616            PLL_Integrations::instance()->cft = new PLL_Cft();
  • polylang/trunk/integrations/domain-mapping/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212PLL_Integrations::instance()->dm = new PLL_Domain_Mapping();
  • polylang/trunk/integrations/duplicate-post/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( defined( 'DUPLICATE_POST_CURRENT_VERSION' ) ) {
    1616            PLL_Integrations::instance()->duplicate_post = new PLL_Duplicate_Post();
  • polylang/trunk/integrations/jetpack/load.php

    r2340428 r3042028  
    99if ( ! defined( 'ABSPATH' ) ) {
    1010    exit; // Don't access directly.
    11 };
     11}
    1212
    1313PLL_Integrations::instance()->jetpack = new PLL_Jetpack(); // Must be loaded before the plugin is active.
  • polylang/trunk/integrations/no-category-base/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212PLL_Integrations::instance()->no_category_base = new PLL_No_Category_Base();
  • polylang/trunk/integrations/twenty-seventeen/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action( 'init', array( PLL_Integrations::instance()->twenty_seventeen = new PLL_Twenty_Seventeen(), 'init' ) );
  • polylang/trunk/integrations/wp-importer/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212PLL_Integrations::instance()->wp_importer = new PLL_WordPress_Importer();
  • polylang/trunk/integrations/wp-importer/wordpress-importer.php

    r2340428 r3042028  
    4343
    4444        $GLOBALS['wp_import'] = new PLL_WP_Import();
    45         register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'polylang' ), array( $GLOBALS['wp_import'], 'dispatch' ) ); // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled
     45        register_importer( 'wordpress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'polylang' ), array( $GLOBALS['wp_import'], 'dispatch' ) ); // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText
    4646    }
    4747
  • polylang/trunk/integrations/wp-offload-media/as3cf.php

    r2802032 r3042028  
    5757     * Deletes the WP Offload Media information from the attachment being deleted.
    5858     * That way WP Offload Media won't delete the file stored in the cloud.
    59      * Done after Polylang has deleted the translations informations, to avoid the synchronization of the deletion
     59     * Done after Polylang has deleted the translations information, to avoid the synchronization of the deletion
    6060     * and of course before WP Offload Media deletes the file, normally at priority 20.
    6161     *
  • polylang/trunk/integrations/wp-offload-media/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( function_exists( 'as3cf_init' ) && class_exists( 'PLL_AS3CF' ) ) {
    1616            add_action( 'pll_init', array( PLL_Integrations::instance()->as3cf = new PLL_AS3CF(), 'init' ) );
     
    1919    0
    2020);
    21 
  • polylang/trunk/integrations/wp-sweep/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( defined( 'WP_SWEEP_VERSION' ) ) {
    1616            PLL_Integrations::instance()->wp_sweep = new PLL_WP_Sweep();
  • polylang/trunk/integrations/wpseo/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( defined( 'WPSEO_VERSION' ) ) {
    1616            add_action( 'pll_init', array( PLL_Integrations::instance()->wpseo = new PLL_WPSEO(), 'init' ) );
     
    1919    0
    2020);
    21 
  • polylang/trunk/integrations/wpseo/wpseo-ogp.php

    r2340428 r3042028  
    5353    }
    5454}
    55 
  • polylang/trunk/integrations/wpseo/wpseo.php

    r2974283 r3042028  
    201201
    202202    /**
    203      * Add filters before the sitemap is evaluated and outputed.
     203     * Add filters before the sitemap is evaluated and outputted.
    204204     *
    205205     * @since 2.6
     
    423423     * @param string[] $keys List of custom fields names.
    424424     * @param bool     $sync True if it is synchronization, false if it is a copy.
    425      * @param int      $from Id of the post from which we copy informations.
    426      * @param int      $to   Id of the post to which we paste informations.
     425     * @param int      $from Id of the post from which we copy information.
     426     * @param int      $to   Id of the post to which we paste information.
    427427     * @return array
    428428     */
  • polylang/trunk/integrations/yarpp/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212add_action(
    1313    'plugins_loaded',
    14     function() {
     14    function () {
    1515        if ( defined( 'YARPP_VERSION' ) ) {
    1616            add_action( 'init', array( PLL_Integrations::instance()->yarpp = new PLL_Yarpp(), 'init' ) );
  • polylang/trunk/modules/share-slug/load.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212if ( $polylang->model->has_languages() ) {
    1313    add_filter(
    1414        'pll_settings_modules',
    15         function( $modules ) {
     15        function ( $modules ) {
    1616            $modules[] = 'PLL_Settings_Preview_Share_Slug';
    1717            return $modules;
  • polylang/trunk/modules/share-slug/settings-preview-share-slug.php

    r2557081 r3042028  
    2323     * @since 1.9
    2424     *
    25      * @param object $polylang Polylang object.
     25     * @param PLL_Settings $polylang Polylang object.
     26     * @param array        $args     Optional. Addition arguments.
     27     *
     28     * @phpstan-param array{
     29     *   module?: non-falsy-string,
     30     *   title?: string,
     31     *   description?: string,
     32     *   active_option?: non-falsy-string
     33     * } $args
    2634     */
    27     public function __construct( &$polylang ) {
    28         parent::__construct(
    29             $polylang,
    30             array(
    31                 'module'      => 'share-slugs',
    32                 'title'       => __( 'Share slugs', 'polylang' ),
    33                 'description' => $this->get_description(),
    34             )
     35    public function __construct( &$polylang, array $args = array() ) {
     36        $default = array(
     37            'module'        => 'share-slugs',
     38            'title'         => __( 'Share slugs', 'polylang' ),
     39            'description'   => $this->get_description(),
     40            'active_option' => 'preview',
    3541        );
     42
     43        parent::__construct( $polylang, array_merge( $default, $args ) );
    3644    }
    3745
     
    4654        return __( 'Allows to share the same URL slug across languages for posts and terms.', 'polylang' );
    4755    }
    48 
    49     /**
    50      * Tells if the module is active.
    51      *
    52      * @since 1.9
    53      *
    54      * @return bool
    55      */
    56     public function is_active() {
    57         return false;
    58     }
    59 
    60     /**
    61      * Displays an upgrade message.
    62      *
    63      * @since 1.9
    64      *
    65      * @return string
    66      */
    67     public function get_upgrade_message() {
    68         return $this->default_upgrade_message();
    69     }
    7056}
  • polylang/trunk/modules/site-health/admin-site-health.php

    r2974283 r3042028  
    4949        add_filter( 'site_status_tests', array( $this, 'status_tests' ) );
    5050        add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health.
    51 
    5251    }
    5352
     
    183182
    184183    /**
    185      * Add Polylang Options to Site Health Informations tab.
     184     * Add Polylang Options to Site Health Information tab.
    186185     *
    187186     * @since 2.8
     
    399398
    400399    /**
    401      * Add Polylang Warnings to Site Health Informations tab.
     400     * Add Polylang Warnings to Site Health Information tab.
    402401     *
    403402     * @since 3.1
  • polylang/trunk/modules/site-health/load.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212if ( $polylang instanceof PLL_Admin && $polylang->model->has_languages() ) {
  • polylang/trunk/modules/sitemaps/load.php

    r2907847 r3042028  
    66if ( ! defined( 'ABSPATH' ) ) {
    77    exit; // Don't access directly.
    8 };
     8}
    99
    1010if ( $polylang->model->has_languages() ) {
  • polylang/trunk/modules/sitemaps/multilingual-sitemaps-provider.php

    r2475716 r3042028  
    110110     *
    111111     * @param string $object_subtype_name Object subtype name if any.
    112      * @param string $lang                Optionnal language name.
     112     * @param string $lang                Optional language name.
    113113     * @return array
    114114     */
  • polylang/trunk/modules/sync/admin-sync.php

    r2974283 r3042028  
    4848
    4949    /**
    50      * Copy menu order, comment, ping status and optionally the date when creating a new tanslation
     50     * Copy menu order, comment, ping status and optionally the date when creating a new translation
    5151     *
    5252     * @since 2.5
     
    128128        $postarr = parent::get_fields_to_sync( $post );
    129129
    130         // For new drafts, save the date now otherwise it is overriden by WP. Thanks to JoryHogeveen. See #32.
     130        // For new drafts, save the date now otherwise it is overridden by WP. Thanks to JoryHogeveen. See #32.
    131131        if ( in_array( 'post_date', $this->options['sync'] ) && isset( $GLOBALS['pagenow'], $_GET['from_post'], $_GET['new_lang'] ) && 'post-new.php' === $GLOBALS['pagenow'] ) {
    132132            check_admin_referer( 'new-post-translation' );
  • polylang/trunk/modules/sync/load.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212if ( $polylang->model->has_languages() ) {
     
    1919    add_filter(
    2020        'pll_settings_modules',
    21         function( $modules ) {
     21        function ( $modules ) {
    2222            $modules[] = 'PLL_Settings_Sync';
    2323            return $modules;
  • polylang/trunk/modules/sync/sync-metas.php

    r2974283 r3042028  
    143143     * @since 2.3
    144144     *
    145      * @param int    $from Id of the post from which we copy informations.
    146      * @param int    $to   Id of the post to which we paste informations.
     145     * @param int    $from Id of the post from which we copy information.
     146     * @param int    $to   Id of the post to which we paste information.
    147147     * @param string $lang Language slug.
    148148     * @param bool   $sync True if it is synchronization, false if it is a copy.
     
    158158         * @param string[] $keys List of custom fields names.
    159159         * @param bool     $sync True if it is synchronization, false if it is a copy.
    160          * @param int      $from Id of the post from which we copy informations.
    161          * @param int      $to   Id of the post to which we paste informations.
     160         * @param int      $from Id of the post from which we copy information.
     161         * @param int      $to   Id of the post to which we paste information.
    162162         * @param string   $lang Language slug.
    163163         */
     
    350350        $this->remove_all_meta_actions();
    351351
    352         $to_copy = $this->get_metas_to_copy( $from, $to, $lang, $sync );
    353         $metas = get_metadata( $this->meta_type, $from );
     352        $to_copy  = $this->get_metas_to_copy( $from, $to, $lang, $sync );
     353        $metas    = get_metadata( $this->meta_type, $from );
     354        $metas    = is_array( $metas ) ? $metas : array();
    354355        $tr_metas = get_metadata( $this->meta_type, $to );
     356        $tr_metas = is_array( $tr_metas ) ? $tr_metas : array();
    355357
    356358        foreach ( $to_copy as $key ) {
     
    360362                    delete_metadata( $this->meta_type, $to, wp_slash( $key ) );
    361363                }
     364            } elseif ( ! empty( $tr_metas[ $key ] ) && 1 === count( $metas[ $key ] ) && 1 === count( $tr_metas[ $key ] ) ) {
     365                // One custom field to update
     366                $value = reset( $metas[ $key ] );
     367                $value = maybe_unserialize( $value );
     368                $to_value = $this->maybe_translate_value( $value, $key, $from, $to, $lang );
     369                update_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) );
    362370            } else {
    363                 if ( ! empty( $tr_metas[ $key ] ) && 1 === count( $metas[ $key ] ) && 1 === count( $tr_metas[ $key ] ) ) {
    364                     // One custom field to update
    365                     $value = reset( $metas[ $key ] );
     371                // Multiple custom fields, either in the source or the target
     372                if ( ! empty( $tr_metas[ $key ] ) ) {
     373                    // The synchronization of multiple values custom fields is easier if we delete all metas first
     374                    delete_metadata( $this->meta_type, $to, wp_slash( $key ) );
     375                }
     376
     377                foreach ( $metas[ $key ] as $value ) {
    366378                    $value = maybe_unserialize( $value );
    367379                    $to_value = $this->maybe_translate_value( $value, $key, $from, $to, $lang );
    368                     update_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) );
    369                 } else {
    370                     // Multiple custom fields, either in the source or the target
    371                     if ( ! empty( $tr_metas[ $key ] ) ) {
    372                         // The synchronization of multiple values custom fields is easier if we delete all metas first
    373                         delete_metadata( $this->meta_type, $to, wp_slash( $key ) );
    374                     }
    375 
    376                     foreach ( $metas[ $key ] as $value ) {
    377                         $value = maybe_unserialize( $value );
    378                         $to_value = $this->maybe_translate_value( $value, $key, $from, $to, $lang );
    379                         add_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) );
    380                     }
     380                    add_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) );
    381381                }
    382382            }
  • polylang/trunk/modules/sync/sync-post-metas.php

    r2974283 r3042028  
    3939     * @since 2.3
    4040     *
    41      * @param int    $from Id of the post from which we copy informations.
    42      * @param int    $to   Id of the post to which we paste informations.
     41     * @param int    $from Id of the post from which we copy information.
     42     * @param int    $to   Id of the post to which we paste information.
    4343     * @param string $lang Language slug.
    4444     * @param bool   $sync True if it is synchronization, false if it is a copy.
  • polylang/trunk/modules/sync/sync-tax.php

    r2974283 r3042028  
    55
    66/**
    7  * A class to manage the sychronization of taxonomy terms across posts translations
     7 * A class to manage the synchronization of taxonomy terms across posts translations
    88 *
    99 * @since 2.3
     
    4848     *
    4949     * @param bool   $sync True if it is synchronization, false if it is a copy.
    50      * @param int    $from Id of the post from which we copy informations, optional, defaults to null.
    51      * @param int    $to   Id of the post to which we paste informations, optional, defaults to null.
     50     * @param int    $from Id of the post from which we copy information, optional, defaults to null.
     51     * @param int    $to   Id of the post to which we paste information, optional, defaults to null.
    5252     * @param string $lang Language slug, optional, defaults to null.
    5353     * @return string[] List of taxonomy names.
     
    6767         * @param string[] $taxonomies List of taxonomy names.
    6868         * @param bool     $sync       True if it is synchronization, false if it is a copy.
    69          * @param int      $from       Id of the post from which we copy informations.
    70          * @param int      $to         Id of the post to which we paste informations.
     69         * @param int      $from       Id of the post from which we copy information.
     70         * @param int      $to         Id of the post to which we paste information.
    7171         * @param string   $lang       Language slug.
    7272         */
     
    150150            wp_set_object_terms( $tr_id, $newterms, $taxonomy, $append );
    151151        }
    152 
    153152    }
    154153
     
    202201
    203202    /**
    204      * Copy terms fron one post to a translation, does not sync
     203     * Copy terms from one post to a translation, does not sync
    205204     *
    206205     * @since 2.3
  • polylang/trunk/modules/sync/sync.php

    r2974283 r3042028  
    169169                    unset( $tr_arr['post_parent'] );
    170170
    171                     // Do not udpate the translation parent if the user set a parent with no translation.
     171                    // Do not update the translation parent if the user set a parent with no translation.
    172172                    if ( isset( $postarr['post_parent'] ) ) {
    173173                        $post_parent = $postarr['post_parent'] ? $this->model->post->get_translation( $postarr['post_parent'], $lang ) : 0;
  • polylang/trunk/modules/translate-slugs/load.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212if ( $polylang->model->has_languages() ) {
    1313    add_filter(
    1414        'pll_settings_modules',
    15         function( $modules ) {
     15        function ( $modules ) {
    1616            $modules[] = 'PLL_Settings_Preview_Translate_Slugs';
    1717            return $modules;
  • polylang/trunk/modules/translate-slugs/settings-preview-translate-slugs.php

    r2557081 r3042028  
    2323     * @since 1.9
    2424     *
    25      * @param object $polylang Polylang object.
     25     * @param PLL_Settings $polylang Polylang object.
     26     * @param array        $args     Optional. Addition arguments.
     27     *
     28     * @phpstan-param array{
     29     *   module?: non-falsy-string,
     30     *   title?: string,
     31     *   description?: string,
     32     *   active_option?: non-falsy-string
     33     * } $args
    2634     */
    27     public function __construct( &$polylang ) {
    28         parent::__construct(
    29             $polylang,
    30             array(
    31                 'module'      => 'translate-slugs',
    32                 'title'       => __( 'Translate slugs', 'polylang' ),
    33                 'description' => $this->get_description(),
    34             )
     35    public function __construct( &$polylang, array $args = array() ) {
     36        $default = array(
     37            'module'        => 'translate-slugs',
     38            'title'         => __( 'Translate slugs', 'polylang' ),
     39            'description'   => $this->get_description(),
     40            'active_option' => 'preview',
    3541        );
     42
     43        parent::__construct( $polylang, array_merge( $default, $args ) );
    3644    }
    3745
     
    4654        return __( 'Allows to translate custom post types and taxonomies slugs in URLs.', 'polylang' );
    4755    }
    48 
    49     /**
    50      * Tells if the module is active.
    51      *
    52      * @since 1.9
    53      *
    54      * @return bool
    55      */
    56     public function is_active() {
    57         return false;
    58     }
    59 
    60     /**
    61      * Displays an upgrade message.
    62      *
    63      * @since 1.9
    64      *
    65      * @return string
    66      */
    67     public function get_upgrade_message() {
    68         return $this->default_upgrade_message();
    69     }
    7056}
  • polylang/trunk/modules/wizard/html-wizard-notice.php

    r2340428 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$wizard_url = add_query_arg(
  • polylang/trunk/modules/wizard/js/languages-step.js

    r2544117 r3042028  
    44
    55jQuery(
    6     function( $ ) {
     6    function ( $ ) {
    77        var addLanguageForm = $( '.languages-step' ); // Form element.
    88        var languageFields = $( '#language-fields' ); // Element where to append hidden fields for creating language.
     
    3636                )
    3737            );
    38             // see the comment and the harcoded code above. languageTrashIconHtml and languageValueHtml are safe.
     38            // see the comment and the hardcoded code above. languageTrashIconHtml and languageValueHtml are safe.
    3939            var languageLineHtml = $( '<tr />' ).prepend( languageTrashIconHtml ).prepend( languageValueHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
    4040            var languageFieldHtml = $( '<input />' ).attr(
     
    5656                'click',
    5757                'span[data-language=' + language.locale + ']',
    58                 function( event ) {
     58                function ( event ) {
    5959                    event.preventDefault();
    6060                    // Remove line in languages table.
     
    8585        function showError( message ) {
    8686            messagesContainer.empty();
    87             // html is harcoded and use of jQuery text method which is safe to add message value.
     87            // html is hardcoded and use of jQuery text method which is safe to add message value.
    8888            // In addition message is i18n value which is initialized server side in PLL_Wizard::add_step_languages and correctly escaped.
    8989            messagesContainer.prepend( $( '<p/>' ).addClass( 'error' ).text( message ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
     
    140140        languagesList.on(
    141141            'selectmenuchange',
    142             function() {
     142            function () {
    143143                hideError();;
    144144            }
     
    149149        $( '#add-language' ).on(
    150150            'click',
    151             function( event ) {
     151            function ( event ) {
    152152                hideError();
    153153                var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex];
     
    183183        addLanguageForm.on(
    184184            'submit',
    185             function( event ) {
     185            function ( event ) {
    186186                // Verify if there is at least one language.
    187187                var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0;
     
    261261                minWidth: 600,
    262262                maxWidth: '100%',
    263                 open: function( event, ui ) {
     263                open: function ( event, ui ) {
    264264                    // Change dialog box position for rtl language
    265265                    if ( $( 'body' ).hasClass( 'rtl' ) ) {
     
    280280                {
    281281                    text: pll_wizard_params.i18n_dialog_yes_button,
    282                     click: function( event ) {
     282                    click: function ( event ) {
    283283                        confirmDialog( 'yes' );
    284284                    }
     
    286286                {
    287287                    text: pll_wizard_params.i18n_dialog_no_button,
    288                     click: function( event ) {
     288                    click: function ( event ) {
    289289                        confirmDialog( 'no' );
    290290                    }
     
    292292                {
    293293                    text: pll_wizard_params.i18n_dialog_ignore_button,
    294                     click: function( event ) {
     294                    click: function ( event ) {
    295295                        confirmDialog( 'ignore' );
    296296                    }
  • polylang/trunk/modules/wizard/load.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212if ( $polylang instanceof PLL_Admin_Base ) {
  • polylang/trunk/modules/wizard/view-wizard-page.php

    r2974283 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313$admin_body_class = array( 'pll-wizard', 'wp-core-ui' );
    1414if ( is_rtl() ) {
  • polylang/trunk/modules/wizard/view-wizard-step-home-page.php

    r2907847 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$languages = $this->model->get_languages_list();
  • polylang/trunk/modules/wizard/view-wizard-step-languages.php

    r2907847 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$existing_languages = $this->model->get_languages_list();
     
    8383            esc_attr( $lg->locale ),
    8484            esc_html( $lg->name ),
    85             $lg->flag,  // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     85            $lg->flag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    8686            $lg->is_default ? ' <span class="icon-default-lang"><span class="screen-reader-text">' . esc_html__( 'Default language', 'polylang' ) . '</span></span>' : ''
    8787        );
  • polylang/trunk/modules/wizard/view-wizard-step-last.php

    r2340428 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414?>
  • polylang/trunk/modules/wizard/view-wizard-step-licenses.php

    r2340428 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$licenses = apply_filters( 'pll_settings_licenses', array() );
     
    2626</div>
    2727<div class="form-field">
    28     <table id="pll-licenses-table" class="form-table">
     28    <table id="pll-licenses-table" class="form-table pll-table-top">
    2929        <tbody>
    3030        <?php
  • polylang/trunk/modules/wizard/view-wizard-step-media.php

    r2549758 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$default_options = PLL_Install::get_default_options();
  • polylang/trunk/modules/wizard/view-wizard-step-untranslated-contents.php

    r2907847 r3042028  
    1010if ( ! defined( 'ABSPATH' ) ) {
    1111    exit; // Don't access directly.
    12 };
     12}
    1313
    1414$languages_list = $this->model->get_languages_list();
  • polylang/trunk/modules/wizard/wizard.php

    r2974283 r3042028  
    6262
    6363        // Display Wizard page before any other action to ensure displaying it outside the WordPress admin context.
    64         // Hooked on admin_init with priority 40 to ensure PLL_Wizard_Pro is corretly initialized.
     64        // Hooked on admin_init with priority 40 to ensure PLL_Wizard_Pro is correctly initialized.
    6565        add_action( 'admin_init', array( $this, 'setup_wizard_page' ), 40 );
    6666        // Add Wizard submenu.
     
    366366        add_action( 'wp_ajax_pll_deactivate_license', array( $this, 'deactivate_license' ) );
    367367
    368         // Be careful pll_admin script is enqueued here without depedency except jquery because only code useful for deactivate license button is needed.
     368        // Be careful pll_admin script is enqueued here without dependency except jquery because only code useful for deactivate license button is needed.
    369369        // To be really loaded the script need to be passed to the $steps['licenses']['scripts'] array below with the same handle than in wp_enqueue_script().
    370370        wp_enqueue_script( 'pll_admin', plugins_url( '/js/build/admin' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery' ), POLYLANG_VERSION, true );
     
    467467    public function add_step_languages( $steps ) {
    468468        wp_deregister_script( 'pll_admin' ); // Deregister after the licenses step enqueue to update jquery-ui-selectmenu dependency.
    469         // The wp-ajax-response and postbox dependencies is useless in wizard steps espacially postbox which triggers a javascript error otherwise.
     469        // The wp-ajax-response and postbox dependencies is useless in wizard steps especially postbox which triggers a javascript error otherwise.
    470470        // To be really loaded the script need to be passed to the $steps['languages']['scripts'] array below with the same handle than in wp_enqueue_script().
    471471        wp_enqueue_script( 'pll_admin', plugins_url( '/js/build/admin' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
  • polylang/trunk/modules/wpml/load.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly.
    10 };
     10}
    1111
    1212if ( $polylang->model->has_languages() ) {
  • polylang/trunk/modules/wpml/wpml-api.php

    r2907847 r3042028  
    2727    public function __construct() {
    2828        /*
    29          * Site Wide Language informations.
     29         * Site Wide Language information.
    3030         */
    3131        add_filter( 'wpml_active_languages', array( $this, 'wpml_active_languages' ), 10, 2 );
     
    414414     *
    415415     * @param string      $url  The url to filter.
    416      * @param null|string $lang Langage code, optional, defaults to the current language.
     416     * @param null|string $lang Language code, optional, defaults to the current language.
    417417     * @return string
    418418     */
  • polylang/trunk/modules/wpml/wpml-config.php

    r2983561 r3042028  
    1010 *
    1111 * @since 1.0
     12 *
     13 * @phpstan-type ParsedMetas array<
     14 *     non-falsy-string,
     15 *     array{
     16 *         action: string,
     17 *         encoding: 'json'|''
     18 *     }
     19 * >
    1220 */
    1321class PLL_WPML_Config {
     
    4856     */
    4957    private $open_basedir_paths;
     58
     59    /**
     60     * Cache for parsed metas.
     61     *
     62     * @var array
     63     *
     64     * @phpstan-var array<non-falsy-string, ParsedMetas>
     65     */
     66    private $parsed_metas = array();
    5067
    5168    /**
     
    109126        add_filter( 'pll_get_post_types', array( $this, 'translate_types' ), 10, 2 );
    110127        add_filter( 'pll_get_taxonomies', array( $this, 'translate_taxonomies' ), 10, 2 );
    111         add_filter( 'pll_blocks_xpath_rules', array( $this, 'translate_blocks' ) );
    112         add_filter( 'pll_blocks_rules_for_attributes', array( $this, 'translate_blocks_attributes' ) );
    113128
    114129        // Export.
    115130        add_filter( 'pll_post_metas_to_export', array( $this, 'post_metas_to_export' ) );
    116131        add_filter( 'pll_term_metas_to_export', array( $this, 'term_metas_to_export' ) );
     132        add_filter( 'pll_post_meta_encodings', array( $this, 'add_post_meta_encodings' ), 20 );
     133        add_filter( 'pll_term_meta_encodings', array( $this, 'add_term_meta_encodings' ), 20 );
     134        add_filter( 'pll_blocks_xpath_rules', array( $this, 'translate_blocks' ) );
     135        add_filter( 'pll_blocks_rules_for_attributes', array( $this, 'translate_blocks_attributes' ) );
    117136
    118137        foreach ( $this->xmls as $context => $xml ) {
     
    174193
    175194    /**
    176      * Adds custom fields to the list of metas to copy when creating a new translation.
     195     * Adds post metas to the list of metas to copy when creating a new translation.
    177196     *
    178197     * @since 1.0
    179198     *
    180      * @param string[] $metas The list of custom fields to copy or synchronize.
     199     * @param string[] $metas The list of post metas to copy or synchronize.
    181200     * @param bool     $sync  True for sync, false for copy.
    182      * @return string[] The list of custom fields to copy or synchronize.
     201     * @return string[] The list of post metas to copy or synchronize.
     202     *
     203     * @phpstan-param array<non-falsy-string> $metas
    183204     */
    184205    public function copy_post_metas( $metas, $sync ) {
    185         foreach ( $this->xmls as $xml ) {
    186             $cfs = $xml->xpath( 'custom-fields/custom-field' );
    187 
    188             if ( ! is_array( $cfs ) ) {
    189                 continue;
    190             }
    191 
    192             foreach ( $cfs as $cf ) {
    193                 $action = $this->get_field_attribute( $cf, 'action' );
    194 
    195                 if ( 'copy' === $action || ( ! $sync && in_array( $action, array( 'translate', 'copy-once' ), true ) ) ) {
    196                     $metas[] = (string) $cf;
    197                 } else {
    198                     $metas = array_diff( $metas, array( (string) $cf ) );
    199                 }
    200             }
    201         }
    202 
    203         return $metas;
     206        return $this->filter_metas_to_copy( (array) $metas, 'custom-fields/custom-field', (bool) $sync );
    204207    }
    205208
     
    212215     * @param bool     $sync  True for sync, false for copy.
    213216     * @return string[] The list of term metas to copy or synchronize.
     217     *
     218     * @phpstan-param array<non-falsy-string> $metas
    214219     */
    215220    public function copy_term_metas( $metas, $sync ) {
    216         foreach ( $this->xmls as $xml ) {
    217             $cfs = $xml->xpath( 'custom-term-fields/custom-term-field' );
    218 
    219             if ( ! is_array( $cfs ) ) {
    220                 continue;
    221             }
    222 
    223             foreach ( $cfs as $cf ) {
    224                 $action = $this->get_field_attribute( $cf, 'action' );
    225 
    226                 if ( 'copy' === $action || ( ! $sync && in_array( $action, array( 'translate', 'copy-once' ), true ) ) ) {
    227                     $metas[] = (string) $cf;
    228                 } else {
    229                     $metas = array_diff( $metas, array( (string) $cf ) );
    230                 }
    231             }
    232         }
    233 
    234         return $metas;
     221        return $this->filter_metas_to_copy( (array) $metas, 'custom-term-fields/custom-term-field', (bool) $sync );
    235222    }
    236223
     
    256243     * @return array
    257244     *
    258      * @phpstan-param array<string, mixed> $keys
    259      * @phpstan-return array<string, mixed>
     245     * @phpstan-param array<non-falsy-string, mixed> $keys
     246     * @phpstan-return array<non-falsy-string, mixed>
    260247     */
    261248    public function post_metas_to_export( $keys ) {
    262249        // Add keys that have the `action` attribute set to `translate`.
    263         foreach ( $this->xmls as $xml ) {
    264             $fields = $xml->xpath( 'custom-fields/custom-field' );
    265 
    266             if ( ! is_array( $fields ) ) {
    267                 // No custom fields.
    268                 continue;
    269             }
    270 
    271             foreach ( $fields as $field ) {
    272                 $action = $this->get_field_attribute( $field, 'action' );
    273 
    274                 if ( 'translate' !== $action ) {
    275                     continue;
    276                 }
    277 
    278                 $keys[ (string) $field ] = 1;
    279             }
    280         }
     250        $keys = $this->add_metas_to_export( (array) $keys, 'custom-fields/custom-field' );
    281251
    282252        // Deal with sub-field translations.
     
    326296     * @return array
    327297     *
    328      * @phpstan-param array<string, mixed> $keys
    329      * @phpstan-return array<string, mixed>
     298     * @phpstan-param array<non-falsy-string, mixed> $keys
     299     * @phpstan-return array<non-falsy-string, mixed>
    330300     */
    331301    public function term_metas_to_export( $keys ) {
    332302        // Add keys that have the `action` attribute set to `translate`.
    333         foreach ( $this->xmls as $xml ) {
    334             $fields = $xml->xpath( 'custom-term-fields/custom-term-field' );
    335 
    336             if ( ! is_array( $fields ) ) {
    337                 // No custom fields.
    338                 continue;
    339             }
    340 
    341             foreach ( $fields as $field ) {
    342                 $action = $this->get_field_attribute( $field, 'action' );
    343 
    344                 if ( 'translate' !== $action ) {
    345                     continue;
    346                 }
    347 
    348                 $keys[ (string) $field ] = 1;
    349             }
    350         }
    351 
    352         return $keys;
     303        return $this->add_metas_to_export( (array) $keys, 'custom-term-fields/custom-term-field' );
     304    }
     305
     306    /**
     307     * Specifies the encoding for post metas.
     308     *
     309     * @since 3.6
     310     *
     311     * @param string[] $metas An array containing meta names as array keys, and their encoding as array values.
     312     * @return string[]
     313     *
     314     * @phpstan-param array<non-falsy-string, non-falsy-string> $metas
     315     */
     316    public function add_post_meta_encodings( $metas ) {
     317        return $this->add_metas_encodings( (array) $metas, 'custom-fields/custom-field' );
     318    }
     319
     320    /**
     321     * Specifies the encoding for term metas.
     322     *
     323     * @since 3.6
     324     *
     325     * @param string[] $metas An array containing meta names as array keys, and their encoding as array values.
     326     * @return string[]
     327     *
     328     * @phpstan-param array<non-falsy-string, non-falsy-string> $metas
     329     */
     330    public function add_term_meta_encodings( $metas ) {
     331        return $this->add_metas_encodings( (array) $metas, 'custom-term-fields/custom-term-field' );
    353332    }
    354333
     
    850829        return $path;
    851830    }
     831
     832    /**
     833     * Adds (or removes) meta names to the list of metas to copy or synchronize.
     834     *
     835     * @since 3.6
     836     *
     837     * @param string[] $metas The list of meta names to copy or synchronize.
     838     * @param string   $xpath Xpath to the meta fields in the xml files.
     839     * @param bool     $sync  Either sync is enabled or not.
     840     * @return string[]
     841     *
     842     * @phpstan-param array<non-falsy-string> $metas
     843     * @phpstan-param non-falsy-string $xpath
     844     */
     845    private function filter_metas_to_copy( array $metas, string $xpath, bool $sync ): array {
     846        $parsed_metas    = $this->parse_xml_metas( $xpath );
     847        $metas_to_remove = array();
     848
     849        foreach ( $parsed_metas as $name => $parsed_meta ) {
     850            if ( 'copy' === $parsed_meta['action'] || ( ! $sync && in_array( $parsed_meta['action'], array( 'translate', 'copy-once' ), true ) ) ) {
     851                $metas[] = $name;
     852            } else {
     853                $metas_to_remove[] = $name;
     854            }
     855        }
     856
     857        return array_diff( $metas, $metas_to_remove );
     858    }
     859
     860    /**
     861     * Adds meta keys to export.
     862     *
     863     * @since 3.6
     864     *
     865     * @param array  $metas {
     866     *     An array containing meta keys to translate.
     867     *     Ex: array(
     868     *      'meta_to_translate_1' => 1,
     869     *      'meta_to_translate_2' => 1,
     870     *      'meta_to_translate_3' => array( ... ),
     871     *    )
     872     * }
     873     * @param string $xpath  Xpath to the meta fields in the xml files.
     874     * @return array
     875     *
     876     * @phpstan-param array<non-falsy-string, mixed> $metas
     877     * @phpstan-param non-falsy-string $xpath
     878     * @phpstan-return array<non-falsy-string, mixed>
     879     */
     880    private function add_metas_to_export( array $metas, string $xpath ) {
     881        $fields = $this->parse_xml_metas( $xpath );
     882
     883        foreach ( $fields as $name => $field ) {
     884            if ( 'translate' === $field['action'] ) {
     885                $metas[ $name ] = 1;
     886            }
     887        }
     888
     889        return $metas;
     890    }
     891
     892    /**
     893     * Adds encoding of metas.
     894     *
     895     * @since 3.6
     896     *
     897     * @param string[] $metas The list of encodings for each metas. Meta names are array keys, encodings are array values.
     898     * @param string   $xpath Xpath to the meta fields in the xml files.
     899     * @return string[]
     900     *
     901     * @phpstan-param array<non-falsy-string, non-falsy-string> $metas
     902     * @phpstan-param non-falsy-string $xpath
     903     */
     904    private function add_metas_encodings( array $metas, string $xpath ): array {
     905        $parsed_metas = $this->parse_xml_metas( $xpath );
     906
     907        foreach ( $parsed_metas as $name => $parsed_meta ) {
     908            if ( ! empty( $parsed_meta['encoding'] ) ) {
     909                $metas[ $name ] = $parsed_meta['encoding'];
     910            }
     911        }
     912
     913        return $metas;
     914    }
     915
     916    /**
     917     * Parses all xml files for metas.
     918     * Results are cached for each `$xpath`.
     919     *
     920     * @since 3.6
     921     *
     922     * @param string $xpath Xpath to the meta fields in the xml files.
     923     * @return array
     924     *
     925     * @phpstan-param non-falsy-string $xpath
     926     * @phpstan-return ParsedMetas
     927     */
     928    private function parse_xml_metas( string $xpath ): array {
     929        if ( isset( $this->parsed_metas[ $xpath ] ) ) {
     930            return $this->parsed_metas[ $xpath ];
     931        }
     932
     933        $this->parsed_metas[ $xpath ] = array();
     934
     935        foreach ( $this->xmls as $xml ) {
     936            $custom_fields = $xml->xpath( $xpath );
     937
     938            if ( ! is_array( $custom_fields ) ) {
     939                continue;
     940            }
     941
     942            foreach ( $custom_fields as $custom_field ) {
     943                $name = (string) $custom_field;
     944
     945                if ( empty( $name ) ) {
     946                    continue;
     947                }
     948
     949                $data = array(
     950                    'action'   => $this->get_field_attribute( $custom_field, 'action' ),
     951                    'encoding' => $this->get_field_attribute( $custom_field, 'encoding' ),
     952                );
     953
     954                $data['encoding'] = 'json' === $data['encoding'] ? 'json' : ''; // Only JSON is supported for now.
     955
     956                $this->parsed_metas[ $xpath ][ $name ] = $data;
     957            }
     958        }
     959
     960        return $this->parsed_metas[ $xpath ];
     961    }
    852962}
  • polylang/trunk/modules/wpml/wpml-legacy-api.php

    r2802032 r3042028  
    2828     * available only on frontend
    2929     *
    30      * List of paramaters accepted in $args:
     30     * List of parameters accepted in $args:
    3131     *
    3232     * skip_missing  => whether to skip missing translation or not, 0 or 1, defaults to 0
  • polylang/trunk/polylang.php

    r3032046 r3042028  
    1111 * Plugin URI:        https://polylang.pro
    1212 * Description:       Adds multilingual capability to WordPress
    13  * Version:           3.5.4
     13 * Version:           3.6-beta1
    1414 * Requires at least: 5.9
    1515 * Requires PHP:      7.0
     
    4040if ( ! defined( 'ABSPATH' ) ) {
    4141    exit; // Don't access directly.
    42 };
     42}
    4343
    4444if ( defined( 'POLYLANG_VERSION' ) ) {
     
    5454} else {
    5555    // Go on loading the plugin
    56     define( 'POLYLANG_VERSION', '3.5.4' );
     56    define( 'POLYLANG_VERSION', '3.6-beta1' );
    5757    define( 'PLL_MIN_WP_VERSION', '5.9' );
    5858    define( 'PLL_MIN_PHP_VERSION', '7.0' );
  • polylang/trunk/readme.txt

    r3032046 r3042028  
    2828* The language is either set by the language code in URL, or you can use a different sub-domain or domain per language.
    2929* Automatic copy of categories, post tags and other metas when creating a new post or page translation.
    30 * Translating menus and widgets.
    31 * Customizable language switcher available as a widget or a navigation menu item.
     30* Translating classic menus and classic widgets. Also accessible with [Site Editor Classic Features](https://wordpress.org/plugins/fse-classic/) in block themes.
     31* Customizable language switcher available as a classic widget or a classic navigation menu item.
    3232* Compatibility with Yoast SEO.
    3333
     
    6565* [WPML to Polylang](https://wordpress.org/plugins/wpml-to-polylang/) allows migrating from WPML to Polylang.
    6666* [DynaMo](https://wordpress.org/plugins/dynamo/) speeds up the translation of WordPress for all non-English sites.
    67 * [Site Editor Classic Features](https://wordpress.org/plugins/fse-classic/) allows to use legacy widgets (including the Polylang language switcher) and menus in the site editor (FSE).
     67* [Site Editor Classic Features](https://wordpress.org/plugins/fse-classic/) allows to use classic widgets (including the Polylang language switcher) and menus in the site editor (FSE).
    6868
    6969= Credits =
     
    104104
    105105== Changelog ==
     106
     107== 3.6 ==
     108
     109* Add compatibility with WP 6.5
     110* Pro: Add DeepL machine translation for posts and terms
     111* Pro: Add export and import of XLIFF 2.0/2.1
     112* Pro: Allow to export and import JSON encoded post and term metas
     113* Pro: Include footer notes block in translation files
     114* Pro: Single files are now exported directly instead of inside a zip
     115* Pro: Fix a race condition which could lead to display a notice to the wrong user
     116* Fix wrong translated post types and taxononies after a `switch_to_blog()` #1415
     117* Fix a minor performance issue for the page for posts #1412
    106118
    107119= 3.5.4 (2023-02-06) =
  • polylang/trunk/settings/flags.php

    r2340428 r3042028  
    66if ( ! defined( 'ABSPATH' ) ) {
    77    exit; // Don't access directly
    8 };
     8}
    99
    1010/**
  • polylang/trunk/settings/languages.php

    r2939729 r3042028  
    66if ( ! defined( 'ABSPATH' ) ) {
    77    exit; // Don't access directly
    8 };
     8}
    99
    1010/**
     
    8181        'flag'     => 'arab',
    8282        'facebook' => 'ar_AR',
     83        'deepl'    => 'AR',
    8384    ),
    8485    'arg' => array(
     
    99100        'flag'     => 'ma',
    100101        'facebook' => 'ar_AR',
     102        'deepl'    => 'AR',
    101103    ),
    102104    'as' => array(
     
    139141        'flag'     => 'bg',
    140142        'facebook' => 'bg_BG',
     143        'deepl'    => 'BG',
    141144    ),
    142145    'bn_BD' => array(
     
    201204        'flag'     => 'cz',
    202205        'facebook' => 'cs_CZ',
     206        'deepl'    => 'CS',
    203207    ),
    204208    'cy' => array(
     
    217221        'flag'     => 'dk',
    218222        'facebook' => 'da_DK',
     223        'deepl'    => 'DA',
    219224    ),
    220225    'de_AT' => array(
     
    225230        'flag'     => 'at',
    226231        'facebook' => 'de_DE',
     232        'deepl'    => 'DE',
    227233    ),
    228234    'de_CH' => array(
     
    233239        'flag'     => 'ch',
    234240        'facebook' => 'de_DE',
     241        'deepl'    => 'DE',
    235242    ),
    236243    'de_CH_informal' => array(
     
    242249        'w3c'      => 'de-CH',
    243250        'facebook' => 'de_DE',
     251        'deepl'    => 'DE',
    244252    ),
    245253    'de_DE' => array(
     
    250258        'flag'     => 'de',
    251259        'facebook' => 'de_DE',
     260        'deepl'    => 'DE',
    252261    ),
    253262    'de_DE_formal' => array(
     
    259268        'w3c'      => 'de-DE',
    260269        'facebook' => 'de_DE',
     270        'deepl'    => 'DE',
    261271    ),
    262272    'dsb' => array(
     
    282292        'flag'     => 'gr',
    283293        'facebook' => 'el_GR',
     294        'deepl'    => 'EL',
    284295    ),
    285296    'en_AU' => array(
     
    290301        'flag'     => 'au',
    291302        'facebook' => 'en_US',
     303        'deepl'    => 'EN-US',
    292304    ),
    293305    'en_CA' => array(
     
    298310        'flag'     => 'ca',
    299311        'facebook' => 'en_US',
     312        'deepl'    => 'EN-US',
    300313    ),
    301314    'en_GB' => array(
     
    306319        'flag'     => 'gb',
    307320        'facebook' => 'en_GB',
     321        'deepl'    => 'EN-GB',
    308322    ),
    309323    'en_NZ' => array(
     
    314328        'flag'     => 'nz',
    315329        'facebook' => 'en_US',
     330        'deepl'    => 'EN-US',
    316331    ),
    317332    'en_US' => array(
     
    322337        'flag'     => 'us',
    323338        'facebook' => 'en_US',
     339        'deepl'    => 'EN-US',
    324340    ),
    325341    'en_ZA' => array(
     
    330346        'flag'     => 'za',
    331347        'facebook' => 'en_US',
     348        'deepl'    => 'EN-US',
    332349    ),
    333350    'eo' => array(
     
    346363        'flag'     => 'ar',
    347364        'facebook' => 'es_LA',
     365        'deepl'    => 'ES',
    348366    ),
    349367    'es_CL' => array(
     
    354372        'flag'     => 'cl',
    355373        'facebook' => 'es_CL',
     374        'deepl'    => 'ES',
    356375    ),
    357376    'es_CO' => array(
     
    362381        'flag'     => 'co',
    363382        'facebook' => 'es_CO',
     383        'deepl'    => 'ES',
    364384    ),
    365385    'es_CR' => array(
     
    370390        'flag'     => 'cr',
    371391        'facebook' => 'es_LA',
     392        'deepl'    => 'ES',
    372393    ),
    373394    'es_DO' => array(
     
    378399        'flag'     => 'do',
    379400        'facebook' => 'es_LA',
     401        'deepl'    => 'ES',
    380402    ),
    381403    'es_EC' => array(
     
    386408        'flag'     => 'ec',
    387409        'facebook' => 'es_LA',
     410        'deepl'    => 'ES',
    388411    ),
    389412    'es_ES' => array(
     
    394417        'flag'     => 'es',
    395418        'facebook' => 'es_ES',
     419        'deepl'    => 'ES',
    396420    ),
    397421    'es_GT' => array(
     
    402426        'flag'     => 'gt',
    403427        'facebook' => 'es_LA',
     428        'deepl'    => 'ES',
    404429    ),
    405430    'es_MX' => array(
     
    410435        'flag'     => 'mx',
    411436        'facebook' => 'es_MX',
     437        'deepl'    => 'ES',
    412438    ),
    413439    'es_PE' => array(
     
    418444        'flag'     => 'pe',
    419445        'facebook' => 'es_LA',
     446        'deepl'    => 'ES',
    420447    ),
    421448    'es_PR' => array(
     
    426453        'flag'     => 'pr',
    427454        'facebook' => 'es_LA',
     455        'deepl'    => 'ES',
    428456    ),
    429457    'es_UY' => array(
     
    434462        'flag'     => 'uy',
    435463        'facebook' => 'es_LA',
     464        'deepl'    => 'ES',
    436465    ),
    437466    'es_VE' => array(
     
    442471        'flag'     => 've',
    443472        'facebook' => 'es_VE',
     473        'deepl'    => 'ES',
    444474    ),
    445475    'et' => array(
     
    450480        'flag'     => 'ee',
    451481        'facebook' => 'et_EE',
     482        'deepl'    => 'ET',
    452483    ),
    453484    'eu' => array(
     
    482513        'flag'     => 'fi',
    483514        'facebook' => 'fi_FI',
     515        'deepl'    => 'FI',
    484516    ),
    485517    'fo' => array(
     
    498530        'flag'     => 'be',
    499531        'facebook' => 'fr_FR',
     532        'deepl'    => 'FR',
    500533    ),
    501534    'fr_CA' => array(
     
    506539        'flag'     => 'quebec',
    507540        'facebook' => 'fr_CA',
     541        'deepl'    => 'FR',
    508542    ),
    509543    'fr_FR' => array(
     
    514548        'flag'     => 'fr',
    515549        'facebook' => 'fr_FR',
     550        'deepl'    => 'FR',
    516551    ),
    517552    'fuc' => array(
     
    609644        'flag'     => 'hu',
    610645        'facebook' => 'hu_HU',
     646        'deepl'    => 'HU',
    611647    ),
    612648    'hsb' => array(
     
    632668        'flag'     => 'id',
    633669        'facebook' => 'id_ID',
     670        'deepl'    => 'ID',
    634671    ),
    635672    'ido' => array(
     
    651688        'flag'     => 'it',
    652689        'facebook' => 'it_IT',
     690        'deepl'    => 'IT',
    653691    ),
    654692    'ja' => array(
     
    659697        'flag'     => 'jp',
    660698        'facebook' => 'ja_JP',
     699        'deepl'    => 'JA',
    661700    ),
    662701    'jv_ID' => array(
     
    725764        'flag'     => 'kr',
    726765        'facebook' => 'ko_KR',
     766        'deepl'    => 'KO',
    727767    ),
    728768    'ku' => array(
     
    756796        'flag'     => 'lt',
    757797        'facebook' => 'lt_LT',
     798        'deepl'    => 'LT',
    758799    ),
    759800    'lv' => array(
     
    764805        'flag'     => 'lv',
    765806        'facebook' => 'lv_LV',
     807        'deepl'    => 'LV',
    766808    ),
    767809    'mg_MG' => array(
     
    830872        'flag'     => 'no',
    831873        'facebook' => 'nb_NO',
     874        'deepl'    => 'NB',
    832875    ),
    833876    'ne_NP' => array(
     
    846889        'flag'     => 'be',
    847890        'facebook' => 'nl_BE',
     891        'deepl'    => 'NL',
    848892    ),
    849893    'nl_NL' => array(
     
    854898        'flag'     => 'nl',
    855899        'facebook' => 'nl_NL',
     900        'deepl'    => 'NL',
    856901    ),
    857902    'nl_NL_formal' => array(
     
    863908        'w3c'      => 'nl-NL',
    864909        'facebook' => 'nl_NL',
     910        'deepl'    => 'NL',
    865911    ),
    866912    'nn_NO' => array(
     
    898944        'flag'     => 'pl',
    899945        'facebook' => 'pl_PL',
     946        'deepl'    => 'PL',
    900947    ),
    901948    'ps' => array(
     
    914961        'flag'     => 'ao',
    915962        'facebook' => 'pt_PT',
     963        'deepl'    => 'PT-PT',
    916964    ),
    917965    'pt_BR' => array(
     
    922970        'flag'     => 'br',
    923971        'facebook' => 'pt_BR',
     972        'deepl'    => 'PT-BR',
    924973    ),
    925974    'pt_PT' => array(
     
    930979        'flag'     => 'pt',
    931980        'facebook' => 'pt_PT',
     981        'deepl'    => 'PT-PT',
    932982    ),
    933983    'pt_PT_ao90' => array(
     
    938988        'flag'     => 'pt',
    939989        'facebook' => 'pt_PT',
     990        'deepl'    => 'PT-PT',
    940991    ),
    941992    'rhg' => array(
     
    9531004        'flag'     => 'ro',
    9541005        'facebook' => 'ro_RO',
     1006        'deepl'    => 'RO',
    9551007    ),
    9561008    'roh' => array(
     
    9651017        'flag'     => 'ru',
    9661018        'facebook' => 'ru_RU',
     1019        'deepl'    => 'RU',
    9671020    ),
    9681021    'sa_IN' => array(
     
    9911044        'flag'     => 'sk',
    9921045        'facebook' => 'sk_SK',
     1046        'deepl'    => 'SK',
    9931047    ),
    9941048    'skr' => array(
     
    10061060        'flag'     => 'si',
    10071061        'facebook' => 'sl_SI',
     1062        'deepl'    => 'SL',
    10081063    ),
    10091064    'sna' => array(
     
    10601115        'flag'     => 'se',
    10611116        'facebook' => 'sv_SE',
     1117        'deepl'    => 'SV',
    10621118    ),
    10631119    'sw' => array(
     
    11371193        'flag'     => 'tr',
    11381194        'facebook' => 'tr_TR',
     1195        'deepl'    => 'TR',
    11391196    ),
    11401197    'tt_RU' => array(
     
    11671224        'flag'     => 'ua',
    11681225        'facebook' => 'uk_UA',
     1226        'deepl'    => 'UK',
    11691227    ),
    11701228    'ur' => array(
     
    12121270        'flag'     => 'cn',
    12131271        'facebook' => 'zh_CN',
     1272        'deepl'    => 'ZH',
    12141273    ),
    12151274    'zh_HK' => array(
     
    12201279        'flag'     => 'hk',
    12211280        'facebook' => 'zh_HK',
     1281        'deepl'    => 'ZH',
    12221282    ),
    12231283    'zh_TW' => array(
     
    12281288        'flag'     => 'tw',
    12291289        'facebook' => 'zh_TW',
     1290        'deepl'    => 'ZH',
    12301291    ),
    12311292);
  • polylang/trunk/settings/settings-browser.php

    r2974283 r3042028  
    3434                'title'         => __( 'Detect browser language', 'polylang' ),
    3535                'description'   => __( 'When the front page is visited, redirects to itself in the browser preferred language. As this doesn\'t work if it is cached, Polylang will attempt to disable the front page cache for known cache plugins.', 'polylang' ),
    36                 'active_option' => $this->is_available() ? 'browser' : false,
     36                'active_option' => $this->is_available() ? 'browser' : 'none',
    3737            )
    3838        );
  • polylang/trunk/settings/settings-licenses.php

    r2475716 r3042028  
    6666    protected function form() {
    6767        if ( ! empty( $this->items ) ) { ?>
    68             <table id="pll-licenses-table" class="form-table">
     68            <table id="pll-licenses-table" class="form-table pll-table-top">
    6969                <?php
    7070                foreach ( $this->items as $item ) {
     
    111111
    112112            // Updated message
    113             add_settings_error( 'general', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'updated' );
     113            add_settings_error( 'polylang', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' );
    114114            ob_start();
    115             settings_errors();
     115            settings_errors( 'polylang' );
    116116            $x->Add( array( 'what' => 'success', 'data' => ob_get_clean() ) );
    117117            $x->send();
  • polylang/trunk/settings/settings-module.php

    r2974283 r3042028  
    3030
    3131    /**
    32      * Stores if the module is active.
    33      *
    34      * @var string|false
     32     * Key to use to manage the module activation state.
     33     * Possible values:
     34     * - An option key for a module that can be activated/deactivated.
     35     * - 'none' for a module that doesn't have a activation/deactivation setting.
     36     * - 'preview' for a preview module whose functionalities are available in the Pro version.
     37     *
     38     * @var string
     39     *
     40     * @phpstan-var non-falsy-string
    3541     */
    3642    public $active_option;
     
    4753     * It must be unique.
    4854     *
    49      * @var string|null
     55     * @var string
     56     *
     57     * @phpstan-var non-falsy-string
    5058     */
    5159    public $module;
     
    93101     * @param object $polylang The Polylang object.
    94102     * @param array  $args {
    95      *   @type string       $module        Unique module name.
    96      *   @type string       $title         The title of the settings module.
    97      *   @type string       $description   The description of the settings module.
    98      *   @type string|false $active_option Optional option name storing if the module is active, false if not used.
     103     *   @type string $module        Unique module name.
     104     *   @type string $title         The title of the settings module.
     105     *   @type string $description   The description of the settings module.
     106     *   @type string $active_option Optional. Key to use to manage the module activation state.
     107     *                               Possible values:
     108     *                               - An option key for a module that can be activated/deactivated.
     109     *                               - 'none' for a module that doesn't have a activation/deactivation setting.
     110     *                               - 'preview' for a preview module whose functionalities are available in the Pro version.
     111     *                               Default is 'none'.
    99112     * }
     113     *
     114     * @phpstan-param array{
     115     *   module: non-falsy-string,
     116     *   title: string,
     117     *   description: string,
     118     *   active_option?: non-falsy-string
     119     * } $args
    100120     */
    101121    public function __construct( &$polylang, $args ) {
    102         $this->options = &$polylang->options;
    103         $this->model = &$polylang->model;
     122        $this->options     = &$polylang->options;
     123        $this->model       = &$polylang->model;
    104124        $this->links_model = &$polylang->links_model;
    105125
     
    109129                'title'         => '',
    110130                'description'   => '',
    111                 'active_option' => false,
     131                'active_option' => 'none',
    112132            )
    113133        );
     134
     135        if ( empty( $args['active_option'] ) ) {
     136            // Backward compatibility.
     137            $args['active_option'] = 'none';
     138        }
    114139
    115140        foreach ( $args as $prop => $value ) {
     
    146171        );
    147172
    148         // Ajax action to save options
     173        // Ajax action to save options.
    149174        add_action( 'wp_ajax_pll_save_options', array( $this, 'save_options' ) );
    150175    }
    151176
    152177    /**
    153      * Tells if the module is active
     178     * Tells if the module is active.
    154179     *
    155180     * @since 1.8
     
    158183     */
    159184    public function is_active() {
    160         return empty( $this->active_option ) || ! empty( $this->options[ $this->active_option ] );
    161     }
    162 
    163     /**
    164      * Activates the module
     185        return 'none' === $this->active_option || ( 'preview' !== $this->active_option && ! empty( $this->options[ $this->active_option ] ) );
     186    }
     187
     188    /**
     189     * Activates the module.
    165190     *
    166191     * @since 1.8
     
    169194     */
    170195    public function activate() {
    171         if ( ! empty( $this->active_option ) ) {
     196        if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
    172197            $this->options[ $this->active_option ] = true;
    173198            update_option( 'polylang', $this->options );
     
    176201
    177202    /**
    178      * Deactivates the module
     203     * Deactivates the module.
    179204     *
    180205     * @since 1.8
     
    183208     */
    184209    public function deactivate() {
    185         if ( ! empty( $this->active_option ) ) {
     210        if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
    186211            $this->options[ $this->active_option ] = false;
    187212            update_option( 'polylang', $this->options );
     
    190215
    191216    /**
    192      * Protected method to display a configuration form
     217     * Protected method to display a configuration form.
    193218     *
    194219     * @since 1.8
     
    197222     */
    198223    protected function form() {
    199         // Child classes can provide a form
    200     }
    201 
    202     /**
    203      * Public method returning the form if any
     224        // Child classes can provide a form.
     225    }
     226
     227    /**
     228     * Public method returning the form if any.
    204229     *
    205230     * @since 1.8
     
    231256
    232257    /**
    233      * Ajax method to save the options
     258     * Ajax method to save the options.
    234259     *
    235260     * @since 1.8
     
    260285            ob_start();
    261286
    262             if ( empty( get_settings_errors() ) ) {
     287            if ( empty( get_settings_errors( 'polylang' ) ) ) {
    263288                // Send update message
    264                 add_settings_error( 'general', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'updated' );
    265                 settings_errors();
     289                add_settings_error( 'polylang', 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' );
     290                settings_errors( 'polylang' );
    266291                $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) );
    267292                $x->send();
    268293            } else {
    269294                // Send error messages
    270                 settings_errors();
     295                settings_errors( 'polylang' );
    271296                $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) );
    272297                $x->send();
     
    289314        }
    290315
    291         if ( $this->active_option ) {
     316        if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) {
    292317            $actions[] = $this->is_active() ? 'deactivate' : 'activate';
    293318        }
     
    312337
    313338    /**
    314      * Default upgrade message ( to Pro version )
     339     * Default upgrade message (to Pro version).
    315340     *
    316341     * @since 1.9
     
    328353
    329354    /**
    330      * Allows child classes to display an upgrade message
     355     * Allows child classes to display an upgrade message.
    331356     *
    332357     * @since 1.9
     
    335360     */
    336361    public function get_upgrade_message() {
    337         return '';
     362        return 'preview' === $this->active_option ? $this->default_upgrade_message() : '';
    338363    }
    339364
  • polylang/trunk/settings/settings-url.php

    r2974283 r3042028  
    263263                    $lang = $this->model->get_language( $key );
    264264                    add_settings_error(
    265                         'general',
    266                         'pll_invalid_domain',
     265                        'polylang',
     266                        sprintf( 'pll_invalid_domain_%s', $key ),
    267267                        esc_html(
    268268                            sprintf(
     
    319319            if ( 200 != $response_code ) {
    320320                add_settings_error(
    321                     'general',
    322                     'pll_invalid_domain',
     321                    'polylang',
     322                    sprintf( 'pll_invalid_domain_%s', $lang->slug ),
    323323                    esc_html(
    324324                        sprintf(
  • polylang/trunk/settings/settings.php

    r2974283 r3042028  
    4848        add_action( 'admin_init', array( $this, 'register_settings_modules' ) );
    4949
    50         // Adds screen options and the about box in the languages admin panel
     50        // Adds screen options and the about box in the languages admin panel.
    5151        add_action( 'load-toplevel_page_mlang', array( $this, 'load_page' ) );
    5252        add_action( 'load-languages_page_mlang_strings', array( $this, 'load_page_strings' ) );
    5353
    54         // Saves per-page value in screen option
    55         add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
     54        // Saves the per-page value in screen options.
     55        add_filter( 'set_screen_option_pll_lang_per_page', array( $this, 'set_screen_option' ), 10, 3 );
     56        add_filter( 'set_screen_option_pll_strings_per_page', array( $this, 'set_screen_option' ), 10, 3 );
    5657    }
    5758
     
    152153
    153154    /**
    154      * Save the "Views/Uploads per page" option set by this user
     155     * Saves the number of rows in the languages or strings table set by this user.
    155156     *
    156157     * @since 0.9.5
    157158     *
    158      * @param mixed  $status false or value returned by previous filter
    159      * @param string $option Name of the option being changed
    160      * @param string $value  Value of the option
    161      *
    162      * @return string New value if this is our option, otherwise nothing
    163      */
    164     public function set_screen_option( $status, $option, $value ) {
    165         return 'pll_lang_per_page' === $option || 'pll_strings_per_page' === $option ? $value : $status;
     159     * @param mixed  $screen_option False or value returned by a previous filter, not used.
     160     * @param string $option        The name of the option, not used.
     161     * @param int    $value         The new value of the option to save.
     162     * @return int The new value of the option.
     163     */
     164    public function set_screen_option( $screen_option, $option, $value ) {
     165        return (int) $value;
    166166    }
    167167
     
    181181
    182182                if ( is_wp_error( $errors ) ) {
    183                     foreach ( $errors->get_error_messages() as $message ) {
    184                         add_settings_error( 'general', 'pll_add_language', $message );
     183                    foreach ( $errors->get_error_codes() as $code ) {
     184                        add_settings_error( 'polylang', $code, $errors->get_error_message( $code ) );
    185185                    }
    186186                } else {
    187                     add_settings_error( 'general', 'pll_languages_created', __( 'Language added.', 'polylang' ), 'updated' );
     187                    add_settings_error( 'polylang', 'pll_languages_created', __( 'Language added.', 'polylang' ), 'success' );
    188188                    $locale = sanitize_locale_name( $_POST['locale'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
    189189
     
    192192                        require_once ABSPATH . 'wp-admin/includes/translation-install.php';
    193193                        if ( ! wp_download_language_pack( $locale ) ) {
    194                             add_settings_error( 'general', 'pll_download_mo', __( 'The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang' ) );
     194                            add_settings_error( 'polylang', 'pll_download_mo', __( 'The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang' ), 'warning' );
    195195                        }
    196196
     
    207207
    208208                if ( ! empty( $_GET['lang'] ) && $this->model->delete_language( (int) $_GET['lang'] ) ) {
    209                     add_settings_error( 'general', 'pll_languages_deleted', __( 'Language deleted.', 'polylang' ), 'updated' );
     209                    add_settings_error( 'polylang', 'pll_languages_deleted', __( 'Language deleted.', 'polylang' ), 'success' );
    210210                }
    211211
     
    218218
    219219                if ( is_wp_error( $errors ) ) {
    220                     foreach ( $errors->get_error_messages() as $message ) {
    221                         add_settings_error( 'general', 'pll_update_language', $message );
     220                    foreach ( $errors->get_error_codes() as $code ) {
     221                        add_settings_error( 'polylang', $code, $errors->get_error_message( $code ) );
    222222                    }
    223223                } else {
    224                     add_settings_error( 'general', 'pll_languages_updated', __( 'Language updated.', 'polylang' ), 'updated' );
     224                    add_settings_error( 'polylang', 'pll_languages_updated', __( 'Language updated.', 'polylang' ), 'success' );
    225225                }
    226226
     
    324324        $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
    325325
    326         wp_enqueue_script( 'pll_admin', plugins_url( '/js/build/admin' . $suffix . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'wp-ajax-response', 'postbox', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
     326        wp_enqueue_script( 'pll_admin', plugins_url( '/js/build/admin' . $suffix . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'wp-ajax-response', 'postbox', 'jquery-ui-selectmenu', 'wp-hooks' ), POLYLANG_VERSION, true );
    327327        wp_localize_script( 'pll_admin', 'pll_admin', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) );
    328328
     
    358358     */
    359359    public static function redirect( $args = array() ) {
    360         $errors = get_settings_errors();
     360        $errors = get_settings_errors( 'polylang' );
    361361        if ( ! empty( $errors ) ) {
    362362            set_transient( 'settings_errors', $errors, 30 );
     
    407407        $languages = apply_filters( 'pll_predefined_languages', $languages );
    408408
    409         // Keep only languages with all necessary informations
     409        // Keep only languages with all necessary information
    410410        foreach ( $languages as $k => $lang ) {
    411411            if ( ! isset( $lang['code'], $lang['locale'], $lang['name'], $lang['dir'], $lang['flag'] ) ) {
  • polylang/trunk/settings/table-settings.php

    r2475716 r3042028  
    176176        usort(
    177177            $items,
    178             function( $a, $b ) {
     178            function ( $a, $b ) {
    179179                return $a->priority > $b->priority ? 1 : -1;
    180180            }
  • polylang/trunk/settings/table-string.php

    r2974283 r3042028  
    8080     *
    8181     * @param array  $item        Data related to the current string.
    82      * @param string $column_name The curent column name.
     82     * @param string $column_name The current column name.
    8383     * @return string
    8484     */
     
    372372    /**
    373373     * Saves the strings translations in DB
    374      * Optionaly clean the DB
     374     * Optionally clean the DB
    375375     *
    376376     * @since 1.9
     
    420420            }
    421421
    422             add_settings_error( 'general', 'pll_strings_translations_updated', __( 'Translations updated.', 'polylang' ), 'updated' );
     422            add_settings_error( 'polylang', 'pll_strings_translations_updated', __( 'Translations updated.', 'polylang' ), 'success' );
    423423
    424424            /**
  • polylang/trunk/settings/view-about.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111?>
    1212<p>
  • polylang/trunk/settings/view-languages.php

    r2911489 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111
    1212require ABSPATH . 'wp-admin/options-head.php'; // Displays the errors messages as when we were a child of options-general.php
  • polylang/trunk/settings/view-tab-lang.php

    r2907847 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111?>
    1212<div id="col-container">
  • polylang/trunk/settings/view-tab-settings.php

    r2340428 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111?>
    1212<div class="form-wrap">
  • polylang/trunk/settings/view-tab-strings.php

    r2708418 r3042028  
    88if ( ! defined( 'ABSPATH' ) ) {
    99    exit; // Don't access directly
    10 };
     10}
    1111?>
    1212<div class="form-wrap">
  • polylang/trunk/uninstall.php

    r2907847 r3042028  
    2424        global $wpdb;
    2525
    26         // Don't do anything except if the constant PLL_REMOVE_ALL_DATA is explicitely defined and true.
     26        // Don't do anything except if the constant PLL_REMOVE_ALL_DATA is explicitly defined and true.
    2727        if ( ! defined( 'PLL_REMOVE_ALL_DATA' ) || ! PLL_REMOVE_ALL_DATA ) {
    2828            return;
     
    6262
    6363        // Delete users options
    64         foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
    65             delete_user_meta( $user_id, 'pll_filter_content' );
    66             delete_user_meta( $user_id, 'pll_dismissed_notices' ); // Legacy meta.
    67             foreach ( $languages as $lang ) {
    68                 delete_user_meta( $user_id, 'description_' . $lang->slug );
    69             }
     64        delete_metadata( 'user', 0, 'pll_filter_content', '', true );
     65        delete_metadata( 'user', 0, 'pll_dismissed_notices', '', true ); // Legacy meta.
     66        foreach ( $languages as $lang ) {
     67            delete_metadata( 'user', 0, "description_{$lang->slug}", '', true );
    7068        }
    7169
  • polylang/trunk/vendor/composer/autoload_classmap.php

    r2974283 r3042028  
    9494    'PLL_Settings_Media' => $baseDir . '/settings/settings-media.php',
    9595    'PLL_Settings_Module' => $baseDir . '/settings/settings-module.php',
     96    'PLL_Settings_Preview_Machine_Translation' => $baseDir . '/modules/machine-translation/settings-preview-machine-translation.php',
    9697    'PLL_Settings_Preview_Share_Slug' => $baseDir . '/modules/share-slug/settings-preview-share-slug.php',
    9798    'PLL_Settings_Preview_Translate_Slugs' => $baseDir . '/modules/translate-slugs/settings-preview-translate-slugs.php',
  • polylang/trunk/vendor/composer/autoload_static.php

    r2974283 r3042028  
    9595        'PLL_Settings_Media' => __DIR__ . '/../..' . '/settings/settings-media.php',
    9696        'PLL_Settings_Module' => __DIR__ . '/../..' . '/settings/settings-module.php',
     97        'PLL_Settings_Preview_Machine_Translation' => __DIR__ . '/../..' . '/modules/machine-translation/settings-preview-machine-translation.php',
    9798        'PLL_Settings_Preview_Share_Slug' => __DIR__ . '/../..' . '/modules/share-slug/settings-preview-share-slug.php',
    9899        'PLL_Settings_Preview_Translate_Slugs' => __DIR__ . '/../..' . '/modules/translate-slugs/settings-preview-translate-slugs.php',
  • polylang/trunk/vendor/composer/installed.php

    r3008143 r3042028  
    22    'root' => array(
    33        'name' => 'wpsyntex/polylang',
    4         'pretty_version' => '3.5.x-dev',
    5         'version' => '3.5.9999999.9999999-dev',
    6         'reference' => 'a7e301c7219098568feace09fc14cf791d9b5242',
     4        'pretty_version' => 'dev-master',
     5        'version' => 'dev-master',
     6        'reference' => '570d8532ad9a968a1147adb3588e67ac357d81c3',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    1212    'versions' => array(
    1313        'wpsyntex/polylang' => array(
    14             'pretty_version' => '3.5.x-dev',
    15             'version' => '3.5.9999999.9999999-dev',
    16             'reference' => 'a7e301c7219098568feace09fc14cf791d9b5242',
     14            'pretty_version' => 'dev-master',
     15            'version' => 'dev-master',
     16            'reference' => '570d8532ad9a968a1147adb3588e67ac357d81c3',
    1717            'type' => 'wordpress-plugin',
    1818            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.