From e7303edd00f7d749ba8cf7517ad1bee6eb4bb764 Mon Sep 17 00:00:00 2001 From: Jonathan Bossenger Date: Wed, 4 Dec 2024 00:44:44 +0200 Subject: [PATCH] Adds the Polylang Pro plugin to Learn.WordPress.org (#3049) * Adds the Polylang Pro plugin to Learn.WordPress.org See #2284 * Add Polylang Pro to build * Reconfigure gitignore for build directories * Add polylang pro frontend assets --------- Co-authored-by: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> --- .github/workflows/build.yml | 2 + .gitignore | 7 +- wp-content/plugins/polylang-pro/LICENSE | 674 +++ wp-content/plugins/polylang-pro/changelog.txt | 2325 +++++++++ .../css/build/admin-export-import.css | 55 + .../css/build/admin-export-import.min.css | 1 + .../plugins/polylang-pro/css/build/admin.css | 459 ++ .../polylang-pro/css/build/admin.min.css | 1 + .../polylang-pro/css/build/bulk-translate.css | 57 + .../css/build/bulk-translate.min.css | 1 + .../plugins/polylang-pro/css/build/dialog.css | 85 + .../polylang-pro/css/build/dialog.min.css | 1 + .../build/machine-translation-settings.css | 103 + .../machine-translation-settings.min.css | 1 + .../polylang-pro/css/build/metabox-button.css | 25 + .../css/build/metabox-button.min.css | 1 + .../polylang-pro/css/build/selectmenu.css | 239 + .../polylang-pro/css/build/selectmenu.min.css | 1 + .../plugins/polylang-pro/css/build/style.css | 289 ++ .../polylang-pro/css/build/style.min.css | 1 + .../plugins/polylang-pro/css/build/wizard.css | 951 ++++ .../polylang-pro/css/build/wizard.min.css | 1 + .../polylang-pro/include/format-util.php | 95 + .../polylang-pro/include/functions.php | 20 + .../plugins/polylang-pro/include/pro.php | 103 + .../integrations/acf/acf-auto-translate.php | 491 ++ .../integrations/acf/acf-sync-metas.php | 305 ++ .../polylang-pro/integrations/acf/acf.php | 321 ++ .../polylang-pro/integrations/acf/js/acf.js | 57 + .../polylang-pro/integrations/acf/load.php | 29 + .../integrations/admin-columns/cpac.php | 72 + .../integrations/admin-columns/load.php | 17 + .../integrations/beaver-builder/flbuilder.php | 41 + .../integrations/beaver-builder/load.php | 17 + .../content-blocks/content-blocks.php | 40 + .../integrations/content-blocks/load.php | 18 + .../polylang-pro/integrations/cptui/cptui.php | 98 + .../polylang-pro/integrations/cptui/load.php | 18 + .../integrations/divi/divi-builder.php | 49 + .../polylang-pro/integrations/divi/load.php | 17 + .../integrations/events-calendar/load.php | 18 + .../integrations/events-calendar/tec.php | 1272 +++++ .../plugins/polylang-pro/js/build/acf.js | 58 + .../plugins/polylang-pro/js/build/acf.min.js | 1 + .../plugins/polylang-pro/js/build/admin.js | 427 ++ .../polylang-pro/js/build/admin.min.js | 1 + .../js/build/block-editor-plugin.js | 924 ++++ .../js/build/block-editor-plugin.min.js | 1 + .../polylang-pro/js/build/block-editor.js | 405 ++ .../polylang-pro/js/build/block-editor.min.js | 1 + .../plugins/polylang-pro/js/build/blocks.js | 1517 ++++++ .../polylang-pro/js/build/blocks.min.js | 1 + .../polylang-pro/js/build/bulk-translate.js | 87 + .../js/build/bulk-translate.min.js | 1 + .../polylang-pro/js/build/classic-editor.js | 451 ++ .../js/build/classic-editor.min.js | 1 + .../js/build/confirmation-modal.js | 125 + .../js/build/confirmation-modal.min.js | 1 + .../js/build/filter-path-middleware.js | 24 + .../js/build/filter-path-middleware.min.js | 1 + .../polylang-pro/js/build/languages-step.js | 303 ++ .../js/build/languages-step.min.js | 1 + .../js/build/machine-translation-settings.js | 220 + .../build/machine-translation-settings.min.js | 1 + .../js/build/metabox-autocomplete.js | 67 + .../js/build/metabox-autocomplete.min.js | 1 + .../polylang-pro/js/build/metabox-button.js | 46 + .../js/build/metabox-button.min.js | 1 + .../plugins/polylang-pro/js/build/nav-menu.js | 105 + .../polylang-pro/js/build/nav-menu.min.js | 1 + .../plugins/polylang-pro/js/build/post.js | 184 + .../plugins/polylang-pro/js/build/post.min.js | 1 + .../plugins/polylang-pro/js/build/sidebar.js | 4198 +++++++++++++++++ .../polylang-pro/js/build/sidebar.min.js | 1 + .../plugins/polylang-pro/js/build/term.js | 232 + .../plugins/polylang-pro/js/build/term.min.js | 1 + .../plugins/polylang-pro/js/build/user.js | 34 + .../plugins/polylang-pro/js/build/user.min.js | 1 + .../js/build/widget-editor-plugin.js | 722 +++ .../js/build/widget-editor-plugin.min.js | 1 + .../plugins/polylang-pro/js/build/widgets.js | 152 + .../polylang-pro/js/build/widgets.min.js | 1 + .../modules/Machine_Translation/Action.php | 205 + .../modules/Machine_Translation/Button.php | 72 + .../Machine_Translation/Button_REST.php | 98 + .../Clients/Client_Interface.php | 45 + .../Machine_Translation/Clients/Deepl.php | 418 ++ .../modules/Machine_Translation/Data.php | 93 + .../modules/Machine_Translation/Factory.php | 138 + .../Machine_Translation/Module_Settings.php | 151 + .../modules/Machine_Translation/Processor.php | 136 + .../Machine_Translation/Services/Deepl.php | 217 + .../Services/Service_Interface.php | 104 + .../Machine_Translation/Settings/Deepl.php | 480 ++ .../Settings/Settings_Interface.php | 72 + .../views/view-characters-consumption-row.php | 20 + .../views/view-deepl-formality-row.php | 69 + .../Settings/views/view-inner-notice.php | 21 + .../Settings/views/view-inner-notices-row.php | 20 + .../Settings/views/view-progress-bar.php | 14 + .../views/view-service-authentication-row.php | 95 + .../css/machine-translation-settings.css | 103 + .../js/machine-translation-settings.js | 219 + .../modules/Machine_Translation/load.php | 44 + .../modules/Machine_Translation/uninstall.php | 8 + .../active-languages/active-languages.php | 260 + .../modules/active-languages/load.php | 12 + .../abstract-language-switcher-block.php | 205 + .../block-editor/block-editor-plugin.php | 439 ++ .../frontend-filters-widgets-blocks.php | 44 + .../block-editor/language-switcher-block.php | 66 + .../modules/block-editor/load.php | 27 + .../navigation-language-switcher-block.php | 300 ++ .../widget-editor-language-attribute.php | 69 + .../bulk-translate/bulk-translate-option.php | 213 + .../modules/bulk-translate/bulk-translate.php | 359 ++ .../bulk-translate/css/bulk-translate.css | 57 + .../bulk-translate/js/bulk-translate.js | 86 + .../modules/bulk-translate/load.php | 13 + .../view-bulk-translate-option.php | 16 + .../bulk-translate/view-bulk-translate.php | 56 + .../modules/duplicate/duplicate-action.php | 99 + .../modules/duplicate/duplicate-rest.php | 65 + .../modules/duplicate/duplicate.php | 39 + .../polylang-pro/modules/duplicate/load.php | 17 + .../modules/duplicate/uninstall.php | 8 + ...stract-bulk-edit-template-slugs-module.php | 161 + .../full-site-editing/fse-abstract-module.php | 52 + .../fse-default-language-change.php | 71 + .../fse-filter-block-types.php | 115 + .../fse-language-slug-change.php | 79 + .../full-site-editing/fse-language.php | 94 + .../full-site-editing/fse-post-deletion.php | 75 + .../full-site-editing/fse-post-types.php | 71 + .../full-site-editing/fse-query-filters.php | 245 + .../fse-recreate-language.php | 334 ++ .../fse-rest-duplicate-template.php | 154 + .../fse-rest-enforce-default-template.php | 151 + .../full-site-editing/fse-rest-route.php | 203 + .../full-site-editing/fse-rest-template.php | 334 ++ .../full-site-editing/fse-template-model.php | 153 + .../fse-template-slug-sync.php | 402 ++ .../full-site-editing/fse-template-slug.php | 188 + .../modules/full-site-editing/fse-tools.php | 221 + .../modules/full-site-editing/load.php | 49 + .../assets/css/admin-export-import.css | 55 + .../export/export-bulk-option.php | 339 ++ .../import-export/export/export-download.php | 149 + .../import-export/export/export-file.php | 49 + .../export/export-strings-action.php | 164 + .../export/view-export-file-format.php | 27 + .../export/view-tab-export-strings.php | 68 + .../file-format/file-format-factory.php | 153 + .../import-export/file-format/file-format.php | 53 + .../modules/import-export/import-export.php | 168 + .../import-export/import/import-action.php | 303 ++ .../import/import-file-interface.php | 69 + .../import/import-object-interface.php | 65 + .../import-export/import/import-posts.php | 192 + .../import-export/import/import-strings.php | 157 + .../import-export/import/import-terms.php | 136 + .../import/view-tab-import-translations.php | 36 + .../modules/import-export/load.php | 18 + .../modules/import-export/po/po-export.php | 145 + .../modules/import-export/po/po-format.php | 59 + .../modules/import-export/po/po-import.php | 175 + .../xliff/export/xliff-export-12.php | 165 + .../xliff/export/xliff-export-20.php | 24 + .../xliff/export/xliff-export-21.php | 173 + .../xliff/export/xliff-export-base.php | 325 ++ .../import-export/xliff/xliff-format.php | 86 + .../xliff/xliff-import-parser-12.php | 243 + .../xliff/xliff-import-parser-21.php | 198 + .../xliff/xliff-import-parser-base.php | 338 ++ .../import-export/xliff/xliff-import.php | 195 + .../modules/locale-fallback/load.php | 11 + .../locale-fallback/locale-fallback.php | 249 + .../locale-fallback/view-locale-fallback.php | 16 + .../modules/media/admin-advanced-media.php | 138 + .../polylang-pro/modules/media/load.php | 37 + .../modules/media/media-bulk-option.php | 63 + .../modules/media/settings-advanced-media.php | 77 + .../polylang-pro/modules/module-interface.php | 32 + .../polylang-pro/modules/rest/load.php | 15 + .../polylang-pro/modules/rest/rest-api.php | 238 + .../modules/rest/rest-comment.php | 41 + .../modules/rest/rest-filtered-object.php | 108 + .../polylang-pro/modules/rest/rest-post.php | 438 ++ .../polylang-pro/modules/rest/rest-term.php | 125 + .../modules/rest/rest-translated-object.php | 148 + .../polylang-pro/modules/share-slug/load.php | 27 + .../share-slug/settings-share-slug.php | 81 + .../modules/share-slug/share-post-slug.php | 358 ++ .../modules/share-slug/share-term-slug.php | 267 ++ .../polylang-pro/modules/sync-post/load.php | 26 + .../sync-post/sync-post-bulk-option.php | 79 + .../modules/sync-post/sync-post-button.php | 102 + .../modules/sync-post/sync-post-model.php | 362 ++ .../modules/sync-post/sync-post-rest.php | 148 + .../modules/sync-post/sync-post.php | 270 ++ .../polylang-pro/modules/sync/load.php | 13 + .../modules/sync/sync-content.php | 621 +++ .../modules/sync/sync-navigation.php | 211 + .../frontend-translate-slugs.php | 231 + .../modules/translate-slugs/load.php | 33 + .../settings-translate-slugs.php | 44 + .../translate-slugs/translate-slugs-model.php | 593 +++ .../translate-slugs/translate-slugs.php | 120 + .../modules/translate-slugs/uninstall.php | 10 + .../polylang-pro/modules/wizard/load.php | 18 + .../modules/wizard/wizard-pro.php | 74 + .../polylang-pro/modules/xdata/load.php | 15 + .../polylang-pro/modules/xdata/xdata-base.php | 390 ++ .../modules/xdata/xdata-domain.php | 174 + .../modules/xdata/xdata-session-manager.php | 65 + .../modules/xdata/xdata-subdomain.php | 142 + wp-content/plugins/polylang-pro/polylang.php | 73 + wp-content/plugins/polylang-pro/readme.txt | 167 + .../services/admin-loader/admin-loader.php | 114 + .../collect-linked-posts.php | 301 ++ .../collect-linked-terms.php | 263 ++ .../plugins/polylang-pro/services/context.php | 114 + .../polylang-pro/services/data-encoding.php | 170 + .../polylang-pro/services/dom/dom-content.php | 245 + .../services/dom/dom-document.php | 203 + .../services/dom/dom-nodes-iterator.php | 130 + .../services/exporter/export-container.php | 93 + .../exporter/export-data-from-posts.php | 158 + .../exporter/export-data-from-strings.php | 67 + .../services/exporter/export-data.php | 127 + .../services/exporter/export-metas.php | 275 ++ .../services/exporter/export-post-metas.php | 62 + .../services/exporter/export-posts.php | 148 + .../services/exporter/export-strings.php | 121 + .../services/exporter/export-term-metas.php | 22 + .../services/exporter/export-terms.php | 99 + .../exporter/export-translated-objects.php | 119 + .../services/manage-user-capabilities.php | 66 + .../metabox-button/css/metabox-button.css | 25 + .../metabox-button/js/metabox-button.js | 45 + .../metabox-button/metabox-button.php | 210 + .../metabox-button/metabox-user-button.php | 40 + .../metabox-button/toggle-user-meta.php | 102 + .../translation-block-parsing-rules.php | 424 ++ .../translation/translation-content.php | 89 + .../translation/translation-metas.php | 400 ++ .../translation-object-model-interface.php | 31 + .../translation/translation-post-metas.php | 28 + .../translation/translation-post-model.php | 387 ++ .../translation/translation-term-metas.php | 28 + .../translation/translation-term-model.php | 297 ++ .../translation/translation-walker-blocks.php | 359 ++ .../translation-walker-classic.php | 109 + .../translation-walker-factory.php | 30 + .../translation-walker-interface.php | 23 + wp-content/plugins/polylang-pro/uninstall.php | 20 + .../plugins/polylang-pro/vendor/autoload.php | 25 + .../vendor/composer/ClassLoader.php | 579 +++ .../vendor/composer/InstalledVersions.php | 359 ++ .../polylang-pro/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 284 ++ .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 9 + .../vendor/composer/autoload_real.php | 38 + .../vendor/composer/autoload_static.php | 294 ++ .../vendor/composer/installed.json | 59 + .../vendor/composer/installed.php | 32 + .../vendor/composer/platform_check.php | 26 + .../vendor/wpsyntex/polylang/LICENSE | 674 +++ .../wpsyntex/polylang/admin/admin-base.php | 575 +++ .../polylang/admin/admin-block-editor.php | 92 + .../polylang/admin/admin-classic-editor.php | 371 ++ .../polylang/admin/admin-default-term.php | 264 ++ .../polylang/admin/admin-filters-columns.php | 451 ++ .../polylang/admin/admin-filters-media.php | 132 + .../admin/admin-filters-post-base.php | 65 + .../polylang/admin/admin-filters-post.php | 223 + .../polylang/admin/admin-filters-term.php | 716 +++ .../admin/admin-filters-widgets-options.php | 34 + .../wpsyntex/polylang/admin/admin-filters.php | 127 + .../wpsyntex/polylang/admin/admin-links.php | 226 + .../wpsyntex/polylang/admin/admin-model.php | 540 +++ .../polylang/admin/admin-nav-menu.php | 280 ++ .../wpsyntex/polylang/admin/admin-notices.php | 270 ++ .../polylang/admin/admin-static-pages.php | 152 + .../wpsyntex/polylang/admin/admin-strings.php | 136 + .../vendor/wpsyntex/polylang/admin/admin.php | 180 + .../admin/view-translations-media.php | 43 + .../polylang/admin/view-translations-post.php | 69 + .../polylang/admin/view-translations-term.php | 98 + .../vendor/wpsyntex/polylang/changelog.txt | 2325 +++++++++ .../wpsyntex/polylang/css/src/admin.css | 459 ++ .../wpsyntex/polylang/css/src/dialog.css | 85 + .../wpsyntex/polylang/css/src/selectmenu.css | 239 + .../vendor/wpsyntex/polylang/flags/ad.png | Bin 0 -> 378 bytes .../vendor/wpsyntex/polylang/flags/ae.png | Bin 0 -> 228 bytes .../vendor/wpsyntex/polylang/flags/af.png | Bin 0 -> 365 bytes .../vendor/wpsyntex/polylang/flags/ag.png | Bin 0 -> 379 bytes .../vendor/wpsyntex/polylang/flags/ai.png | Bin 0 -> 392 bytes .../vendor/wpsyntex/polylang/flags/al.png | Bin 0 -> 365 bytes .../vendor/wpsyntex/polylang/flags/am.png | Bin 0 -> 254 bytes .../vendor/wpsyntex/polylang/flags/an.png | Bin 0 -> 242 bytes .../vendor/wpsyntex/polylang/flags/ao.png | Bin 0 -> 255 bytes .../vendor/wpsyntex/polylang/flags/ar.png | Bin 0 -> 260 bytes .../vendor/wpsyntex/polylang/flags/arab.png | Bin 0 -> 184 bytes .../vendor/wpsyntex/polylang/flags/as.png | Bin 0 -> 428 bytes .../vendor/wpsyntex/polylang/flags/at.png | Bin 0 -> 212 bytes .../vendor/wpsyntex/polylang/flags/au.png | Bin 0 -> 402 bytes .../vendor/wpsyntex/polylang/flags/aw.png | Bin 0 -> 264 bytes .../vendor/wpsyntex/polylang/flags/ax.png | Bin 0 -> 384 bytes .../vendor/wpsyntex/polylang/flags/az.png | Bin 0 -> 319 bytes .../vendor/wpsyntex/polylang/flags/ba.png | Bin 0 -> 340 bytes .../vendor/wpsyntex/polylang/flags/basque.png | Bin 0 -> 215 bytes .../vendor/wpsyntex/polylang/flags/bb.png | Bin 0 -> 316 bytes .../vendor/wpsyntex/polylang/flags/bd.png | Bin 0 -> 251 bytes .../vendor/wpsyntex/polylang/flags/be.png | Bin 0 -> 272 bytes .../vendor/wpsyntex/polylang/flags/bf.png | Bin 0 -> 289 bytes .../vendor/wpsyntex/polylang/flags/bg.png | Bin 0 -> 255 bytes .../vendor/wpsyntex/polylang/flags/bh.png | Bin 0 -> 230 bytes .../vendor/wpsyntex/polylang/flags/bi.png | Bin 0 -> 400 bytes .../vendor/wpsyntex/polylang/flags/bj.png | Bin 0 -> 248 bytes .../vendor/wpsyntex/polylang/flags/bm.png | Bin 0 -> 371 bytes .../vendor/wpsyntex/polylang/flags/bn.png | Bin 0 -> 360 bytes .../vendor/wpsyntex/polylang/flags/bo.png | Bin 0 -> 297 bytes .../vendor/wpsyntex/polylang/flags/br.png | Bin 0 -> 353 bytes .../vendor/wpsyntex/polylang/flags/bs.png | Bin 0 -> 335 bytes .../vendor/wpsyntex/polylang/flags/bt.png | Bin 0 -> 368 bytes .../vendor/wpsyntex/polylang/flags/bw.png | Bin 0 -> 238 bytes .../vendor/wpsyntex/polylang/flags/by.png | Bin 0 -> 280 bytes .../vendor/wpsyntex/polylang/flags/bz.png | Bin 0 -> 399 bytes .../vendor/wpsyntex/polylang/flags/ca.png | Bin 0 -> 340 bytes .../wpsyntex/polylang/flags/catalonia.png | Bin 0 -> 233 bytes .../vendor/wpsyntex/polylang/flags/cc.png | Bin 0 -> 359 bytes .../vendor/wpsyntex/polylang/flags/cd.png | Bin 0 -> 301 bytes .../vendor/wpsyntex/polylang/flags/cf.png | Bin 0 -> 355 bytes .../vendor/wpsyntex/polylang/flags/cg.png | Bin 0 -> 259 bytes .../vendor/wpsyntex/polylang/flags/ch.png | Bin 0 -> 167 bytes .../vendor/wpsyntex/polylang/flags/ci.png | Bin 0 -> 226 bytes .../vendor/wpsyntex/polylang/flags/ck.png | Bin 0 -> 347 bytes .../vendor/wpsyntex/polylang/flags/cl.png | Bin 0 -> 240 bytes .../vendor/wpsyntex/polylang/flags/cm.png | Bin 0 -> 310 bytes .../vendor/wpsyntex/polylang/flags/cn.png | Bin 0 -> 252 bytes .../vendor/wpsyntex/polylang/flags/co.png | Bin 0 -> 253 bytes .../vendor/wpsyntex/polylang/flags/cr.png | Bin 0 -> 270 bytes .../vendor/wpsyntex/polylang/flags/cu.png | Bin 0 -> 317 bytes .../vendor/wpsyntex/polylang/flags/cv.png | Bin 0 -> 294 bytes .../vendor/wpsyntex/polylang/flags/cx.png | Bin 0 -> 385 bytes .../vendor/wpsyntex/polylang/flags/cy.png | Bin 0 -> 232 bytes .../vendor/wpsyntex/polylang/flags/cz.png | Bin 0 -> 260 bytes .../vendor/wpsyntex/polylang/flags/de.png | Bin 0 -> 357 bytes .../vendor/wpsyntex/polylang/flags/dj.png | Bin 0 -> 315 bytes .../vendor/wpsyntex/polylang/flags/dk.png | Bin 0 -> 219 bytes .../vendor/wpsyntex/polylang/flags/dm.png | Bin 0 -> 386 bytes .../vendor/wpsyntex/polylang/flags/do.png | Bin 0 -> 264 bytes .../vendor/wpsyntex/polylang/flags/dz.png | Bin 0 -> 323 bytes .../vendor/wpsyntex/polylang/flags/ec.png | Bin 0 -> 306 bytes .../vendor/wpsyntex/polylang/flags/ee.png | Bin 0 -> 213 bytes .../vendor/wpsyntex/polylang/flags/eg.png | Bin 0 -> 266 bytes .../vendor/wpsyntex/polylang/flags/eh.png | Bin 0 -> 292 bytes .../wpsyntex/polylang/flags/england.png | Bin 0 -> 248 bytes .../vendor/wpsyntex/polylang/flags/er.png | Bin 0 -> 440 bytes .../vendor/wpsyntex/polylang/flags/es.png | Bin 0 -> 290 bytes .../wpsyntex/polylang/flags/esperanto.png | Bin 0 -> 156 bytes .../vendor/wpsyntex/polylang/flags/et.png | Bin 0 -> 353 bytes .../vendor/wpsyntex/polylang/flags/fi.png | Bin 0 -> 206 bytes .../vendor/wpsyntex/polylang/flags/fj.png | Bin 0 -> 411 bytes .../vendor/wpsyntex/polylang/flags/fk.png | Bin 0 -> 416 bytes .../vendor/wpsyntex/polylang/flags/fm.png | Bin 0 -> 225 bytes .../vendor/wpsyntex/polylang/flags/fo.png | Bin 0 -> 243 bytes .../vendor/wpsyntex/polylang/flags/fr.png | Bin 0 -> 271 bytes .../vendor/wpsyntex/polylang/flags/ga.png | Bin 0 -> 292 bytes .../wpsyntex/polylang/flags/galicia.png | Bin 0 -> 254 bytes .../vendor/wpsyntex/polylang/flags/gb.png | Bin 0 -> 394 bytes .../vendor/wpsyntex/polylang/flags/gd.png | Bin 0 -> 415 bytes .../vendor/wpsyntex/polylang/flags/ge.png | Bin 0 -> 294 bytes .../vendor/wpsyntex/polylang/flags/gh.png | Bin 0 -> 269 bytes .../vendor/wpsyntex/polylang/flags/gi.png | Bin 0 -> 269 bytes .../vendor/wpsyntex/polylang/flags/gl.png | Bin 0 -> 259 bytes .../vendor/wpsyntex/polylang/flags/gm.png | Bin 0 -> 302 bytes .../vendor/wpsyntex/polylang/flags/gn.png | Bin 0 -> 293 bytes .../vendor/wpsyntex/polylang/flags/gp.png | Bin 0 -> 264 bytes .../vendor/wpsyntex/polylang/flags/gq.png | Bin 0 -> 316 bytes .../vendor/wpsyntex/polylang/flags/gr.png | Bin 0 -> 267 bytes .../vendor/wpsyntex/polylang/flags/gs.png | Bin 0 -> 392 bytes .../vendor/wpsyntex/polylang/flags/gt.png | Bin 0 -> 220 bytes .../vendor/wpsyntex/polylang/flags/gu.png | Bin 0 -> 257 bytes .../vendor/wpsyntex/polylang/flags/gw.png | Bin 0 -> 297 bytes .../vendor/wpsyntex/polylang/flags/gy.png | Bin 0 -> 429 bytes .../vendor/wpsyntex/polylang/flags/hk.png | Bin 0 -> 240 bytes .../vendor/wpsyntex/polylang/flags/hm.png | Bin 0 -> 402 bytes .../vendor/wpsyntex/polylang/flags/hn.png | Bin 0 -> 279 bytes .../vendor/wpsyntex/polylang/flags/hr.png | Bin 0 -> 269 bytes .../vendor/wpsyntex/polylang/flags/ht.png | Bin 0 -> 278 bytes .../vendor/wpsyntex/polylang/flags/hu.png | Bin 0 -> 212 bytes .../vendor/wpsyntex/polylang/flags/id.png | Bin 0 -> 209 bytes .../vendor/wpsyntex/polylang/flags/ie.png | Bin 0 -> 243 bytes .../vendor/wpsyntex/polylang/flags/il.png | Bin 0 -> 218 bytes .../vendor/wpsyntex/polylang/flags/in.png | Bin 0 -> 294 bytes .../vendor/wpsyntex/polylang/flags/io.png | Bin 0 -> 438 bytes .../vendor/wpsyntex/polylang/flags/iq.png | Bin 0 -> 293 bytes .../vendor/wpsyntex/polylang/flags/ir.png | Bin 0 -> 311 bytes .../vendor/wpsyntex/polylang/flags/is.png | Bin 0 -> 245 bytes .../vendor/wpsyntex/polylang/flags/it.png | Bin 0 -> 234 bytes .../vendor/wpsyntex/polylang/flags/jm.png | Bin 0 -> 435 bytes .../vendor/wpsyntex/polylang/flags/jo.png | Bin 0 -> 272 bytes .../vendor/wpsyntex/polylang/flags/jp.png | Bin 0 -> 214 bytes .../vendor/wpsyntex/polylang/flags/ke.png | Bin 0 -> 343 bytes .../vendor/wpsyntex/polylang/flags/kg.png | Bin 0 -> 245 bytes .../vendor/wpsyntex/polylang/flags/kh.png | Bin 0 -> 300 bytes .../vendor/wpsyntex/polylang/flags/ki.png | Bin 0 -> 391 bytes .../vendor/wpsyntex/polylang/flags/km.png | Bin 0 -> 344 bytes .../vendor/wpsyntex/polylang/flags/kn.png | Bin 0 -> 377 bytes .../vendor/wpsyntex/polylang/flags/kp.png | Bin 0 -> 299 bytes .../vendor/wpsyntex/polylang/flags/kr.png | Bin 0 -> 339 bytes .../wpsyntex/polylang/flags/kurdistan.png | Bin 0 -> 239 bytes .../vendor/wpsyntex/polylang/flags/kw.png | Bin 0 -> 298 bytes .../vendor/wpsyntex/polylang/flags/ky.png | Bin 0 -> 386 bytes .../vendor/wpsyntex/polylang/flags/kz.png | Bin 0 -> 350 bytes .../vendor/wpsyntex/polylang/flags/la.png | Bin 0 -> 276 bytes .../vendor/wpsyntex/polylang/flags/lb.png | Bin 0 -> 247 bytes .../vendor/wpsyntex/polylang/flags/lc.png | Bin 0 -> 331 bytes .../vendor/wpsyntex/polylang/flags/li.png | Bin 0 -> 328 bytes .../vendor/wpsyntex/polylang/flags/lk.png | Bin 0 -> 357 bytes .../vendor/wpsyntex/polylang/flags/lr.png | Bin 0 -> 237 bytes .../vendor/wpsyntex/polylang/flags/ls.png | Bin 0 -> 343 bytes .../vendor/wpsyntex/polylang/flags/lt.png | Bin 0 -> 313 bytes .../vendor/wpsyntex/polylang/flags/lu.png | Bin 0 -> 262 bytes .../vendor/wpsyntex/polylang/flags/lv.png | Bin 0 -> 248 bytes .../vendor/wpsyntex/polylang/flags/ly.png | Bin 0 -> 181 bytes .../vendor/wpsyntex/polylang/flags/ma.png | Bin 0 -> 220 bytes .../vendor/wpsyntex/polylang/flags/mc.png | Bin 0 -> 198 bytes .../vendor/wpsyntex/polylang/flags/md.png | Bin 0 -> 310 bytes .../vendor/wpsyntex/polylang/flags/me.png | Bin 0 -> 270 bytes .../vendor/wpsyntex/polylang/flags/mg.png | Bin 0 -> 267 bytes .../vendor/wpsyntex/polylang/flags/mh.png | Bin 0 -> 376 bytes .../vendor/wpsyntex/polylang/flags/mk.png | Bin 0 -> 430 bytes .../vendor/wpsyntex/polylang/flags/ml.png | Bin 0 -> 299 bytes .../vendor/wpsyntex/polylang/flags/mm.png | Bin 0 -> 178 bytes .../vendor/wpsyntex/polylang/flags/mn.png | Bin 0 -> 323 bytes .../vendor/wpsyntex/polylang/flags/mo.png | Bin 0 -> 294 bytes .../vendor/wpsyntex/polylang/flags/mp.png | Bin 0 -> 367 bytes .../vendor/wpsyntex/polylang/flags/mq.png | Bin 0 -> 295 bytes .../vendor/wpsyntex/polylang/flags/mr.png | Bin 0 -> 315 bytes .../vendor/wpsyntex/polylang/flags/ms.png | Bin 0 -> 400 bytes .../vendor/wpsyntex/polylang/flags/mt.png | Bin 0 -> 219 bytes .../vendor/wpsyntex/polylang/flags/mu.png | Bin 0 -> 354 bytes .../vendor/wpsyntex/polylang/flags/mv.png | Bin 0 -> 269 bytes .../vendor/wpsyntex/polylang/flags/mw.png | Bin 0 -> 342 bytes .../vendor/wpsyntex/polylang/flags/mx.png | Bin 0 -> 301 bytes .../vendor/wpsyntex/polylang/flags/my.png | Bin 0 -> 323 bytes .../vendor/wpsyntex/polylang/flags/mz.png | Bin 0 -> 378 bytes .../vendor/wpsyntex/polylang/flags/na.png | Bin 0 -> 403 bytes .../vendor/wpsyntex/polylang/flags/nc.png | Bin 0 -> 375 bytes .../vendor/wpsyntex/polylang/flags/ne.png | Bin 0 -> 278 bytes .../vendor/wpsyntex/polylang/flags/nf.png | Bin 0 -> 281 bytes .../vendor/wpsyntex/polylang/flags/ng.png | Bin 0 -> 234 bytes .../vendor/wpsyntex/polylang/flags/ni.png | Bin 0 -> 270 bytes .../vendor/wpsyntex/polylang/flags/nl.png | Bin 0 -> 243 bytes .../vendor/wpsyntex/polylang/flags/no.png | Bin 0 -> 239 bytes .../vendor/wpsyntex/polylang/flags/np.png | Bin 0 -> 255 bytes .../vendor/wpsyntex/polylang/flags/nr.png | Bin 0 -> 261 bytes .../vendor/wpsyntex/polylang/flags/nu.png | Bin 0 -> 352 bytes .../vendor/wpsyntex/polylang/flags/nz.png | Bin 0 -> 391 bytes .../wpsyntex/polylang/flags/occitania.png | Bin 0 -> 157 bytes .../vendor/wpsyntex/polylang/flags/om.png | Bin 0 -> 255 bytes .../vendor/wpsyntex/polylang/flags/pa.png | Bin 0 -> 292 bytes .../vendor/wpsyntex/polylang/flags/pe.png | Bin 0 -> 208 bytes .../vendor/wpsyntex/polylang/flags/pf.png | Bin 0 -> 269 bytes .../vendor/wpsyntex/polylang/flags/pg.png | Bin 0 -> 364 bytes .../vendor/wpsyntex/polylang/flags/ph.png | Bin 0 -> 342 bytes .../vendor/wpsyntex/polylang/flags/pk.png | Bin 0 -> 270 bytes .../vendor/wpsyntex/polylang/flags/pl.png | Bin 0 -> 194 bytes .../vendor/wpsyntex/polylang/flags/pm.png | Bin 0 -> 439 bytes .../vendor/wpsyntex/polylang/flags/pn.png | Bin 0 -> 440 bytes .../vendor/wpsyntex/polylang/flags/pr.png | Bin 0 -> 333 bytes .../vendor/wpsyntex/polylang/flags/ps.png | Bin 0 -> 266 bytes .../vendor/wpsyntex/polylang/flags/pt.png | Bin 0 -> 360 bytes .../vendor/wpsyntex/polylang/flags/pw.png | Bin 0 -> 290 bytes .../vendor/wpsyntex/polylang/flags/py.png | Bin 0 -> 270 bytes .../vendor/wpsyntex/polylang/flags/qa.png | Bin 0 -> 204 bytes .../vendor/wpsyntex/polylang/flags/quebec.png | Bin 0 -> 157 bytes .../vendor/wpsyntex/polylang/flags/ro.png | Bin 0 -> 272 bytes .../vendor/wpsyntex/polylang/flags/rs.png | Bin 0 -> 263 bytes .../vendor/wpsyntex/polylang/flags/ru.png | Bin 0 -> 265 bytes .../vendor/wpsyntex/polylang/flags/rw.png | Bin 0 -> 315 bytes .../vendor/wpsyntex/polylang/flags/sa.png | Bin 0 -> 233 bytes .../vendor/wpsyntex/polylang/flags/sb.png | Bin 0 -> 361 bytes .../vendor/wpsyntex/polylang/flags/sc.png | Bin 0 -> 375 bytes .../wpsyntex/polylang/flags/scotland.png | Bin 0 -> 354 bytes .../vendor/wpsyntex/polylang/flags/sd.png | Bin 0 -> 280 bytes .../vendor/wpsyntex/polylang/flags/se.png | Bin 0 -> 248 bytes .../vendor/wpsyntex/polylang/flags/sg.png | Bin 0 -> 238 bytes .../vendor/wpsyntex/polylang/flags/sh.png | Bin 0 -> 389 bytes .../vendor/wpsyntex/polylang/flags/si.png | Bin 0 -> 312 bytes .../vendor/wpsyntex/polylang/flags/sk.png | Bin 0 -> 349 bytes .../vendor/wpsyntex/polylang/flags/sl.png | Bin 0 -> 272 bytes .../vendor/wpsyntex/polylang/flags/sm.png | Bin 0 -> 311 bytes .../vendor/wpsyntex/polylang/flags/sn.png | Bin 0 -> 284 bytes .../vendor/wpsyntex/polylang/flags/so.png | Bin 0 -> 238 bytes .../vendor/wpsyntex/polylang/flags/sr.png | Bin 0 -> 297 bytes .../vendor/wpsyntex/polylang/flags/ss.png | Bin 0 -> 194 bytes .../vendor/wpsyntex/polylang/flags/st.png | Bin 0 -> 375 bytes .../vendor/wpsyntex/polylang/flags/sv.png | Bin 0 -> 257 bytes .../vendor/wpsyntex/polylang/flags/sy.png | Bin 0 -> 239 bytes .../vendor/wpsyntex/polylang/flags/sz.png | Bin 0 -> 402 bytes .../vendor/wpsyntex/polylang/flags/tc.png | Bin 0 -> 413 bytes .../vendor/wpsyntex/polylang/flags/td.png | Bin 0 -> 291 bytes .../vendor/wpsyntex/polylang/flags/tf.png | Bin 0 -> 249 bytes .../vendor/wpsyntex/polylang/flags/tg.png | Bin 0 -> 355 bytes .../vendor/wpsyntex/polylang/flags/th.png | Bin 0 -> 252 bytes .../vendor/wpsyntex/polylang/flags/tibet.png | Bin 0 -> 381 bytes .../vendor/wpsyntex/polylang/flags/tj.png | Bin 0 -> 250 bytes .../vendor/wpsyntex/polylang/flags/tk.png | Bin 0 -> 397 bytes .../vendor/wpsyntex/polylang/flags/tl.png | Bin 0 -> 342 bytes .../vendor/wpsyntex/polylang/flags/tm.png | Bin 0 -> 309 bytes .../vendor/wpsyntex/polylang/flags/tn.png | Bin 0 -> 245 bytes .../vendor/wpsyntex/polylang/flags/to.png | Bin 0 -> 200 bytes .../vendor/wpsyntex/polylang/flags/tr.png | Bin 0 -> 236 bytes .../vendor/wpsyntex/polylang/flags/tt.png | Bin 0 -> 337 bytes .../vendor/wpsyntex/polylang/flags/tv.png | Bin 0 -> 331 bytes .../vendor/wpsyntex/polylang/flags/tw.png | Bin 0 -> 236 bytes .../vendor/wpsyntex/polylang/flags/tz.png | Bin 0 -> 388 bytes .../vendor/wpsyntex/polylang/flags/ua.png | Bin 0 -> 252 bytes .../vendor/wpsyntex/polylang/flags/ug.png | Bin 0 -> 353 bytes .../vendor/wpsyntex/polylang/flags/us.png | Bin 0 -> 350 bytes .../vendor/wpsyntex/polylang/flags/uy.png | Bin 0 -> 305 bytes .../vendor/wpsyntex/polylang/flags/uz.png | Bin 0 -> 313 bytes .../vendor/wpsyntex/polylang/flags/va.png | Bin 0 -> 305 bytes .../vendor/wpsyntex/polylang/flags/vc.png | Bin 0 -> 359 bytes .../vendor/wpsyntex/polylang/flags/ve.png | Bin 0 -> 332 bytes .../vendor/wpsyntex/polylang/flags/veneto.png | Bin 0 -> 350 bytes .../vendor/wpsyntex/polylang/flags/vg.png | Bin 0 -> 394 bytes .../vendor/wpsyntex/polylang/flags/vi.png | Bin 0 -> 415 bytes .../vendor/wpsyntex/polylang/flags/vn.png | Bin 0 -> 238 bytes .../vendor/wpsyntex/polylang/flags/vu.png | Bin 0 -> 369 bytes .../vendor/wpsyntex/polylang/flags/wales.png | Bin 0 -> 431 bytes .../vendor/wpsyntex/polylang/flags/wf.png | Bin 0 -> 265 bytes .../vendor/wpsyntex/polylang/flags/ws.png | Bin 0 -> 248 bytes .../vendor/wpsyntex/polylang/flags/ye.png | Bin 0 -> 246 bytes .../vendor/wpsyntex/polylang/flags/yt.png | Bin 0 -> 278 bytes .../vendor/wpsyntex/polylang/flags/za.png | Bin 0 -> 407 bytes .../vendor/wpsyntex/polylang/flags/zm.png | Bin 0 -> 261 bytes .../vendor/wpsyntex/polylang/flags/zw.png | Bin 0 -> 374 bytes .../polylang/frontend/accept-language.php | 112 + .../frontend/accept-languages-collection.php | 143 + .../wpsyntex/polylang/frontend/canonical.php | 269 ++ .../polylang/frontend/choose-lang-content.php | 166 + .../polylang/frontend/choose-lang-domain.php | 45 + .../polylang/frontend/choose-lang-url.php | 118 + .../polylang/frontend/choose-lang.php | 351 ++ .../frontend/frontend-auto-translate.php | 331 ++ .../frontend/frontend-filters-links.php | 350 ++ .../frontend/frontend-filters-search.php | 183 + .../frontend/frontend-filters-widgets.php | 153 + .../polylang/frontend/frontend-filters.php | 210 + .../polylang/frontend/frontend-links.php | 228 + .../polylang/frontend/frontend-nav-menu.php | 339 ++ .../frontend/frontend-static-pages.php | 318 ++ .../wpsyntex/polylang/frontend/frontend.php | 287 ++ .../vendor/wpsyntex/polylang/include/api.php | 574 +++ .../vendor/wpsyntex/polylang/include/base.php | 219 + .../wpsyntex/polylang/include/cache.php | 121 + .../polylang/include/class-polylang.php | 298 ++ .../wpsyntex/polylang/include/cookie.php | 107 + .../wpsyntex/polylang/include/crud-posts.php | 484 ++ .../wpsyntex/polylang/include/crud-terms.php | 346 ++ .../wpsyntex/polylang/include/db-tools.php | 48 + .../polylang/include/filter-rest-routes.php | 178 + .../polylang/include/filters-links.php | 202 + .../polylang/include/filters-sanitization.php | 106 + .../include/filters-widgets-options.php | 92 + .../wpsyntex/polylang/include/filters.php | 472 ++ .../wpsyntex/polylang/include/functions.php | 237 + .../polylang/include/language-deprecated.php | 256 + .../polylang/include/language-factory.php | 338 ++ .../wpsyntex/polylang/include/language.php | 675 +++ .../wpsyntex/polylang/include/license.php | 355 ++ .../include/links-abstract-domain.php | 114 + .../polylang/include/links-default.php | 116 + .../polylang/include/links-directory.php | 295 ++ .../polylang/include/links-domain.php | 121 + .../wpsyntex/polylang/include/links-model.php | 264 ++ .../polylang/include/links-permalinks.php | 219 + .../polylang/include/links-subdomain.php | 92 + .../wpsyntex/polylang/include/links.php | 71 + .../vendor/wpsyntex/polylang/include/mo.php | 77 + .../wpsyntex/polylang/include/model.php | 1050 +++++ .../wpsyntex/polylang/include/nav-menu.php | 177 + .../wpsyntex/polylang/include/olt-manager.php | 254 + .../wpsyntex/polylang/include/query.php | 234 + .../polylang/include/rest-request.php | 125 + .../polylang/include/static-pages.php | 230 + .../wpsyntex/polylang/include/switcher.php | 293 ++ ...anslatable-object-with-types-interface.php | 45 + .../translatable-object-with-types-trait.php | 64 + .../polylang/include/translatable-object.php | 519 ++ .../polylang/include/translatable-objects.php | 130 + .../polylang/include/translate-option.php | 404 ++ .../polylang/include/translated-object.php | 567 +++ .../polylang/include/translated-post.php | 396 ++ .../polylang/include/translated-term.php | 341 ++ .../polylang/include/walker-dropdown.php | 95 + .../wpsyntex/polylang/include/walker-list.php | 64 + .../wpsyntex/polylang/include/walker.php | 73 + .../polylang/include/widget-calendar.php | 282 ++ .../polylang/include/widget-languages.php | 141 + .../polylang/install/install-base.php | 134 + .../wpsyntex/polylang/install/install.php | 148 + .../polylang/install/plugin-updater.php | 645 +++ .../vendor/wpsyntex/polylang/install/t15s.php | 237 + .../wpsyntex/polylang/install/upgrade.php | 288 ++ .../aqua-resizer/aqua-resizer.php | 32 + .../integrations/aqua-resizer/load.php | 13 + .../integrations/cache/cache-compat.php | 105 + .../polylang/integrations/cache/load.php | 20 + .../custom-field-template/cft.php | 35 + .../custom-field-template/load.php | 21 + .../domain-mapping/domain-mapping.php | 82 + .../integrations/domain-mapping/load.php | 12 + .../duplicate-post/duplicate-post.php | 37 + .../integrations/duplicate-post/load.php | 21 + .../polylang/integrations/integrations.php | 50 + .../integrations/jetpack/featured-content.php | 121 + .../polylang/integrations/jetpack/jetpack.php | 137 + .../polylang/integrations/jetpack/load.php | 14 + .../integrations/no-category-base/load.php | 13 + .../no-category-base/no-category-base.php | 36 + .../integrations/twenty-seventeen/load.php | 12 + .../twenty-seventeen/twenty-seven-teen.php | 30 + .../integrations/wp-importer/load.php | 12 + .../wp-importer/wordpress-importer.php | 70 + .../integrations/wp-importer/wp-import.php | 204 + .../integrations/wp-offload-media/as3cf.php | 72 + .../integrations/wp-offload-media/load.php | 20 + .../polylang/integrations/wp-sweep/load.php | 21 + .../integrations/wp-sweep/wp-sweep.php | 62 + .../polylang/integrations/wpseo/load.php | 20 + .../polylang/integrations/wpseo/wpseo-ogp.php | 54 + .../polylang/integrations/wpseo/wpseo.php | 517 ++ .../polylang/integrations/yarpp/load.php | 20 + .../polylang/integrations/yarpp/yarpp.php | 20 + .../vendor/wpsyntex/polylang/js/src/admin.js | 426 ++ .../wpsyntex/polylang/js/src/block-editor.js | 238 + .../polylang/js/src/classic-editor.js | 308 ++ .../polylang/js/src/lib/confirmation-modal.js | 99 + .../js/src/lib/filter-path-middleware.js | 22 + .../js/src/lib/metabox-autocomplete.js | 41 + .../wpsyntex/polylang/js/src/nav-menu.js | 104 + .../vendor/wpsyntex/polylang/js/src/post.js | 183 + .../vendor/wpsyntex/polylang/js/src/term.js | 231 + .../vendor/wpsyntex/polylang/js/src/user.js | 33 + .../wpsyntex/polylang/js/src/widgets.js | 151 + .../modules/machine-translation/load.php | 18 + .../settings-preview-machine-translation.php | 46 + .../polylang/modules/share-slug/load.php | 20 + .../settings-preview-share-slug.php | 56 + .../modules/site-health/admin-site-health.php | 520 ++ .../polylang/modules/site-health/load.php | 14 + .../modules/sitemaps/abstract-sitemaps.php | 37 + .../polylang/modules/sitemaps/load.php | 17 + .../multilingual-sitemaps-provider.php | 218 + .../modules/sitemaps/sitemaps-domain.php | 71 + .../polylang/modules/sitemaps/sitemaps.php | 128 + .../polylang/modules/sync/admin-sync.php | 233 + .../wpsyntex/polylang/modules/sync/load.php | 26 + .../polylang/modules/sync/settings-sync.php | 115 + .../polylang/modules/sync/sync-metas.php | 406 ++ .../polylang/modules/sync/sync-post-metas.php | 94 + .../polylang/modules/sync/sync-tax.php | 310 ++ .../polylang/modules/sync/sync-term-metas.php | 25 + .../wpsyntex/polylang/modules/sync/sync.php | 268 ++ .../polylang/modules/translate-slugs/load.php | 20 + .../settings-preview-translate-slugs.php | 56 + .../polylang/modules/wizard/css/wizard.css | 951 ++++ .../modules/wizard/html-wizard-notice.php | 49 + .../wizard/images/media-screen-rtl.png | Bin 0 -> 21885 bytes .../modules/wizard/images/media-screen.png | Bin 0 -> 27311 bytes .../modules/wizard/images/polylang-logo.png | Bin 0 -> 980 bytes .../modules/wizard/js/languages-step.js | 302 ++ .../wpsyntex/polylang/modules/wizard/load.php | 14 + .../modules/wizard/view-wizard-page.php | 108 + .../wizard/view-wizard-step-home-page.php | 135 + .../wizard/view-wizard-step-languages.php | 136 + .../modules/wizard/view-wizard-step-last.php | 114 + .../wizard/view-wizard-step-licenses.php | 38 + .../modules/wizard/view-wizard-step-media.php | 62 + ...view-wizard-step-untranslated-contents.php | 37 + .../polylang/modules/wizard/wizard.php | 855 ++++ .../wpsyntex/polylang/modules/wpml/load.php | 17 + .../polylang/modules/wpml/wpml-api.php | 495 ++ .../polylang/modules/wpml/wpml-compat.php | 193 + .../polylang/modules/wpml/wpml-config.php | 1048 ++++ .../polylang/modules/wpml/wpml-legacy-api.php | 418 ++ .../vendor/wpsyntex/polylang/polylang.php | 78 + .../vendor/wpsyntex/polylang/readme.md | 29 + .../vendor/wpsyntex/polylang/readme.txt | 167 + .../wpsyntex/polylang/settings/flags.php | 276 ++ .../wpsyntex/polylang/settings/languages.php | 1292 +++++ .../polylang/settings/settings-browser.php | 107 + .../polylang/settings/settings-cpt.php | 177 + .../polylang/settings/settings-licenses.php | 147 + .../polylang/settings/settings-media.php | 37 + .../polylang/settings/settings-module.php | 379 ++ .../polylang/settings/settings-url.php | 332 ++ .../wpsyntex/polylang/settings/settings.php | 414 ++ .../polylang/settings/table-languages.php | 277 ++ .../polylang/settings/table-settings.php | 194 + .../polylang/settings/table-string.php | 449 ++ .../wpsyntex/polylang/settings/view-about.php | 30 + .../polylang/settings/view-languages.php | 35 + .../polylang/settings/view-tab-lang.php | 178 + .../polylang/settings/view-tab-settings.php | 19 + .../polylang/settings/view-tab-strings.php | 33 + .../vendor/wpsyntex/polylang/uninstall.php | 136 + 714 files changed, 87192 insertions(+), 4 deletions(-) create mode 100644 wp-content/plugins/polylang-pro/LICENSE create mode 100644 wp-content/plugins/polylang-pro/changelog.txt create mode 100644 wp-content/plugins/polylang-pro/css/build/admin-export-import.css create mode 100644 wp-content/plugins/polylang-pro/css/build/admin-export-import.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/admin.css create mode 100644 wp-content/plugins/polylang-pro/css/build/admin.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/bulk-translate.css create mode 100644 wp-content/plugins/polylang-pro/css/build/bulk-translate.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/dialog.css create mode 100644 wp-content/plugins/polylang-pro/css/build/dialog.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/machine-translation-settings.css create mode 100644 wp-content/plugins/polylang-pro/css/build/machine-translation-settings.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/metabox-button.css create mode 100644 wp-content/plugins/polylang-pro/css/build/metabox-button.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/selectmenu.css create mode 100644 wp-content/plugins/polylang-pro/css/build/selectmenu.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/style.css create mode 100644 wp-content/plugins/polylang-pro/css/build/style.min.css create mode 100644 wp-content/plugins/polylang-pro/css/build/wizard.css create mode 100644 wp-content/plugins/polylang-pro/css/build/wizard.min.css create mode 100644 wp-content/plugins/polylang-pro/include/format-util.php create mode 100644 wp-content/plugins/polylang-pro/include/functions.php create mode 100644 wp-content/plugins/polylang-pro/include/pro.php create mode 100644 wp-content/plugins/polylang-pro/integrations/acf/acf-auto-translate.php create mode 100644 wp-content/plugins/polylang-pro/integrations/acf/acf-sync-metas.php create mode 100644 wp-content/plugins/polylang-pro/integrations/acf/acf.php create mode 100644 wp-content/plugins/polylang-pro/integrations/acf/js/acf.js create mode 100644 wp-content/plugins/polylang-pro/integrations/acf/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/admin-columns/cpac.php create mode 100644 wp-content/plugins/polylang-pro/integrations/admin-columns/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/beaver-builder/flbuilder.php create mode 100644 wp-content/plugins/polylang-pro/integrations/beaver-builder/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/content-blocks/content-blocks.php create mode 100644 wp-content/plugins/polylang-pro/integrations/content-blocks/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/cptui/cptui.php create mode 100644 wp-content/plugins/polylang-pro/integrations/cptui/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/divi/divi-builder.php create mode 100644 wp-content/plugins/polylang-pro/integrations/divi/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/events-calendar/load.php create mode 100644 wp-content/plugins/polylang-pro/integrations/events-calendar/tec.php create mode 100644 wp-content/plugins/polylang-pro/js/build/acf.js create mode 100644 wp-content/plugins/polylang-pro/js/build/acf.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/admin.js create mode 100644 wp-content/plugins/polylang-pro/js/build/admin.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/block-editor-plugin.js create mode 100644 wp-content/plugins/polylang-pro/js/build/block-editor-plugin.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/block-editor.js create mode 100644 wp-content/plugins/polylang-pro/js/build/block-editor.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/blocks.js create mode 100644 wp-content/plugins/polylang-pro/js/build/blocks.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/bulk-translate.js create mode 100644 wp-content/plugins/polylang-pro/js/build/bulk-translate.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/classic-editor.js create mode 100644 wp-content/plugins/polylang-pro/js/build/classic-editor.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/confirmation-modal.js create mode 100644 wp-content/plugins/polylang-pro/js/build/confirmation-modal.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/filter-path-middleware.js create mode 100644 wp-content/plugins/polylang-pro/js/build/filter-path-middleware.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/languages-step.js create mode 100644 wp-content/plugins/polylang-pro/js/build/languages-step.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/machine-translation-settings.js create mode 100644 wp-content/plugins/polylang-pro/js/build/machine-translation-settings.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.js create mode 100644 wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/metabox-button.js create mode 100644 wp-content/plugins/polylang-pro/js/build/metabox-button.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/nav-menu.js create mode 100644 wp-content/plugins/polylang-pro/js/build/nav-menu.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/post.js create mode 100644 wp-content/plugins/polylang-pro/js/build/post.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/sidebar.js create mode 100644 wp-content/plugins/polylang-pro/js/build/sidebar.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/term.js create mode 100644 wp-content/plugins/polylang-pro/js/build/term.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/user.js create mode 100644 wp-content/plugins/polylang-pro/js/build/user.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.js create mode 100644 wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.min.js create mode 100644 wp-content/plugins/polylang-pro/js/build/widgets.js create mode 100644 wp-content/plugins/polylang-pro/js/build/widgets.min.js create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Action.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Button.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Button_REST.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Clients/Client_Interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Clients/Deepl.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Data.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Factory.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Module_Settings.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Processor.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Deepl.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Service_Interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Deepl.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Settings_Interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-characters-consumption-row.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-deepl-formality-row.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notice.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notices-row.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-progress-bar.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-service-authentication-row.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/css/machine-translation-settings.css create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/js/machine-translation-settings.js create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/Machine_Translation/uninstall.php create mode 100644 wp-content/plugins/polylang-pro/modules/active-languages/active-languages.php create mode 100644 wp-content/plugins/polylang-pro/modules/active-languages/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/abstract-language-switcher-block.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/block-editor-plugin.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/frontend-filters-widgets-blocks.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/language-switcher-block.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/navigation-language-switcher-block.php create mode 100644 wp-content/plugins/polylang-pro/modules/block-editor/widget-editor-language-attribute.php create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/bulk-translate-option.php create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/bulk-translate.php create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/css/bulk-translate.css create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/js/bulk-translate.js create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/view-bulk-translate-option.php create mode 100644 wp-content/plugins/polylang-pro/modules/bulk-translate/view-bulk-translate.php create mode 100644 wp-content/plugins/polylang-pro/modules/duplicate/duplicate-action.php create mode 100644 wp-content/plugins/polylang-pro/modules/duplicate/duplicate-rest.php create mode 100644 wp-content/plugins/polylang-pro/modules/duplicate/duplicate.php create mode 100644 wp-content/plugins/polylang-pro/modules/duplicate/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/duplicate/uninstall.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-abstract-bulk-edit-template-slugs-module.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-abstract-module.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-default-language-change.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-filter-block-types.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-language-slug-change.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-language.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-post-deletion.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-post-types.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-query-filters.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-recreate-language.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-rest-duplicate-template.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-rest-enforce-default-template.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-rest-route.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-rest-template.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-template-model.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-template-slug-sync.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-template-slug.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/fse-tools.php create mode 100644 wp-content/plugins/polylang-pro/modules/full-site-editing/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/assets/css/admin-export-import.css create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/export-bulk-option.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/export-download.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/export-file.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/export-strings-action.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/view-export-file-format.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/export/view-tab-export-strings.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/file-format/file-format-factory.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/file-format/file-format.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import-export.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-action.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-file-interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-object-interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-posts.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-strings.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/import-terms.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/import/view-tab-import-translations.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/po/po-export.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/po/po-format.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/po/po-import.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/export/xliff-export-12.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/export/xliff-export-20.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/export/xliff-export-21.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/export/xliff-export-base.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/xliff-format.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/xliff-import-parser-12.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/xliff-import-parser-21.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/xliff-import-parser-base.php create mode 100644 wp-content/plugins/polylang-pro/modules/import-export/xliff/xliff-import.php create mode 100644 wp-content/plugins/polylang-pro/modules/locale-fallback/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/locale-fallback/locale-fallback.php create mode 100644 wp-content/plugins/polylang-pro/modules/locale-fallback/view-locale-fallback.php create mode 100644 wp-content/plugins/polylang-pro/modules/media/admin-advanced-media.php create mode 100644 wp-content/plugins/polylang-pro/modules/media/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/media/media-bulk-option.php create mode 100644 wp-content/plugins/polylang-pro/modules/media/settings-advanced-media.php create mode 100644 wp-content/plugins/polylang-pro/modules/module-interface.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-api.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-comment.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-filtered-object.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-post.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-term.php create mode 100644 wp-content/plugins/polylang-pro/modules/rest/rest-translated-object.php create mode 100644 wp-content/plugins/polylang-pro/modules/share-slug/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/share-slug/settings-share-slug.php create mode 100644 wp-content/plugins/polylang-pro/modules/share-slug/share-post-slug.php create mode 100644 wp-content/plugins/polylang-pro/modules/share-slug/share-term-slug.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/sync-post-bulk-option.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/sync-post-button.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/sync-post-model.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/sync-post-rest.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync-post/sync-post.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync/sync-content.php create mode 100644 wp-content/plugins/polylang-pro/modules/sync/sync-navigation.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/frontend-translate-slugs.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/settings-translate-slugs.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/translate-slugs-model.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/translate-slugs.php create mode 100644 wp-content/plugins/polylang-pro/modules/translate-slugs/uninstall.php create mode 100644 wp-content/plugins/polylang-pro/modules/wizard/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/wizard/wizard-pro.php create mode 100644 wp-content/plugins/polylang-pro/modules/xdata/load.php create mode 100644 wp-content/plugins/polylang-pro/modules/xdata/xdata-base.php create mode 100644 wp-content/plugins/polylang-pro/modules/xdata/xdata-domain.php create mode 100644 wp-content/plugins/polylang-pro/modules/xdata/xdata-session-manager.php create mode 100644 wp-content/plugins/polylang-pro/modules/xdata/xdata-subdomain.php create mode 100644 wp-content/plugins/polylang-pro/polylang.php create mode 100644 wp-content/plugins/polylang-pro/readme.txt create mode 100644 wp-content/plugins/polylang-pro/services/admin-loader/admin-loader.php create mode 100644 wp-content/plugins/polylang-pro/services/collect-linked-objects/collect-linked-posts.php create mode 100644 wp-content/plugins/polylang-pro/services/collect-linked-objects/collect-linked-terms.php create mode 100644 wp-content/plugins/polylang-pro/services/context.php create mode 100644 wp-content/plugins/polylang-pro/services/data-encoding.php create mode 100644 wp-content/plugins/polylang-pro/services/dom/dom-content.php create mode 100644 wp-content/plugins/polylang-pro/services/dom/dom-document.php create mode 100644 wp-content/plugins/polylang-pro/services/dom/dom-nodes-iterator.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-container.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-data-from-posts.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-data-from-strings.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-data.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-post-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-posts.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-strings.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-term-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-terms.php create mode 100644 wp-content/plugins/polylang-pro/services/exporter/export-translated-objects.php create mode 100644 wp-content/plugins/polylang-pro/services/manage-user-capabilities.php create mode 100644 wp-content/plugins/polylang-pro/services/metabox-button/css/metabox-button.css create mode 100644 wp-content/plugins/polylang-pro/services/metabox-button/js/metabox-button.js create mode 100644 wp-content/plugins/polylang-pro/services/metabox-button/metabox-button.php create mode 100644 wp-content/plugins/polylang-pro/services/metabox-button/metabox-user-button.php create mode 100644 wp-content/plugins/polylang-pro/services/metabox-button/toggle-user-meta.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-block-parsing-rules.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-content.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-object-model-interface.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-post-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-post-model.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-term-metas.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-term-model.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-walker-blocks.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-walker-classic.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-walker-factory.php create mode 100644 wp-content/plugins/polylang-pro/services/translation/translation-walker-interface.php create mode 100644 wp-content/plugins/polylang-pro/uninstall.php create mode 100644 wp-content/plugins/polylang-pro/vendor/autoload.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/ClassLoader.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/InstalledVersions.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/LICENSE create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/autoload_classmap.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/autoload_namespaces.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/autoload_psr4.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/autoload_real.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/autoload_static.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/installed.json create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/installed.php create mode 100644 wp-content/plugins/polylang-pro/vendor/composer/platform_check.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/LICENSE create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-base.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-block-editor.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-classic-editor.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-default-term.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-columns.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-media.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-post-base.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-post.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-term.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters-widgets-options.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-filters.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-links.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-model.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-nav-menu.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-notices.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-static-pages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin-strings.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/admin.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/view-translations-media.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/view-translations-post.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/admin/view-translations-term.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/changelog.txt create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/css/src/admin.css create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/css/src/dialog.css create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/css/src/selectmenu.css create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ad.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ae.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/af.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ag.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ai.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/al.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/am.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/an.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ao.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ar.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/arab.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/as.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/at.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/au.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/aw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ax.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/az.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ba.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/basque.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bb.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bd.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/be.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bi.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bj.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bo.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/br.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bs.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/by.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/bz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ca.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/catalonia.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cd.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ch.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ci.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ck.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/co.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cv.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cx.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cy.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/cz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/de.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/dj.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/dk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/dm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/do.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/dz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ec.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ee.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/eg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/eh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/england.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/er.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/es.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/esperanto.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/et.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fi.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fj.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fo.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/fr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ga.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/galicia.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gb.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gd.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ge.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gi.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gp.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gq.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gs.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/gy.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/hk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/hm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/hn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/hr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ht.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/hu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/id.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ie.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/il.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/in.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/io.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/iq.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ir.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/is.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/it.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/jm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/jo.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/jp.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ke.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ki.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/km.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kp.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kurdistan.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ky.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/kz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/la.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lb.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/li.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ls.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/lv.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ly.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ma.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/md.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/me.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ml.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mo.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mp.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mq.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ms.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mv.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mx.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/my.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/mz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/na.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ne.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ng.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ni.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/no.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/np.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/nz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/occitania.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/om.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pa.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pe.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ph.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ps.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/pw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/py.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/qa.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/quebec.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ro.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/rs.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ru.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/rw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sa.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sb.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/scotland.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sd.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/se.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sh.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/si.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/so.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ss.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/st.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sv.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sy.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/sz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/td.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/th.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tibet.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tj.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tk.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/to.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tr.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tv.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/tz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ua.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ug.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/us.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/uy.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/uz.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/va.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/vc.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ve.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/veneto.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/vg.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/vi.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/vn.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/vu.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/wales.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/wf.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ws.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/ye.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/yt.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/za.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/zm.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/flags/zw.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/accept-language.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/accept-languages-collection.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/canonical.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/choose-lang-content.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/choose-lang-domain.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/choose-lang-url.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/choose-lang.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-auto-translate.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-filters-links.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-filters-search.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-filters-widgets.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-filters.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-links.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-nav-menu.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend-static-pages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/frontend/frontend.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/api.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/base.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/cache.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/class-polylang.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/cookie.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/crud-posts.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/crud-terms.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/db-tools.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/filter-rest-routes.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/filters-links.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/filters-sanitization.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/filters-widgets-options.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/filters.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/functions.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/language-deprecated.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/language-factory.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/language.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/license.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-abstract-domain.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-default.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-directory.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-domain.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-model.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-permalinks.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links-subdomain.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/links.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/mo.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/model.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/nav-menu.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/olt-manager.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/query.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/rest-request.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/static-pages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/switcher.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translatable-object-with-types-interface.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translatable-object-with-types-trait.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translatable-object.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translatable-objects.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translate-option.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translated-object.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translated-post.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/translated-term.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/walker-dropdown.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/walker-list.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/walker.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/widget-calendar.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/include/widget-languages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/install-base.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/install.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/plugin-updater.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/t15s.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/upgrade.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/aqua-resizer.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/cache-compat.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/cft.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/domain-mapping.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/duplicate-post/duplicate-post.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/duplicate-post/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/integrations.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/featured-content.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/jetpack.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/no-category-base.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/twenty-seventeen/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/twenty-seventeen/twenty-seven-teen.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wordpress-importer.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wp-import.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/as3cf.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/wp-sweep.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo-ogp.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/yarpp.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/admin.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/block-editor.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/classic-editor.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/filter-path-middleware.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/nav-menu.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/post.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/term.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/user.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/widgets.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/settings-preview-machine-translation.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/settings-preview-share-slug.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/admin-site-health.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/abstract-sitemaps.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/multilingual-sitemaps-provider.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps-domain.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/admin-sync.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/settings-sync.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-metas.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-post-metas.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-tax.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-term-metas.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/settings-preview-translate-slugs.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/css/wizard.css create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/html-wizard-notice.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen-rtl.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/polylang-logo.png create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/js/languages-step.js create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-page.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-home-page.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-languages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-last.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-licenses.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-media.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-untranslated-contents.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/wizard.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/load.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-api.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-compat.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-config.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-legacy-api.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/polylang.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.md create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.txt create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/flags.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/languages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-browser.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-cpt.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-licenses.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-media.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-module.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-url.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-languages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-settings.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-string.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-about.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-languages.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-lang.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-settings.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-strings.php create mode 100644 wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/uninstall.php diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ccc2a84ab..2a2317804 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,6 +57,7 @@ jobs: mv wp-content/mu-plugins/pub/class-validator.php $RUNNER_TEMP mv wp-content/mu-plugins/pub/locales.php $RUNNER_TEMP mv wp-content/mu-plugins/pub/wporg-learn-cli.php $RUNNER_TEMP + mv wp-content/plugins/polylang-pro $RUNNER_TEMP mv wp-content/plugins/sensei-pro $RUNNER_TEMP mv wp-content/plugins/wporg-learn $RUNNER_TEMP mv wp-content/themes/pub/wporg-learn-2024 $RUNNER_TEMP @@ -69,6 +70,7 @@ jobs: mv $RUNNER_TEMP/class-validator.php wp-content/mu-plugins/pub mv $RUNNER_TEMP/locales.php wp-content/mu-plugins/pub mv $RUNNER_TEMP/wporg-learn-cli.php wp-content/mu-plugins/pub + mv $RUNNER_TEMP/polylang-pro wp-content/plugins mv $RUNNER_TEMP/sensei-pro wp-content/plugins mv $RUNNER_TEMP/wporg-learn wp-content/plugins mv $RUNNER_TEMP/wporg-learn-2024 wp-content/themes/pub diff --git a/.gitignore b/.gitignore index 0943e3ccd..80fdc6b63 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ /wp-content/* /wp-content/mu-plugins/* /wp-content/mu-plugins/pub/* -/wp-content/mu-plugins/pub/locale-switcher/build /wp-content/plugins/* /wp-content/themes/* /wp-content/themes/pub/* @@ -33,9 +32,9 @@ !/wp-content/plugins !/wp-content/plugins/wporg-learn !/wp-content/plugins/sensei-pro +!/wp-content/plugins/polylang-pro +!/wp-content/plugins/polylang-pro/css/build/ +!/wp-content/plugins/polylang-pro/js/build/ !/wp-content/themes !/wp-content/themes/pub !/wp-content/themes/pub/wporg-learn-2024 - -# Ignore subfolders in our custom code. -/wp-content/plugins/wporg-learn/build diff --git a/wp-content/plugins/polylang-pro/LICENSE b/wp-content/plugins/polylang-pro/LICENSE new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/wp-content/plugins/polylang-pro/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/wp-content/plugins/polylang-pro/changelog.txt b/wp-content/plugins/polylang-pro/changelog.txt new file mode 100644 index 000000000..9be0f27e2 --- /dev/null +++ b/wp-content/plugins/polylang-pro/changelog.txt @@ -0,0 +1,2325 @@ +== Changelog == + +This file contains only old changelog. See readme.txt for newer versions. + += 3.5.4 (2024-02-06) = + +* Pro: Fix an accessibility issue int the navigation language switcher block +* Pro: Fix featured image not exported for posts with blocks +* Pro: Fix a conflict with the Flatsome builder +* Fix a notice when using system CRON. Props arielruminski #1397 +* Fix an edge case where a wrong post tag may be assigned to a post #1418 + += 3.5.3 (2023-12-11) = + +* Pro: Fix fatal error with The Events Calendar when rewrite param of event category is set to false +* Remove flag alt text in the language switcher when both the flag and language name are displayed #1393 +* Fix incorrect string translations when 2 languages are sharing the same locale in a multisite #1378 +* Fix posts lists not filtered by the current language when editing a post in the block editor #1386 +* Fix error when a tax query is filled with unexpected data #1396 + += 3.5.2 (2023-10-25) = + +* Pro: Fix terms not filtered by the current language in the block editor custom taxonomy component panel +* Fix incorrect rewrite rules leading to error 404 for the main site on mutisite #1375 + += 3.5.1 (2023-10-17) = + +* Pro: Fix terms not filtered by the current language in the block editor custom taxonomy component panel +* Pro: Fix fatal error when using plain permalinks on multisite +* Pro: Fix rewrite rules incorrectly refreshed when saving strings translations +* Fix incorrect rewrite rules leading to error 404 on mutisite #1366 +* Fix fatal error when using symlinked MU plugins that are not in open_basedir #1368 + += 3.5 (2023-10-09) = + +* Requires WordPress 5.9 as minimum version +* Pro: Manage navigation blocks translations in the site editor (requires WP 6.3) +* Pro: Manage pages translations in the site editor (requires WP 6.3) +* Pro: Manage patterns translations in the site editor (requires WP 6.3) +* Pro: Remove compatibility with the navigation screen removed from Gütenberg 15.1 +* Pro: Add filter 'pll_export_post_fields' to control post fields exported to XLIFF files +* Pro: Do not set default translation option to "translate" for ACF fields created before Polylang Pro is activated +* Pro: Fix Polylang not set as recently active when automatically deactivated by Polylang Pro +* Don't output javascript type for themes supporting html5 #1332 +* Hook WP_Query automatic translation to 'parse_query' instead of 'pre_get_posts' #1339 +* Improve preload paths management for the block editor #1341 +* Fix rewrite rules in WP 6.4 #1345 +* Fix: always assign the default language to new posts and terms if no language is specified #1351 +* Fix 'polylang' option not correctly created when a new site is created on a multisite #1319 +* Fix front page display switched to "Your latest posts" when deleting a static home page translation #1311 +* Fix wrong language assigned to terms #1336 +* Fix error when updating a translated option while the blog is switched on a multisite #1342 + += 3.4.6 (2023-09-13) = + +* Pro: Security: Fix unsafe custom style injection in navigation language switcher block + += 3.4.5 (2023-08-07) = + +* Requires PHP 7.0 as minimum version +* Pro: Fix error in site editor with WP 6.3 +* Pro: Remove usage of block_core_navigation_submenu_build_css_colors() deprecated in WP 6.3 +* Pro: Fix categories and tags kept in old language after the language of a post has been changed +* Add 'pll_admin_ajax_params' filter #1326 +* Fix error when changing the language of a post and the post type doesn't support excerpts #1323 + += 3.4.4 (2023-07-18) = + +* Pro: Register a default (empty) value for the "lang" param when listing posts and terms in REST API +* Pro: Fix categories list refresh when the language of a post is changed in the block editor +* Pro: Fix store "pll/metabox" is already registered +* Add Kirghiz to the predefined list of languages #1308 +* Fix incorrect flag url when WordPress is installed in a subfolder #1296 +* Fix wrong home page url in multisite #1300 + += 3.4.3 (2023-06-13) = + +* Adapt the language filter for `get_pages()` for WP 6.3 #1268 +* Fix static front page displaying latest posts when it is not translated #1295 +* Fix a database error in ANSI mode #1297 +* Fix a database error when accessing posts from another site in multisite #1301 + += 3.4.2 (2023-05-30) = + +* Fix empty languages displayed when Falang data are remaining in the database #1286 +* Fix PHP warning on term_props #1288 +* Fix blog page displayed in the customizer instead of the static front page when changing a setting #1289 + += 3.4.1 (2023-05-25) = + +* Fix incorrect site titles in My Site admin bar menu on multisites #1284 +* Fix incorrect home url when using multiple domains or subdomain and a static front page #1285 + += 3.4 (2023-05-23) = + +* Requires WP 5.8 as minimum version +* Pro: Language fallbacks are now stored in language description instead of a term meta. +* Pro: Add more error messages when doing wrong when importing or exporting translations +* Pro: Avoid to check for translations files existence if no language fallbacks are defined. +* Pro: Reduce the number of DB queries when exporting posts for translation +* Pro: Fix incorrect post slug after XLIFF import +* Pro: Fix a performance issue with the autocomplete field in the block editor languages panel +* Pro: Fix translations not refreshed when switching the language in the block editor sidebar +* Pro: Fix a performance issue in Site editor +* Pro: Fix a possible bug in Site editor when language term_id and term_taxonomy_id are different +* Pro: Fix deactivated language re-activated when it is edited. +* Pro: Fix language switcher in legacy widget menu not correctly rendered in widget block editor +* Pro: Fix error 404 for untranslated attached attachement +* Pro: Fix a deprecated notice in ACF integration +* Pro: Fix update compatibility with WP Umbrella +* Refactor core to allow to easily translate contents stored in custom tables +* Strings translations are now stored in a language term meta instead of post meta of specific post type #1209 +* Deprecate the filters `pll_languages_list` and `pll_after_languages_cache` #1210 +* Add a new property `PLL_Language::$is_default` #1228 +* Add a custom admin body class `pll-lang-{$language_code}` #1190 +* Add support for new WPML API filters #1266 +* Fix languages metabox autocomplete field not always returning expected results #1187 +* Fix language not displayed if the transient has been saved with an empty array #1247 +* Fix a PHP warning `Attempt to read property "home_url" on bool` #1206 +* Fix a conflict leading to a performance issue when translating the theme Astra options #1196 +* Fix related translations resetted when updating Yoast SEO titles settings #1111 +* Fix a fatal error in case the registered strings option is corrupted #1264 +* Fix the language extraction from the URL in plain permalinks #1270 +* Fix content cleared when switching the language of a new post in the block editor #1272 +* Fix: Prevent saving strings translations with an empty source #1273 + += 3.3.3 (2023-04-11) = + +* Pro: Adapt the submenu colors of the navigation language switcher block to WP 6.2 +* Pro: Fix the dropdown setting in the navigation language switcher block +* Add Amharic, Aragonese and Spanish from Dominican Republic to the list of predefined languages #1248 +* Fix a deprecated notice in WP 6.2 when using multiple domains without the Internationalization PHP extension (intl) #1245 + += 3.3.2 (2023-03-06) = + +* Pro: Add compatibility with FSE changes introduced by WP 6.2 +* Pro: Adapt the navigation language switcher block for consistency with WP 6.2 +* Only store term ids in taxonomy relationships cache for WP 6.0+. Props @ocean90 #1154 +* Remove usage of `get_page_by_title()` deprecated in WP 6.2 #1213 +* Fix fatal error if the mu-plugins folder is not readable #1217 +* Fix a compatibility issue with plugins not expecting a null 'update_plugins' transient #1224 + += 3.3.1 (2023-01-09) = + +* Pro: Allow to translate Oembed, URL and Email ACF fields +* Pro: Fix ACF REST API mixing fields +* Pro: Fix ACF compatibility loaded when no language exist +* Pro: Fix headers of exported PO files. +* Pro: Fix spacing in language switcher navigation block preview +* Work around a bug in Sendinblue for WooCommerce causing a fatal error. #1156 +* Fix a regression with WooCommerce Product Add-Ons Ultimate. #1186 + += 3.3 (2022-11-28) = + +* Requires WP 5.7 as minimum version +* Pro: Allow to export and import XLIFF files for posts +* Pro: Honor the provided context for the navigation language switcher block. +* Pro: Remove the parent hyperlink in the navigation language switcher block. +* Pro: Add spacing between flag and name in the navigation language switcher block. +* Pro: Disallow some special characters in translated slugs to avoid 404 errors. +* Pro: Fix string translation not imported when the original is registered but has never been saved in database. +* Pro: Fix string translation not imported when it includes an html entity. +* Pro: Fix navigation language switcher block rendering in block editor. +* Pro: Fix navigation language switcher may be displayed wrong color. +* Translate the post pages in get_post_type_archive_link() on admin side too. #1000 +* Enable the block editor in page for posts translations to match the WordPress behavior since version 5.8 #1002 +* Improve the site health report #1062 #1076 +* Set the current language when saving a post #1065 +* The search block is now filtered by language #1081 +* Display slug of CPT and taxonomies in Custom post types and Taxonomies settings. Props @nicomollet #1112 +* Add support for wpml-config.xml to MU plugins #1140 Props Jeremy Simkins +* Fix some deprecated notices fired by PHP 8.1 #975 +* Fix some missing canonical redirect taxonomies #1074 +* Fix redirect when permalink structure has no trailing slash #1080 +* Fix language switcher in legacy navigation menu widget not rendered in widgets block editor #1083 +* Fix language in tax query when an OR relation is used #1098 +* Fix parent of translated category removed when assigning an untranslated parent #1105 +* Fix is_front_page() when a static front page is not translated #1123 +* Yoast SEO: Fix posts without language displayed in the sitemap #1103 +* Yoast SEO: Avoid syncing robots meta. #1118 + += 3.2.8 (2022-10-17) = + +* Fix PHP warning when a filtered taxonomy has no query var #1124 +* Fix SQL error when attempting to get objects without languages and no language exist #1126 +* Fix error when term slugs are provided as array in WP_Query #1119, #1132 Props Susanna Häggblom +* Fix a CSS regression in the wizard causing the default language icon to be removed #1137 + += 3.2.7 (2022-09-20) = + +* Work around a WooCommerce 6.9.x bug causing a fatal error in the wizard. #1116 + += 3.2.6 (2022-09-06) = + +* Pro: Fix a conflict with Kadence blocks +* Pro: Fix a conflict with Flatsome builder +* Fix media translation setting having no effect + += 3.2.5 (2022-06-28) = + +* Pro: Fix creation of WC product categories with shared slug via REST API +* Pro: Fix conflict with WooBuilder when editing a WC product +* Fix: Force empty string translation to empty string #1058 +* Fix CSS conflict with Dynamic content for Elementor #1060 + += 3.2.4 (2022-06-07) = + +* Pro: Remove "Navigation menus" from the post type settings list +* Pro: Fix block editor languages panel missing in WordPress 5.6 +* Pro: Fix wrongly indexed languages list returned by REST API when the first language is deactivated. +* Revert fix for category feed not redirected when the language code is wrong #1054 +* Fix wrong redirect of category when the url includes a query string #1048 +* Fix querying multiple categories failing + += 3.2.3 (2022-05-17) = + +* Pro: Fix a fatal error when inserting a term +* Pro: Fix translation of the block cover when duplicating a post +* Pro: Fix a CSS issue in bulk tranlate form introduced by WP 6.0 +* Pro: Fix a CSS issue in string import/export metaboxes. +* Prevent random languages order in WP 6.0 #1041 +* Translate site title in retrieve password email #1042 +* Fix 'lang' attribute in language widget dropdown #1039 + += 3.2.2 (2022-04-25) = + +* Pro: Fix redirect occuring for tags sharing the same slug as their translations +* Fix quick edit allowing to modify the language of the default category when it should not #1018 + += 3.2.1 (2022-04-14) = + +* Pro: Fix users with editor role not able to save or publish posts +* Pro: Fix FSE compatibility not loaded when the plugin Gütenberg is active +* Pro: Fix a fatal error occuring with Yoast SEO Premium +* Pro: Fix a fatal error with ACF when no language is defined + += 3.2 (2022-04-12) = + +* Requires WP 5.6 as minimum version +* Pro: Add compatibility with the full site editing introduced in WP 5.9 +* Pro: Add a language switcher block for the navigation block introduced in WP 5.9 +* Pro: Add compatibility with the new gallery block introduced in WP 5.9 +* Pro: Make the language switcher block available in the widget section of the customizer +* Pro: Fix wrong category when translating the latest posts block +* Pro: Fix the language switcher block when using the dropdown option +* Pro: Fix some edge cases with locale fallback +* Pro: Fix post template replacing the post content when duplicating a post +* Pro: Fix synchronization groups not correctly cleaned up when a language is deleted +* Pro: Fix incorrect sticky property when duplicating / synchronizing posts +* Pro: Fix "Page for posts" label after the page has been bulk translated +* Pro: Fix translated slug when the url includes a query string +* Pro: Synchronize ACF layout fields if a child field is synchronized or translatable +* Pro: Fix wrong field group translation displayed when using object cache with ACF +* Update plugin updater to 1.9.1 +* Add compatibility with the block site title introduced in WP 5.9 +* Add the list of wpml-config.xml files in the site health information +* Improve the performance of the get_pages() filter #980 +* Improve the compatibility of 'wpml_object_id' with the original filter #972 +* Prevent term_exists to be filtered by language in WP 6.0 +* Fix some PHP 8.1 deprecations #949 #985 +* Fix a fatal error in PHP 8.1 #987 +* Fix category feed not redirected when the langage code is wrong #887 +* Fix default category not created for secondary languages (introduced in 3.1) #997 +* Fix parent page when the parent post type is not translatable #1001 +* Fix the Yoast SEO breadcrumb when it includes a non-synchronized taxonomy #1005 +* Fix a PHP Notice when adding a new language and Yoast SEO is active #979 +* Fix a PHP warning in Yoast SEO compatibility #954 + += 3.1.4 (2022-01-31) = + +* Pro: Adapt duplication and synchronization of the gallery block refactored in WP 5.9 +* Fix UI glitch in the classic editor custom fields form when changing a post language in WP 5.9 #970 + += 3.1.3 (2021-12-14) = + +* Fix user description escaping #934 +* Fix dismissable notice when creating a term in WP 5.9 #936 +* Fix empty search not handled correctly. Props Dominik Schilling #937 +* Fix warning occurring when a 3rd party plugin attempts to register anything else than a string using the WPML API #942 +* Fix Yoast SEO columns not corectly drawn when quick editing a post #943 + += 3.1.2 (2021-10-11) = + +* Pro: Fix parent page not filtered by language in the block editor since WP 5.6 +* Pro: Fix XLIFF mime type for PHP 7.0 and PHP 7.1 +* Fix settings page displaying the media modules whne no language are defined +* Enforce Yoast SEO to use dynamic permalinks #882 +* Yoast SEO: Fix static front page and blog page breadcrumb + += 3.1.1 (2021-08-16) = + +* Pro: Fix a fatal error with The Events Calendar +* Allow to remove the cookie with the pll_cookie_expiration filter #905 + += 3.1 (2021-07-27) = + +* Add compatibility with WordPress 5.8 +* Raise Minimum WordPress version to 5.4 +* Pro: Allow to filter blocks by language in the widget block editor +* Pro: Allow to export and import XLIFF files for string translations +* Pro: Add the language switcher in the navigation block (experimental) +* Pro: Replace dashicons by svg icons in the block editor +* Pro: The Events Calendar: Add compatibility with Views V2 (only for sites using only one domain) +* Pro: Fix + icon displayed in the block editor sidebar when the user cannot create a translation +* Add a warning section to the site health for posts and terms without languages #825 +* Require the simplexml extension in the site health if a wpml-config.xml is found #827 +* Remove the information about the WPML compabitility mode in settings #843 +* The browser preferred language detection is now deactivated by default +* The media are now untranslated by default +* Highlight the language filter in the admin toolbar when it's active #821 +* Allow to query comments in multiple languages (just as posts and terms) #840 +* Don't disable the translation input field in the classic metabox #841 Props Onatcer +* Optimize all images including flags #848 Props lowwebtech +* Don't redirect if WordPress doesn't validate the redirect url to avoid redirects to /wp-admin/ #879 +* Fix media appearing to have a language after the language is changed in the media library grid view #807 +* Fix media not all deleted when bulk deleting from the grid view of the media library #830 +* Fix when more than one language switcher are added to the same menu #853 +* Fix PHP notice when adding a CPT archive link to a menu #868 Props davidwebca + += 3.0.6 (2021-06-22) = + +* Fix a conflict with the WooCommerce cart translation and cache plugins #876 + += 3.0.5 (2021-06-08) = + +* Pro: fix original post not assigned to a new translation when the languages sidebar is closed +* Pro: Attempt to fix zip file corrupted on some installations when exporting string translations +* Support session cookie with the pll_cookie_expiration filter #835 +* Fix javascript error when a plugin defines its own editor for translated post types #837 +* Fix languages displayed in screen options when editing a term #850 +* Cache: fix post type archive cache not cleared when saving a post #828 + += 3.0.4 (2021-04-27) = + +* Improve performance in the pages (or hierarchical post types) list table +* Fix an ajax conflict with WooCommerce License manager + += 3.0.3 (2021-03-23) = + +* Fix a warning when a language is corrupted in database (term_language missing) +* Fix confirmation modal with WooCommerce and WordPress < 5.6 +* Fix an ajax conflict with WooCommerce Tree Table Rate Shipping and HubSpot All-In-One Marketing + += 3.0.2 (2021-03-16) = + +* Move hreflang attributes higher in the head section #771 +* Fix custom flags not working (introduced in 3.0) +* Fix translation of the confirmation modal when changing the language of a post +* Fix js and css not loaded when Polylang is used as a mu-plugin (introduced in 3.0) +* Fix support for html5 stylesheet link tags #775 +* Fix possible warning in frontend-filters-links.php +* Yoast SEO Premium: Take over the multilingual compatibility removed in Yoast SEO Premium 15.8 #796 +* Yoast SEO: Fix CPT breadcrumb title when the option is left empty #794 +* Yoast SEO: Fix sitemap.xml not redirected on secondary domains #789 + += 3.0.1 (2021-03-10) = + +* Fix media gallery messed when editing a post in the classic editor +* Fix missing script dependency on old WP versions +* Fix CSS conflict with WooCommerce Bookings for WP < 5.6 +* Fix conflict resulting in '__' already defined in block-editor.js. #779 +* Fix search form removed for some themes. Props Marián Kadaňka. #780 +* Fix fatal error with very old versions of Yoast SEO. Props Nicola Peluchetti. #781 + += 3.0 (2021-03-08) = + +* Add compatibility with WordPress 5.7 +* Remove upgrades from Polylang older than 1.8 +* Remove deprecated class PLL_Pointer +* Pro: Hide the license keys +* Pro: Fix redirect to the home page of a deactivated language +* Pro: Fix synchronization of post status not working +* Pro: Fix language switcher block not working in a post retrieved in REST API +* Pro: Fix PO export of strings with line breaks +* Pro: Fix file block title customization lost +* Add a dialog box to ask a confirmation about a language change in classic and block editors +* Improve browser language detection #591 +* Improve robustness and documentation of code +* Fix media library after the language has been chnaged in the editor metabox +* Fix duplicated title attribute on flag link in posts list +* Fix legacy block editor language metabox compatibility with WordPress 5.6 +* Fix uploaded theme and plugin files in media library +* Fix site title not translated in email change confirmation email +* Fix remaining deprecated jQuery notices #741 +* Fix compatibility with GN publisher +* Fix compatibility with Woodmart theme search form +* Fix compatibility issue with 3rd party ajax requests since jQuery 3.3 #744 +* Fix CSS conflict with WooCommerce Bookings +* Fix browser error when displaying an embed and using a cache plugin #757 +* Fix post type archive title and metadesc not translated in Yoast SEO +* Fix PHP notice in REST API + += 2.9.2 (2021-02-02) = + +* Pro: Fix translation of CPTUI plural label and description not working +* Add Spanish (Ecuador) to the list of predefined languages +* Fix typo in "WordPress" string translation group. Props Viktor Szépe #682 + += 2.9.1 (2020-12-15) = + +* Fix PHP notice: Undefined property: PLL_Cache_Compat::$options with cache plugins. Props bahaa-almahamid. #658 +* Fix title of the search results page with Yoast SEO > 14.0 + += 2.9 (2020-12-07) = + +* Add compatibility with WordPress 5.6 +* Pro: Add locale fallback used when the theme or plugins translations are not available +* Pro: Fix SSO and browser preferred language redirect when using multiple domains +* Pro: Fix post slugs for German and Danish in the REST API +* Pro: Fix a fatal error in ACF integration when saving url modifications with multiple domains +* Pro: Fix a deprecated notice fired by ACF since the version 5.9.2 +* Pro: Fix ACF relationship fields not reloaded when changing the language in the classic editor +* Update plugin updater to version 1.8 +* Add Lower Sorbian to the list of predefined language +* Options are now translated on backend when using the admin language filter +* Keep previous translations when modifying an option value +* Add navigation markup to the language switcher widget +* Fix canonical redirect for taxonomy terms +* Fix a fatal error when deleting a post with a translation group corrupted in the database +* Fix a fatal error when switching to plain permalinks and using multiple domains +* Fix a conflict with WP Sweep which could corrupt languages +* Fix title displayed instead of meta description with Yoast SEO > 14.0 +* Fix PHP Notice: Undefined index: wp_the_query in /frontend/choose-lang-content.php on line 92 + += 2.8.4 (2020-11-03) = + +* Pro: Remove useless bulk translate action for ACF fields groups +* Pro: Fix the translation of the CPTUI labels when the language is set from the content +* Fix sitemaps redirected to the default language since WP 5.5.1 +* Fix object cache not flushed for sticky posts #601 +* Fix blog page broken when trashing a page and the blog page is not translated in all languages +* Fix custom flags ignored in WPML compatibility mode +* Fix breadcrumb for untranslated post types in Yoast SEO + += 2.8.3 (2020-10-13) = + +* Honor install_languages capability to download language packs +* Pro: Fix integrations not loaded (with The Events Calendar, CPTUI, Content blocks) +* Pro: Fix fatal error with ACF if a flexible content includes a repeater and a relationship +* Pro: Fix terms sharing their slug impossible to update without changing the slug +* When available, use wpcom_vip_get_page_by_path() instead of get_page_by_path() +* Fix queries filtered when editing a post that was declared untranslatable after it got a language +* Fix issues with Yoast SEO 14.0+ (breadcrumbs, canonical, title and description) + += 2.8.2 (2020-09-08) = + +* Pro: Fix posts sharing the same slug displayed on the same page +* Fix: Don't use a javascript localized string removed in WP 5.5 #568 +* Fix fatal error in site health when no language is defined #563 +* Fix various issues with Yoast SEO 14.x #65, #503, #505 +* Fix fatal error with MU Domain Mapping when saving domains in Polylang settings #569 + += 2.8.1 (2020-08-25) = + +* Pro: Fix fatal error with WP 4.9 +* Fix pll_the_languages() with 'raw' option returning html flag instead of flag url #558 +* Fix compatibility with Duplicate Posts not correcly loaded #557 +* Fix custom flag size in admin bar language switcher #559 +* Fix tag clouds mixed in the classic editor #561 + += 2.8 (2020-08-17) = + +* Pro: Add a language switcher block +* Pro: Add compatibility with block image edition introduced in WP 5.5 +* Pro: Fix our private taxonomies being displayed in the ACF field group rules. +* Pro: Fix incorrect flags loaded from the block editor +* Pro: Fix SSO causing a wrong redirect when using subdomains (introduced in 2.7.4) +* Pro: Fix a performance issue on the plugins list +* Pro: Fix option to automatically duplicate media in all languages when uploading a new file not honored in block image +* Use composer for autoload and Polylang Pro dependency on Polylang +* Display a flag for each post in the posts list tables (same for terms). #515 +* Add test for the homepage translations to Site Health +* Add debug information to Site Health +* Add compatibility with the sitemaps introduced in WP 5.5 #451 +* Always filter WP_Query by the current language +* Support wildcards in "admin-texts" parent keys in wpml-config.xml +* Fix sticky posts showed for all languages when the admin language filter is active #469 +* Fix a performance issue on the pages list +* Fix dependency to jQuery Migrate removed from WP 5.5 #539 +* Fix: output secure cookie when using a cache plugin and ssl #542 +* Fix the possibility to create 2 terms with the same name in the same language, without specifying the second slug. +* Fix sticky posts appearing 2 times in WP 5.5 + += 2.7.4 (2020-06-29) = + +* Pro: Allow using our /untranslated-posts REST endpoint for non-public post types +* Pro: Fix broken display in the block editor sidebar when a language has no flag +* Pro: Fix SSO breaking the preview on secondary domains +* Pro: Fix ACF translation option not working for term custom fields +* Pro: Fix a styling issue in the fields group list table in ACF 5.9 +* Add Spanish from Puerto Rico to the predefined list of languages + += 2.7.3 (2020-05-26) = + +* Security: Slash metas +* Pro: Fix categories not savedafter the language has been switched in the block editor +* Pro: Fix ACF fields stored as integers instead of strings +* Pro: Fix ACF untranslated posts or terms being copied when creating a new translation +* Pro: Fix PHP notice with ACF when a repeater or group is included in a flexible content +* Pro: Fix "DevTools failed to load SourceMap" warning in browser console +* Update plugin updater to 1.7.1 +* Honor the filter "pll_the_language_link" when the language switcher displays a dropdown #506 +* Fix "Something went wrong" message when quick editing untranslated post types #508 +* Fix wpseo_opengraph deprecated warning #509 + += 2.7.2 (2020-04-27) = + +* Pro: Re-allow to modify the capability for strings translations +* Pro: Fix redirect for posts having the same slug as a media +* Pro: Fix PHP notice with ACF flexible content +* Pro: Fix a fatal error with InfiniteWP +* Update plugin updater to 1.7 +* Fix font in setup wizard + += 2.7.1 (2020-04-09) = + +* Pro: Fix untranslated post types filtered by the parameter in the REST API #493 +* Fix fatal error when the function idn_to_ascii is not available +* Fix PHP warning warning when a 3rd party plugin declares options not stored in DB in wpml-config.xml #492 +* Fix fatal error when a 3rd party plugin declares options stored as objects in wpml-config.xml #494 + += 2.7 (2020-04-06) = + +* Minimum WordPress version is now 4.9 +* Pro: Strings translations can now be exported and imported (in PO format) +* Pro: Allow to decide individually which ACF fields to copy or synchronize +* Pro: Add action pll_inactive_language_requested +* Pro; Fix fatal error in The Events Calendar compatibility when no language is defined yet +* Pro: Fix bulk translate when a post has no language +* Pro: Fix reusable block saved without language +* Pro: Fix post requested by slug not filtered in REST API, when the slug is shared +* Add a setup wizard +* Add Swahili, Upper Sorbian, Sindhi and Spanish from Uruguay to the list of predefined languages +* Add flags in the predefined list of languages +* Allow to hide the metaboxes from the screen options +* The deletion of the plugin's data at uninstall is now controlled by a PHP constant instead of an option #456 +* Add parent in ajax response when selecting a term in autocomplete field #328 +* Add Vary: Accept-Language http header in home page redirect. Props @chesio #452 +* Improve performance to register/unregister WPML strings +* Add support for the action wpml_switch_language +* Add post_status to the list of accepted args of pll_count_posts() +* Apply the filter pll_preferred_language in wp-login.php +* Use filtered wrappers to create meta when creating media translations #231 +* Allow to translate the Twenty Seventeen header video Youtube url #460 +* Notices are now dismissed per site instead of per user #478 +* Fix terms not visible in the quick edit when only one language is defined and teh admin language filter is active +* Fix post state not displayed for translations of the privacy policy page #395 +* Fix wildcards not correctly interpreted in wpml-config.xml +* Fix product categories with special characters duplicated when importing WooCommerce products #474 + += 2.6.10 (2020-02-19) = + +* Pro: Fix sticky posts not filtered in REST API (introduced in 2.6.9) +* Fix wrong language detected if a child page uses the slug of another language +* Fix a PHP notice with PHP 7.4. #438 +* Fix lang-item-first class in language switcher when the current language is hidden. #445 +* Fix partially a conflict with Fusion Builder (the other part of the conflict being in Fusion Builder). + += 2.6.9 (2020-01-15) = + +* Pro: Use 'parse_query' rather than 'rest_{$type}_query' to filter REST requests. +* Pro: Filter the comments REST endpoint. +* Pro: Fix duplication of terms without language. +* Pro: Fix fatal error when Admin Columns is activated and no language is defined yet. +* Fix shortlink when using one subdomain or domain per language + += 2.6.8 (2019-12-11) = + +* Pro: Fix conflict with JetThemesCore from Crocoblock +* Fix: better detection of REST requests when using plain permalinks +* Fix usage of deprecated action wpmu_new_blog in WP 5.1+ +* Fix PHP notices with PHP 7.4 + += 2.6.7 (2019-11-14) = + +* Require PHP 5.6 +* Fix PHP warning in WP 5.3 + += 2.6.6 (2019-11-12) = + +* Pro: Fix wrong ajax url when using one domain per language +* Pro: Fix conflict with user switching plugin when using multiple domains +* Pro: Fix latest posts block in WP 5.3 +* Fix database error when attempting to sync an untranslated page parent +* Fix a conflict with the theme Neptune by Osetin + += 2.6.5 (2019-10-09) = + +* Pro: Require ACF 5.7.11+ to activate the compatibility to avoid fatal errors with older versions +* Pro: Avoid translating empty front slug (could cause a wrong redirect to /wp-admin) +* Pro: Fix filter wp_unique_term_slug not always correctly applied. +* Pro: Fix a conflict with Divi causing post synchronization buttons to be displayed multiple times +* Avoid notice in WP CLI context + += 2.6.4 (2019-08-27) = + +* Pro: Fix a conflict preventing meta synchronization when ACF is active +* Pro: Fix post metas not correctly copied when translating a Beaver Builder page +* Pro: Fix a fatal error when posts made with Elementor are synchronized +* Pro: Fix Prewiew button not working correctly when using one domain per language +* Pro: Fix post synchronization not available for WP CRON and WP CLI +* Fix future posts not available in the autocomplete input field of the languages metabox +* Fix translations files not loaded on REST requests +* Fix deleted term parent not synchronized + += 2.6.3 (2019-08-06) = + +* Pro: Fix fatal error when updating an ACF field from frontend +* Pro: Add action 'pll_post_synchronized' +* Allow to get the current or default language object using the API. Props Jory Hogeveen. #359 +* Fix empty span in languages switcher widget when showing only flags +* Fix wpml_register_single_string when updating the original string + += 2.6.2 (2019-07-16) = + +* Pro: Fix slow admin in case the translations update server can't be reached +* Pro: Fix value not correctly translated for ACF clone fields in repeater +* Fix strings translations mixed when registered via the WPML compatibility. #381 + += 2.6.1 (2019-07-03) = + +* Pro: Fix Yoast SEO sitemap for inactive languages when using subdomains or multiple domains +* Fix fatal error in combination with Yoast SEO and Social Warfare +* Fix post type archive url in Yoast SEO sitemap + += 2.6 (2019-06-26) = + +* Pro: Remove all languages files. All translations are now maintained on TranslationsPress +* Pro: Move the languages metabox to a block editor plugin +* Pro: Better management of user capabilities when synchronizing posts +* Pro: Separate REST requests from the frontend +* Pro: Copy the post slug when duplicating a post +* Pro: Duplicate ACF term metas when terms are automatically duplicated when creating a new post translation +* Pro: Fix hierarchy lost when duplicating terms +* Pro: Fix page shared slugs with special characters +* Pro: Fix synchronized posts sharing their slug when the language is set from the content +* Pro: Fix PHP warning with ACF Pro 5.8.1 +* Pro: Fix ACF clone fields not translated in repeaters +* Better management of user capablities when synchronizing taxonomies terms and custom fields +* Extend string translations search to translated strings #207 +* Update plugin updater to 1.6.18 +* Honor the filter `pll_flag` when performing the flag validation when creating a new language +* Modify the title and the label for the language switcher menu items #307 +* Add support for international domain names +* Add a title to the link icon used to add a translation #325 +* Add a notice when a static front page is not translated in a language +* Add support for custom term fields in wpml-config.xml +* Add filter `pll_admin_languages_filter` for the list of items the admin bar language filter +* Add compatibility with WP Offload Media Lite. Props Daniel Berkman +* Yoast SEO: Add post type archive url in all languages to the sitemap +* Fix www. not redirected to not www. for the home page in multiple domains #311 +* Fix cropped images not being synchronized +* Fix auto added page to menus when the page is created with the block editor +* Fix embed of translated static front page #318 +* Fix a possible infinite redirect if the static front page is not translated +* Fix incorrect behavior of action 'wpml_register_single_string' when updating the string source +* Fix fatal error with Jetpack when no languages has been defined yet #330 +* Fix a conflict with Laravel Valet. Props @chesio. #250 +* Fix a conflict with Thesis. +* Fix a conflict with Pods in the block editor. Props Jory Hogeveen. #369 +* Fix fatal error with Twenty Fourteen introduced in version 2.5.4. #374 + += 2.5.4 (2019-05-28) = + +* Add Kannada to the predefined languages list +* Yoast SEO: Fix primary product cat not copied or synchronized +* WPMU Domain Mapping: Fix incorrect domain used for the theme +* Fix style-rtl.css not loaded when the language is set from the content #356 +* Fix Jetpack featured pages not working. Props Anis Ladram. #357 +* Fix Call to undefined function wp_generate_attachment_metadata() + += 2.5.3 (2019-04-16) = + +* Add de_AT and pt_AO to the predefined languages list +* Pro: Add filter pll_translate_blocks +* Pro: fix PHP notice when the queried post type has been modified to an array +* Pro: fix PHP warning when combined with The Event Calendar and Page builder by SiteOrigin + += 2.5.2 (2019-02-12) = + +* Pro: Fix translated slugs not accepting forward slashes +* Pro: Fix fatal error with ACF Pro 5.7.11 +* Fix parent categories incorrectly synchronized #327 + += 2.5.1 (2019-01-16) = + +* Security: Fix categories and media duplication not protected from CSRF +* Pro: Allow to update the plugin with WP CLI +* Pro: Fix search in the button block not filtered in the correct language (needs WP 5.1) +* Add Saraiki to the predefined languages list +* Fix a conflict causing a blank page with Divi + += 2.5 (2018-12-06) = + +* Add compatibility with WP 5.0 +* Fix custom flags when the WP content folder is not in the WP install folder +* Fix PHP notice if a language has no flag + += 2.4.1 (2018-11-27) = + +* Pro: Add compatibility with REST API changes made in WP 5.0 +* Pro: Fix sticky posts in the REST API +* Pro: Fix overwritten custom post slug when the post is updated with the REST API +* Pro: Fix bulk translate for media +* Fix a conflict with Custom sidebars and Content aware sidebars +* Fix a conflict with the theme Pokemania +* Fix PHP notices when using the function 'icl_link_to_element' for terms +* Fix title slugs for posts written in German + += 2.4 (2018-11-12) = + +* Minimum WordPress version is now 4.7 +* Pro: Add the possibility to bulk duplicate or bulk synchronize posts. +* Pro: Add compatibility with Admin Columns +* Pro: Add synchronized posts to the REST API +* Pro: Fix variations messed when changing WooCommerce attributes slugs +* Pro: Fix incorrect language for ajax requests made on front by The Events Calendar +* Pro: Fix term not duplicated correctly when the language is set from the content +* Refactor the core to activate on front and for the REST api actions that were previously available only in the backend (language checks, synchronizations...). +* Add flags to widgets displayed in only one language (Props Jory Hogeveen) #257 +* Honor the filter 'pll_the_language_args' for all options in menus #237 +* Add better filters for default flags and custom flags +* Custom flags can now be stored in the polylang directory in the theme +* Custom flags can now use SVG +* Add compatibility with Jetpack featured content module +* Fix Twenty Fourteen featured posts possibly not filtered per language +* Fix home url not working with WordPress MU Domain mapping +* Fix Assigning a parent category breaking the hierarchy of translated category +* Fix: Accept 0,1 and 1.0 as q factors in browser preferred language detection (Props Dominic Rubas) +* Fix performance issue when using hundreds of widgets +* Fix translations possibly wrong if the post language is changed without saving the post after + += 2.3.11 (2018-10-03) = + +* Pro: Add action 'pll_created_sync_post' +* Pro: Fix language and translations not included for tags in the REST API +* Fix Assigning a parent category breaking the hierarchy of translated category + += 2.3.10 (2018-08-16) = + +* Fix Lingotek notice not dismissable +* Fix fatal error with the widget calendar + += 2.3.9 (2018-08-14) = + +* Add a notice to inform about Polylang for WooCommerce +* Deprecate PLL_Pointer +* Fix bulk editing pages with no language breaking hierarchy #281 +* Fix an edge case where rewrite rules could be messed on a multisite +* MU Domain Mapping: fix secondary domain redirected to primary domain + += 2.3.8 (2018-07-16) = + +* Pro: Duplicate term meta when duplicating a post creates new terms +* Pro: Add compatibility with ACF Pro when it's bundled with the theme +* Pro: Fix a fatal error when duplicating posts +* Set cookie during the home redirect +* Accept a port in the url to detect the site home +* Add filter 'pll_is_cache_active' to allow to load the cache compatibility #270 #274 +* Fix potential fatal error when a 3rd party misuses the 'wpml_active_languages' filter #268 +* Fix Uncaught TypeError: s.split is not a function. Props Wouter Van Vliet #262 +* Fix text alignment for RTL scripts in Lingotek panel #247 +* Fix html language attribute filter on admin +* Fix cookie expiration time when set in js. Props Jens Nachtigall #271 +* Fix fatal error when a 3rd party misuses the WP_Query tax_query param. Props JanneAalto #252 +* Fix an edge case which could mess home pages on a multisite + + += 2.3.7 (2018-06-07) = + +* Pro: The Events Calendar: Fix untranslated events shown in all languages +* Avoid displaying edit links of translations of the privacy policy page to non-admin +* Fix draft created when creating a new page on multisite +* Do not prevent using the cache for home when using WP Rocket 3.0.5 or later #236 +* Fix language filter applied to wrong queries on admin side + += 2.3.6 (2018-05-17) = + +* Pro: Fix post type archive slug not translated in ACF page link fields +* WP 4.9.6: Translate the privacy policy page +* WP 4.9.6: Add the translated user descriptions to exported personal data +* Update Plugin updater to version 1.6.16 +* Fix conflict with the plugin View Admin As. Props Jory Hogeveen. #253 + += 2.3.5 (2018-05-08) = + +* Pro: Fix translated CPT slugs when one CPT name is a substring of another one. Props Steve Reimer. +* Pro: Fix canonical redirection for post types archives when the CPT slug is translated +* Pro: Fix ACF private key uselessly synchronized when the public custom field is not synchronized +* Add filter 'pll_filter_query_excluded_query_vars' +* Redirect www. to non www. when using multiple domains +* Fix Yoast SEO category sitemap not filtered by language when using multiple domains +* Fix PLL_COOKIE === false not honored when using a cache plugin. #248 +* Fix empty predefined languages list + += 2.3.4 (2018-03-27) = + +* Pro: Fix conflict with Pods related to translated slugs for custom post types +* Add Friulian to the predefined languages list +* Fix conflict (javascript error) with Gütenberg #225 +* Fix conflict on ajax requests introduced by WooCoommerce 3.3.4 +* Fix queries by 'category_name' not auto translated #238 + += 2.3.3 (2018-03-15) = + +* Pro: Fix tax query using a term sharing slugs (fix a conflict with Fusion Builder) +* Restore Polylang (free) on REST requests, while disabling the language filter as in v2.3 +* Rework auto translated query with taxonomy in different language #223 +* Synchronize Yoast SEO primary category (needs Yoast SEO 7.0+) +* Fix PHP warning introduced by Yoast SEO 7.0 #229 +* Fix tax query when using the relation 'OR' +* Fix a conflict with the combination of Barrel + WP Bakery Page Builder +* Fix broken redirect with MU domain mapping #226 +* Fix site title not translated in password change email + += 2.3.2 (2018-03-05) = + +* Pro: Fix REST requests not filtered by the requested language (introduced in 2.3). +* Pro: Fix error 404 on single posts if posts are untranslatable +* Deactivate Polylang (free) on REST requests by default. +* Fix translated terms unassigned from posts when deleting a term +* Fix auto translated query with taxonomy in different language returning empty results since WP 4.9 #223 +* Fix conflict with a homepage option of the theme Extra +* Fix warning when filtering get_pages() + += 2.3.1 (2018-02-15) = + +* Pro: Fix GET REST request with slug parameter deleting the post slug +* Fix http request with a custom query var being redirected to the home page #216 + += 2.3 (2018-01-30) = + +* Pro: Duplicating a post now duplicates untranslated terms and the featured image (if media are translatable) +* Pro: Add filter 'pll_sync_post_fields' +* Pro: Translate ACF Pro clone fields when creating a new field group translation +* Pro: Allow to share slugs when creating a post or term with the REST API +* Pro: Load asynchronously the script added on front for multiple domains and subdomains +* Pro: Fix 'lang' parameter not interpreted when the query includes 'name' +* Refactor the synchronization of metas for better synchronization and performance improvement +* Refactor the synchronization of taxonomy terms for performance improvement +* Refactor language and translations saving for performance improvement +* Refactor the synchronization of sticky posts +* Remove all languages files. All translations are now maintained on https://translate.wordpress.org/projects/wp-plugins/polylang #199 +* Refactor the list of languages to merge predefined languages, Facebook locales and fixes for W3C locales +* Automatically deactivate Polylang when activating Polylang Pro +* Disable programmatically translated post types and taxonomies in settings. Props Ulrich Pogson. #180 +* Set the cookie language in Javascript when a cache plugin is active +* Automatically remove the home page from cache when requesting the detection of the browser preferred language +* Use relative urls for the admin language filter in admin bar. #209 +* Disable auto translation of WP_Term_Query if it has a 'lang' parameter +* Don't filter REST requests by default. #211 +* Fix Yoast SEO statistics in dashboard showing only the default language. #211 +* Fix WP Rocket clearing the cache of the wrong adjacent post +* Fix random header image +* Fix home page not correctly loaded when adding a query var +* Fix: Impossible to change the language code when the language code is also a WordPress locale. + += 2.2.8 (2018-01-09) = + +* Pro: Fix: Impossible to link past events by translation in The Events Calendar +* Disallow to delete translations of the default term for all taxonomies +* Fix: Auto add pages adds WooCommerce pages in default language to menus in all languages +* Fix most used tag cloud in Tags metabox in WP4.9+. Props Pär Thernström. #208 + += 2.2.7 (2017-11-30) = + +* Fix queries by taxonomy broken since WP 4.9 +* Fix PHP notice in icl_object_id() + += 2.2.6 (2017-11-22) = + +* Pro: Fix query by post name and alternative language always returning the post in current language (when sharing slugs) +* Pro: Fix query by taxonomy and alternative language returning empty results +* Rework how translation files are loaded in ajax on front when the user is logged (in WP 4.7+) +* Add filter 'get_objects_with_no_lang_limit' +* Force loading the admin side when using WP CLI (Props chrisschrijver) +* Fix check for terms with no language not scaling +* Fix pll_count_posts not working with multiple post types +* Fix inconsistent spacing between flag and language name in language switcher parent menu item (Props Amit Tal) +* Fix spacing between flag and language name when displaying an RTL language +* Fix get_terms not accepting comma separated values for 'lang' parameter (Props Pavlo Zhukov) +* Fix possible wrong language detected in url when using subdomains (Props Pavlo Zhukov) +* Fix double escaped query + += 2.2.5 (2017-11-09) = + +* Update plugin updater class to 1.6.15 +* Add $link in cache key of links filters +* Add support for 'nav_menu' post type in wpml_object_id +* Fix conflict with Timber (introduced in 2.2.4) + += 2.2.4 (2017-10-26) = + +* Pro: Fix unknown language not redirected to default when using multiple domains +* Pro: Fix empty 'lang' query var not deactivating the language query filter +* Pro: Fix conflict with The Events Calendar and Visual Composer when used together +* Add new filter `pll_hide_archive_translation_url` #174 +* Add support for undocumented and deprecated WPML functions `wpml_object_id_filter` and `icl_get_current_language` +* Fix 'orderby' and 'order' in `wpml_active_languages`. Needs WP 4.7+ +* Fix `icl_get_languages` not returning all languages when skip_missing = 0. Props Loïc Blascos +* Fix `pll_translate_string` not working on admin #178 +* Fix PHP Warning in widget video in WP 4.9 +* Fix query using 'any' post type not filtered per language (introduced in 2.2) +* Fix untranslatable string in About metabox. Props Farhad Sakhaei +* Fix error with PHP 7.1 and Duplicate Post. Props Enea Scerba +* Fix query auto translation not active in ajax requests on frontend +* Fix query auto translation for 'postname' and 'pagename' +* Fix terms query auto translation not working for 'include' when no taxonomy is provided (WP 4.5+) + += 2.2.3 (2017-09-24) = + +* Fix editor removed on pages (introduced in 2.2.2) + += 2.2.2 (2017-09-22) = + +* Pro: Fix Duplicate post button not working when the user meta has been corrupted +* Fix PHP notice with the plugin Members #175 +* Fix page template select displayed when editing a translated page for posts +* Fix incompatibility with WP 4.8.2 (placeholder %1$s in prepare) + += 2.2.1 (2017-08-30) = + +* Pro: partially refactor REST API classes +* Pro: Fix duplicate content user meta not removed from DB when uninstalling the plugin +* Fix strings translations not removed from DB when uninstalling the plugin +* Fix incorrect translation files loaded in ajax on front when the user is logged in (WP 4.7+) +* Fix widget language dropdown removed when saving a widget (introduced in 2.2) +* Fix queries with negative values for the 'cat' parameter (introduced in 2.2 for queries made on frontend) +* Fix performance issue in combination with some plugins when the language is set from the content (introduced in 2.2) + += 2.2 (2017-08-16) = + +* Pro: Add support for the REST API +* Pro: Add integration with The Events Calendar +* Pro: Refactor ACF Pro integration for post metas and integrate term metas +* Pro: Ask confirmation if synchronizing a post overwrites an existing translation +* Pro: Separate sync post logic from interface +* Pro: Fix 'Detect browser language' option automatically deactivated +* Pro: Fix redirect to 404 when the 'page' slug translation includes non alphanumeric characters. +* Pro: Fix untranslated post type archive slug +* Pro: Fix ACF taxonomy fields not copied when the taxonomy is not translated #156 +* Pro: Fix fatal error with ACF4 +* Support a different content text direction in admin #45 +* Add support for wildcards and 'copy-once' attribute in wpml-config.xml +* Add minimal support for the filters 'wpml_display_language_names' and 'icl_ls_languages' +* Improve compatibility with the plugin WordPress MU Domain Mapping #116 +* Improve speed of the sticky posts filter #41 +* Remove redirect_lang option for multiple domains and subdomains +* Use secure cookie when using SSL +* Allow to copy/sync term metas with the filter 'pll_copy_term_metas' +* Filter ajax requests in term.php according to the term language +* Add error message in customizer when setting an untranslated static front page #47 +* Load static page class only if we are using a static front page +* Refactor parse_query filters to use the same code on frontend and admin +* Don't use add_language_to_link in filters +* Move ajaxPrefilter footer script on top +* Use wp_doing_ajax() instead of DOING_AJAX constant +* Fix queries custom tax not excluded from language filter on admin +* Fix WP translation not loaded when the language is set from the content on multisite. +* Fix the list of core post types in PLL_OLT_Manager for WP 4.7+ +* Fix post name and tag slug incorrectly sanitized for German and Danish +* Fix lang attribute in dropdowns +* Fix wpml_permalink filter #139 +* Fix WPML constants undefined on backend #151 +* Fix a conflict with the plugin Custom Permalinks #143 +* Fix menu location unexpectedly unset + += 2.1.6 (2017-07-17) = + +* Pro: fix duplicate post button not working in PHP 7.1 +* Pro: fix CPTUI untranslated labels on admin +* Adapt related posts filter to use slug instead of name to follow changes made on Jetpack server ( Props Steve Kaeser ) +* Fix PHP notices when translating CPT and custom tax titles in Yoast SEO +* Fix PHP warning when all plugins are networked activated + += 2.1.5 (2017-05-31) = + +* Add compatibility with new media widgets introduced in WP 4.8 +* Removing the language information in URL for the default language is now default +* Update plugin updater class to 1.6.12 +* Pro: fix PHP notices when duplicating the content +* Fix: test existence of `twentyseventeen_panel_count` instead of relying only on the active template +* Fix: set current property to false when removing the current-menu-item class #134 props @mowar +* Fix PHP notice when editing a term without language +* Fix possible PHP notice when deleting a category +* Fix fatal error with Gantry 5 + += 2.1.4 (2017-05-16) = + +* Pro: fix user not logged in on secondary domain when previewing changes +* Pro: fix archive links without language code in ACF link field (ACF 5.4.0+) +* Fix redirection from www subdomain to wrong language domain. +* Fix: selecting "Front page displays latest posts" in the customizer not cleaning the languages cache +* Fix accessibility of the admin language switcher + += 2.1.3 (2017-04-11) = + +* Pro: Fix translated slug of 'page' if it is translated to an empty string +* Update plugin updater class to 1.6.11 +* Strings registered with a wpml-config.xml file or WPML functions are now multiline by default +* Translate the site title in emails sent to the user +* Fix sanitize_user for specific locales +* Fix deprecation notice in Yoast SEO integration +* Fix: Clean term cache after the language has been set in mass #119 + += 2.1.2 (2017-03-09) = + +* Pro: Add filter 'pll_xdata_nonce_life' +* Pro: Fix translation of WooCommerce product attribute slug +* Pro: Fix product synchronization in WooCommerce 2.7 +* Pro: Fix error message when bulk trashing synchronized posts +* Add option to discard item spacing in the output of pll_the_languages() ( Props Ceslav Przywara ) #93 #95 +* Add as, dzo, kab, km, ml_IN, nl_BE, pa_IN, rhg, sah, ta_IN, tah, te, tt_RU to the predefined list of languages +* Update plugin updater class to 1.6.10 +* Fix: Remove the dependency to is_ssl() to detect the language in the url ( language set from the directory name ) +* Fix issue with secondary level domains +* Fix strings not translated in emails +* Fix incorrect usage of add_action() ( Props Peter J. Herrel ) #103 +* Fix wrong redirect in customizer in WP 4.7 + += 2.1.1 (2017-02-15) = + +* Pro: Add filter 'pll_enable_duplicate_media' for a fine control of automatic media duplication +* Add filter 'pll_links_model' for the links model class name +* Trim any starting ^ from modified rewrite rules +* Pro: Fix wrong count of plugins to update +* Fix slashed strings translations not saved #94 + += 2.1 (2017-01-25) = + +* Minimum WordPress version is now 4.4 +* Pro: Add support for synchronized posts (same post in multiple languages) +* Pro: Add support for custom post type UI and the Divi Builder +* Improve support of Yoast SEO (no category base and post type archive breadcrumb title) +* Move Languages menu at top level instead of submenu of the WordPress settings +* Copy the original post date when creating a translation and when the date is synchronized (Props Jory Hogeveen) #32 +* Remove hreflang attributes on paged pages and paged posts +* Add label to widget language dropdown for better accessibility (Props Lawrence Francell) #53 #56 +* Remove constants POLYLANG_URL and PLL_LOCAL_URL +* wp_get_sidebars_widgets() and is_active_sidebar() are now filtered according to widgets languages #54 +* Add functions pll_esc_html__(), pll_esc_html_e(), pll_esc_attr__() and pll_esc_attr_e() to the API (Props jegbagus) #83 +* Pro: Fix conflict between WooCommerce shop on front and translated shop base slug +* Pro: Fix $wp_rewrite search base and author_base not translated #68 +* Pro: Fix page preview does not log in the user when using subdomains +* Fix: avoid setting the language cookie on 404 pages +* Fix: rewrite rules order modified for custom post types archives +* Fix: conflict with WP All Import causing our filters to fail in "Add Media" modal when editing a post +* Fix: auto add pages not working for nav menus assigned to several locations +* Fix: Jetpack infinite scroll for multiple domains #58 #74 +* Fix: serialize error in Strings translations when balanceTags option is active #63 +* Fix: static front page preview when redirected from the languages page #49 +* Fix: Auto add pages not working for nav menus assigned to several locations +* Fix: Conflict with Woocommerce Show Single Variation +* Fix: Parent page not synchronized in Quick edit (introduced in 2.0.8) +* Fix: WPML API wpml_element_has_translations and wpml_post_language_details +* Fix: unattached media translations not in language switcher +* Fix: Conflict with WP Residence advanced search + += 2.0.12 (2016-12-19) = + +* Fix plugin not loaded first (introduced in 2.0.11) +* Fix wrong translations files loaded when the language is set from the content in WP 4.7 #76 +* Fix notice when a tax query has no terms (using EXISTS or NOT EXISTS) + += 2.0.11 (2016-12-12) = + +* Pro: Fix shared term slugs broken by a late change in WP 4.7 #73 +* Pro: Fix media taxonomies lost when creating a media translation when taxonomies sync is activated #72 +* Fix fatal error in customizer when Twenty Seventen is activated and another theme is previewed #71 +* Fix wrong plugin language on admin if user locale is different from site locale in WP 4.7 + += 2.0.10 (2016-12-05) = + +* Add support for front page panels of Twenty Seventeen +* Remove draft posts from the language switcher even when the user is logged in +* Fix: Make argument 2 of icl_object_id optional +* Fix a conflict with the Divi theme (#67) + += 2.0.9 (2016-11-15) = + +* Fix javascript error in some ajax requests + += 2.0.8 (2016-11-14) = + +* Disable admin language feature in WP 4.7+ +* Pro: fix case where a media could lose its parent post when translated on the fly by the content duplication +* Pro: fix on the fly media created at content duplication attached to parent page instead of child page +* Fix translations input fields not populated in languages metabox when creating a new translation in WP 4.7 +* Fix possibility to delete the translations of the default category in WP 4.7 +* Fix tag search not filtered per language in Quick edit in WP 4.7 +* Fix dropdown language switcher not working for untranslated pages + += 2.0.7 (2016-10-18) = + +* Fix issues with static front pages introduced in version 2.0.6 + += 2.0.6 (2016-10-17) = + +* Pro: Fix translated paged slug not working on paged static front page +* Add support for WPML filter 'wpml_language_form_input_field' +* Fix PHP notice when using the WPML filter 'wpml_current_language' +* Fix cases where the admin language filter is not correctly taken into account +* Fix paged static front pages in plain permalinks +* Fix paged static front pages for multiple domains (#43) +* Fix warning occurring when a 3rd party plugin attempts to register anything but a string in the strings translations panel +* Fix cross domain http request for media when using multiple domains or subdomains +* Fix error 404 on pages when no language has been created yet + += 2.0.5 (2016-09-22) Five years after! = + +* Pro: Fix conflict with WPBakery Visual Composer +* Pro: Fix conflict between multiple domains SSO and FORCE_SSL_ADMIN +* Pro: Fix duplicated fields not displayed in new translation in ACF Pro 5.4+ +* Add Tibetan and Silesian to the predefined languages list +* Remove duplicated strings from the strings translations (even when they have a different name or group) +* The languages and translations of custom post types and taxonomies are no more activated by default at activation +* Allow to deactivate auto translation in secondary by setting 'lang' to an empty value +* Fix: invalidate the cache of PLL_MO ids when adding a new language +* Fix: don't filter secondary queries when editing a post in an untranslated post type + += 2.0.4 (2016-09-06) = + +* Add Gujarati to the predefined languages list +* Fix conflict with Page Builder. Other parts of the conflict are fixed in Page Builder 2.4.14 +* Fix plugins translations incorrectly loaded in WP 4.6 +* Fix error 404 on paged urls when using a non standard port + += 2.0.3 (2016-08-16) = + +* Pro: Fix PHP notice when hiding the language code in url and the language is set from subdomains +* Pro: Fix one more media being created when the duplicate media in all languages is activated (introduced in 2.0) +* Pro: Fix shared term slugs not working on PHP 7 +* Pro: Fix Polylang storing integers in some ACF Pro fields where ACF Pro stores strings +* Pro: Fix ACF Pro custom fields synchronized even when the custom fields synchronization option is deactivated (#40) +* Fix PHP notice: Undefined variable: original_value in /modules/wpml/wpml-api.php on line 168 +* Fix translations loaded too soon by plugins not correctly reloaded since WP 4.6 (#39) +* Fix: Remove the delete link for translations of the default category on PHP 7 +* Fix unescaped i18n strings in Lingotek presentation + += 2.0.2 (2016-08-03) = + +* Avoid fatal error when a 3rd party theme or plugin has a malformed wpml-config.xml file: the malformed wpml-config.xml file is simply ignored + += 2.0.1 (2016-08-02) = + +* Fix fatal error on PHP < 5.4 (introduced in 2.0) +* Fix custom flags not being loaded (introduced in 2.0) + += 2.0 (2016-08-02) = + +* Pro: Improve integration with ACF Pro +* Pro: Add support for single sign on across multiple domains or subdomains +* Pro: Add support for browser language detection when using multiple domains +* Pro: Add support for translation of the static portion of the post permalink structure +* Pro: Fix deactivated languages appearing in Yoast SEO sitemaps +* Pro: Fix impossibility to visit a deactivated language when using subdomains or multiple domains (#10) +* Pro: Fix when sharing slug on the page for posts, only one of them is accessible (#33) +* Add the possibility to use the language switcher as dropdown in menu +* Add support for custom logo introduced in WP 4.5 (#6) +* The backend current language ( PLL()->curlang ) is now equal to the language of current post or term being edited (#19) +* The sample permalink is now updated when changing the language in the Languages metabox +* Revamp the wpml-config.xml reader to use simplexml instead of our custom xml parser +* Improve support for the WPML API (including Hook API introduced in WPML 3.2) +* Add support for translation of meta titles and descriptions of custom post types and custom taxonomies in Yoast SEO +* Replace uncached functions by WPCOM VIP functions when available +* Improve compatibility with WP 4.6 +* Fix parent category wrongly assigned to post when synchronizing children categories (#21) +* Fix custom fonts not loaded when using multiple domains or subdomains +* Fix remove_accents() not working for German and Danish (#24) +* Fix incorrect static front pages urls on backend +* Fix impossible to directly enter the page number in strings translation table (introduced in 1.9.3) +* Fix conflict with WP Sweep (needs WP Sweep 1.0.8+) +* Fix potential performance issue by querying only taxonomies to show in quick edit to filter the category checklist +* Fix conflict (database error) with ReOrder-posts-within-categories plugin +* Fix languages per page option not saved + += 1.9.3 (2016-06-28) = + +* Pro: Allow to add slashes in url slugs translations +* Pro: Fix archive links not using translated slugs +* Pro: Fix visitor being redirected to 404 if his browser preference is set to an inactive language +* Fix strings translations table always back to page 1 when submitting the form (#14) +* Fix get_pages( array( 'lang' => '' ) ) not querying all the languages +* Fix switching the admin language filter can override the static front page settings (#16) + += 1.9.2 (2016-06-06) = + +* Pro: fix unreachable hierarchical custom post type posts when they are sharing slugs across languages +* Fix missing argument 3 in icl_t +* Fix conflict with WooCommerce product variations + += 1.9.1 (2016-05-23) = + +* Pro: add compatibility with Beaver Builder +* Pro: fix media wrongly created when adding a new media translation +* Add azb, ceb, de_CH_informal, es_GT, mr, nl_NL_formal to the predefined list of languages +* Fix the language switcher not linking to media translations for anonymous visitors + += 1.9 (2016-04-27) = + +* Pro: add the possibility to translate custom post types slugs, taxonomies slugs and more +* Pro: add the possibility to share the same post or term slug across languages +* Pro: add the possibility to duplicate the content when creating a new translation +* Pro: add the possibility to create all translations at once when uploading a media +* Pro: add the possibility to disable a language +* Add license and update management +* Add inline docs for all filters and actions +* When possible, the rel alternate hreflang now display only the language code (without the country code) +* When combined with flags in the language switcher, wrap the language name inside tags +* Add customizer selective refresh support for the language switcher widget ( needs WP 4.5+ ) +* Fix dynamic options of the language switcher widget not working in the customizer +* Fix possible error 404 on page shortlink when using subdomains or multiple domains +* Fix get_adjacent_post() and wp_get_archives() for untranslated post types ( needs WP 4.4+ ) +* Fix language homepage urls not present in Yoast SEO sitemap (when the homepages display posts) + += 1.8.5 (2016-04-03) = + +* Revert from $_SERVER['PHP_SELF'] to $_SERVER['SCRIPT_FILENAME'] to detect if the user is on login/register/signup page +* Fix incompatibility introduced by WP 4.5 in Edit single taxonomy term screen +* Fix existing post overridden when creating a language and a conflicting plugin sets the global $post on languages pages + += 1.8.4 (2016-03-06) = + +* Revert canonical redirection of static front page when combining plain permalinks + default language hidden in url (introduced in 1.8.2) + += 1.8.3 (2016-03-04) = + +* fix: All pages are redirected to the home page on some installations (introduced in 1.8.2) + += 1.8.2 (2016-03-02) = + +* Add support for the 'wpml_get_default_language()' function from the WPML API +* Stop blocking saving settings when errors are detected (invalid domains) +* Use publicly_queryable => true instead of public => true for the language taxonomy (WP 4.5+) +* fix: PHP notice when pll_default_language() is called before a language is created +* fix: PHP notice undefined property PLL_Language::$page_on_front +* fix: canonical redirection of static front page when combining plain permalinks + default language hidden in url +* fix: YARPP compatibility broken in v1.8 +* fix: Remove the delete link for translations of the default category (introduced back by WP 4.3) +* fix: settings not displayed with WP 4.1 or older + += 1.8.1 (2016-01-31) = + +* Update the list of Facebook locales used for Opengraph support with Yoast SEO and Jetpack +* fix: secondary query with translated post type and untranslated taxonomy mixes languages (introduced in 1.8) +* fix: issue with paged static front page when hiding the default language in url +* fix: potential issue with cache after synchronizations +* fix: trailing slash added to canonical home url outputted by Yoast SEO when using default permalinks + += 1.8 (2016-01-19) = + +* Minimum WordPress version is now 4.0 +* Add ary, bn_BD, en_ZA, es_AR, fr_CA and fr_BE to the predefined languages list +* Adopt WordPress coding standards +* New structure for translated posts and terms (=> several methods of PLL_Model are deprecated). +* Revamp the management of the static front page and page for posts +* Improve performance for navigation menus with a lot of pages +* The Polylang and WPML API are now loaded when 'plugins_loaded' is fired (on frontend only if at least one language has been defined) +* Add 'pll_get_post_translations()' and 'pll_get_term_translations()' to the API +* Add filter 'pll_cookie_expiration' to change the cookie expiration time +* Add support for 'wpml_get_language_information()' function from the WPML API +* The default language is now managed directly from the languages list table +* Various accessibility improvements +* It is now possible to choose the languages flags from the available list (custom flags on frontend still work as previously) +* Revamp the settings page (now a list table with inline configuration) +* Add an option to remove all data when uninstalling the plugin +* Add test of subdomains and domains accessibility +* Add post state for translations of the front page and posts page +* Add better support of the customizer menus introduced in WP 4.3 +* Media taxonomies (created by 3rd party plugins) are now filtered by language when editing a media +* Synchronization of taxonomies (created by 3rd party plugins) and meta are now enabled for media +* The 'hreflang' tag now refers to the locale instead of the 2-letters language code +* Workaround for WordPress locales not being W3C valid (see #33511) +* Workaround a bug in Nextgen Gallery causing redirect on album +* Add compatibility with Duplicate Post plugin to avoid duplicated post keeping the link to translations +* Add compatibility with Jetpack Related Posts +* fix: incorrect rewrite rules after changing how the language is set (need to flush rewrite rules after this) +* fix: password protected pages don't work on multiple domains +* fix: ensure that the page parent is in the correct language when using bulk edit +* fix: is_tax set on category and post tags archives when it should not +* fix: automatically added new top-level pages to menus are not filtered by language +* fix: nav menus locations are messed when changing the default language +* fix: error 404 for untranslated taxonomies pages +* fix: single posts and pages links do not include the language code when using the default permalinks and forcing the language code in url +* fix: missing trailing slash on home url when using default permalinks or a static front page +* fix: sticky visibility is copied to new translation only if the synchronization is activated +* fix: remove "» Languages » [language name]" from the feed title +* fix: spaces are not honored when searching strings translations +* fix: default language not set and terms translations not correctly imported when using WordPress Importer +* fix: the browser language detection does not differentiate 'en_US' and 'en_GB' +* fix: non alphanumeric characters query vars values lead to an infinite redirection loop on static front pages +* fix: user profile not saved for a language when the language code contains a "-" +* fix: non translated posts page always link to the static front page even when they should not +* fix: remove hreflang="x-default" when using one domain per language +* fix: deprecated function notice in WP 4.5 alpha +* fix: wrong url for attachments when media are translated and using subdomains +* fix: wrong url for unattached attachments when using subdirectories (since WP 4.4) +* fix: wrong url scheme for custom flags + += 1.7.12 (2015-11-13) = + +* The language taxonomy is now public for compatibility with WP 4.4 +* fix: nav menus locations are not correctly populated in customizer in WP 4.4 +* fix: the termmeta table was still deleted at upgrade +* fix: fatal error when using the argument 'post_id' in 'pll_the_languages()' (introduced in 1.7.11) [props EKesty](https://wordpress.org/support/topic/bug-on) +* fix: potential notice in 'pll_the_languages()' [props mattkeys](https://wordpress.org/support/topic/bug-on) + += 1.7.11 (2015-10-15) = + +* fix: conflict with GET ajax requests sent by the jquery method load +* fix: notice in frontend-nav-menu.php at line 211 (introduced in 1.7.10) [props Jesse Graupmann](https://wordpress.org/support/topic/warning-and-notice-on-upgrade) +* fix: the parent list in page attributes metabox is not in the correct language (introduced in 1.7.10) +* fix: error 404 for attachments +* fix: the language switcher is not displayed when combining "Forces link to front page" and "Hides languages with no translation" + += 1.7.10 (2015-09-28) = + +* Add Occitan translation contributed by [Cédric Valmary](http://www.totenoc.eu/) +* Add de_DE_formal, en_NZ, es_CO, hy, oci, ps and tl to the predefined languages list +* Add the filter 'pll_predefined_languages' and the actions 'pll_language_edit_form_fields' and 'pll_language_add_form_fields' +* the termmeta table (used in Polylang < 1.2) is no more deleted when uninstalling the plugin (as it will soon be included in WP) +* fix: prevent creating a media translation if one already exists +* fix: Attempt to translate the nav menus for themes registering a theme location but not using it in wp_nav_menu() +* fix: Jetpack infinite scroll +* fix: issue with terms languages when two languages have the same name +* fix: notices when deleting a tag and Lingotek is active +* fix: the languages cache is not cleaned when updating the site home url +* fix: conflict with the theme Ambition +* fix: front page canonical url displayed by Yoast SEO +* fix: typo in options definition at install [props null.bit](https://wordpress.org/support/topic/suggestions-for-two-new-filters?replies=5#post-7466159) +* fix: error when adding a term in a non-translated taxonomy + += 1.7.9 (2015-08-17) = + +* Minimum WordPress version is now v3.9 +* Add: hreflang="x-default" on front page when the default language code is not hidden in urls +* fix: remove hreflang links in html head section of paged archives to please Google +* fix: conflict with WPSEO sitemap caching when using multiple domains. [props Junaid Bhura](https://wordpress.org/support/topic/wp-seo-sitemap-and-translation-subdomain-issue?replies=8#post-7113817) +* fix: change the order of strings translations columns for better display on mobile devices in WP 4.3 +* fix: various issues with nav menus and customizer in WP 4.3 +* fix: correctly disallow unchecking both show names and show flags in the language switcher form + += 1.7.8 (2015-07-21) = + +* fix: conflict with PHP < 5.4 introduced in 1.7.7 + += 1.7.7 (2015-07-20) = + +* Add Romanian translation contributed by uskro +* Add Japanese translation contributed by [Eiko Toda](http://www.eikotoda.com) +* Update French translation contributed by [fxbenard](http://fxbenard.com/) +* The language locale is now validated with the same pattern as in WP 4.3. See #28303 +* fix: make sure that the language switcher never finds translations for untranslated post types (could occur when the post type was previously translated) +* fix: display the default category according to the admin language filter in settings->writing +* fix: flushing rewrite rules at network activation and de-activation is back. [props RavanH](https://polylang.wordpress.com/2015/06/10/polylang-1-7-6-and-multisite/comment-page-1/#comment-1138) +* fix: avoid a conflict with WP Super Cache preloading (loading 'polylang_mo' posts which are 404). [props ecdltf](https://wordpress.org/support/topic/polylang_mo-and-404s-take-2) +* fix: customizer menus issues introduced by changes in WP 4.1 +* fix: strings translations are not saved when pressing enter +* fix: it is not possible to de-activate the translation for custom post types and taxonomies from wpml-config.xml +* fix: conflict with plugins using stringified json in ajax requests + += 1.7.6 (2015-06-10) = + +* Add Galician translation contributed by [Toño Calo](http://fedellar.wordpress.com/) +* fix: incorrect post type archive link for untranslated post types +* fix: notices in wp-import.php +* fix: avoid flushing rewrite rules at network activation and de-activation +* fix: the note below the category list table displays the default category according to the admin language filter +* fix: wrong future posts permalinks +* fix: deleting a media translation deletes the file too +* fix: when using persistent object cache, get_terms is not always filtered by the correct language on admin side +* fix: it is possible to create two categories having the same translation +* fix: fatal error when using the dropdown language switcher in WP < 4.1 + += 1.7.5 (2015-05-11) = + +* Add 'pll_languages_list' filter +* fix: warning when a plugin calls 'icl_object_id' with an untranslated post type (seen in ACF 4.4.1) +* fix: the language is not correctly set from the url when using PATHINFO permalinks (introduced in 1.6!) +* fix: notice when a search is filtered by a taxonomy term in a different language + += 1.7.4 (2015-05-03) = + +* fix: translated taxonomies and post types from wpml-config.xml are not filtered on frontend (introduced in 1.7.2) +* fix: WPML strings translations not always loaded (introduced in 1.7) +* fix: $.ajaxPrefilter() may not work as expected [props ScreenfeedFr](https://wordpress.org/support/topic/ajaxprefilter-may-not-work-as-expected) +* fix: can't hide the language code for the default language when using subdomains +* fix: incorrect static front page url when hiding the default language information +* fix: an untranslated posts page may display posts in all languages +* fix: javascript error when changing the language of a hierarchical post type from the languages metabox in WP 4.2 +* fix: subdomains urls are malformed when the main site uses www. +* fix: suggest tags are not filtered in quick edit +* fix: parent page dropdown list not filtered in quick edit + += 1.7.3 (2015-04-11) = + +* the transient 'pll_languages_list' now stores an array of arrays instead of an array of PLL_Language objects +* fix: fatal error for users hosted at GoDaddy (due to PLL_Language objects stored in a transient) +* fix: additional query vars are removed from home page +* fix: categories are not filtered by the admin language switcher in posts list table (introduced in 1.7) +* fix: when using multiple domains, the domain url is lost when modifying the language slug +* fix: the queried object is incorrectly set for author archives (introduced in 1.6.5) +* fix: notice when a nav menu assigned to a translated nav menu location has been deleted +* fix: no canonical redirection when using pretty permalinks and querying default permalinks + += 1.7.2 (2015-03-23) = + +* fix: comments are filtered for posts in a post type not managed by Polylang +* fix: translated static front page don't work when setting PLL_CACHE_HOME_URL to false (introduced in 1.7) +* fix: the query for taxonomies on custom post types is broken (when adding the language code to the url) + += 1.7.1 (2015-03-20) = + +* fix: wrong redirection when using a static front page and replacing the page name by the language code (introduced in 1.7) + += 1.7 (2015-03-19) = + +* Minimum WordPress version is now v3.8 +* Add new languages to the predefined languages list: Swiss German, Hazaragi +* Add compatibility with nested tax queries introduced in WP 4.1 +* Add compatibility with splitting shared terms to be introduced in WP 4.2 +* Add the possibility to change the domain in the default language when using multiple domains (avoids a conflict with the domain mapping plugin) +* Add the possibility to set the language from the code in url when using default permalinks +* Adding the language code in url is now default at first activation (should improve the out of the box compatibility with other plugins and themes) +* Add new language switcher option to hide a language with no translation +* pll_the_languages() now outputs the js code to handle language change in dropdown list (as done by the widget) +* Improve performance by using base64 encoded flags + various slight optimizations +* Improve protection against chained redirects +* The find posts list is now filtered per media language when clicking on attach link in Media library +* Copy alternative text when creating a media translation +* The category checklist in quick edit is now filtered per post language instead of admin language filter +* Quick and bulk language edit don't break translations anymore if the new language is free +* Make it impossible to change the language of the default categories +* Make sure that a default category defined in settings->writing is translated in all languages +* Tweak css for mobiles in add and edit term form +* Tweak the query getting the list of available posts in the autocomplete input field in the post languages metabox +* fix: after adding a term translation, need to refresh the page before adding a new term +* fix: term translations rows are not modified in list table when a term is added / deleted or inline edited +* fix: post translations rows are not modified in list table when a post is inline edited +* fix: using brackets in language name breaks strings translations +* fix: quick edit may conflict with other plugins +* fix: impossible to use several dropdown languages widgets +* fix: pll_the_languages() may display a dropdown with empty options +* fix: the categories widget does not work correctly with dropdown +* fix: autosave post always created after manual save +* fix: tax query not filtered by language when using 'NOT IN' operator on a translated taxonomy +* fix: incorrect translation url for searches filtered by taxonomy +* fix: backward incompatibility for edited_term_taxonomy action introduced in WP 4.2 +* fix: the home link may be incorrect on MS Windows +* fix: tags in wrong language may be assigned when bulk editing posts in several languages +* fix: tags created when bulk editing posts are not assigned any language +* fix: Illegal string offset 'taxonomy' introduced in v1.6.5 +* fix: Undefined property: WP_Query::$queried_object_id when calling pll_the_languages(array('raw' => 1)) in a function hooked to 'wp'. props [KLicheR](https://wordpress.org/support/profile/klicher) +* fix: Notice in admin.php when used with MailPoet plugin + += 1.6.5 (2015-02-18) = + +* Add new correspondences between WordPress locales and Facebook locales (for WPSEO and Jetpack users) +* fix: quick draft posts are always assigned the default category in the default language +* fix: Notice: Undefined offset: 0 in wp-includes/query.php introduced in WP 4.1 +* fix: is_tax and is_archive are not correctly set when a custom taxonomy term is queried +* fix: conflict introduced by WPSEO 1.7.2+ + += 1.6.4 (2015-02-01) = + +* Add es_MX to predefined languages list +* Add compatibility with WordPress SEO sitemaps for multiple domains and subdomains +* fix: a new post is assigned the wrong (untranslated) default category if no category is assigned by the user +* fix: the home links now have the right scheme even if PLL_CACHE_HOME_URL is not set to false +* fix: fatal error when using old versions of WPSEO (I should do what I tell other to do!) +* fix: strings translations are not switched when using switch_to_blog + += 1.6.3 (2015-01-09) = + +* Add Georgian translation contributed by [Tours in Georgia](http://www.georgia-tours.eu/) +* fix: WXR export does not include the language of untranslated terms (will now work only for newly saved terms) +* fix: better cleaning of DB when translated objects are deleted +* fix: incorrect (ajax) translations links when modifying a term language +* fix: warning: Illegal string offset 'taxonomy' introduced by the combination of WP 4.1 and some plugins. + += 1.6.2 (2014-12-14) = + +* fix: bugs and inconsistencies compared to WPML in 'icl_get_languages' (should fix a conflict with Avada) +* fix: https issue +* fix: stop displaying an error when adding en_US as new language (translation not downloaded) +* fix: infinite redirect loop on (unattached) attachment links +* fix: impossible to add tags in post quick edit (introduced in 1.5) +* fix: the customizer does not land to the right page when cumulating: static front page + page name in url + default language code not hidden +* fix: read parent theme wpml-config.xml before child theme +* fix: add protection to avoid empty language +* fix: page preview link again + += 1.6.1 (2014-11-19) = + +* Add Brazilian Portuguese translation contributed by [Henrique Vianna](http://henriquevianna.com/) +* Improve compatibility with Types: allow custom fields to be populated when creating a new translation +* Make it impossible to remove the translations of the default category +* Fix: possibility to add a path when using multiple domains (same path for all languages) broken since v1.5.6 +* Fix: preview link for non default language when using multiple domains +* Fix: error displayed when setting the static front page and only one language has been defined +* Fix: revert changes on rewrite rules with front introduced in 1.6 +* Fix: conflict with WordPress SEO when no language has been created + += 1.6 (2014-10-27) = + +* Add Croatian translation contributed by Bajro +* Add new languages to predefined languages list: Azerbaijani, English (Australia), English (UK), Basque +* Add flag in front of the language select dropdown for posts and terms +* Add widget text translation +* Add opengraph support for locale and translations when WordPress SEO or Jetpack are activated +* Add error message if attempting to assign an untranslated page as static front page +* Add 'pll_sanitize_string_translation' filter to sanitize registered strings translations when saved +* Fix: change the en_US flag to US flag. The UK flag is now associated to en_GB +* Fix: change Belarusian locale from be_BY to bel to in agreement with translate.wordpress.org +* Fix home pages duplicate urls when using domains or subdomains +* Fix rewrite rules with front +* Fix: terms are always in default language when created from post bulk edit + += 1.5.6 (2014-10-11) = + +* Fix: the admin language filter is not active for paginated taxonomy in nav menu admin panel +* Fix: wrong redirection if a domain is a substring of another domain (ex: mysite.com and mysite.co) +* Fix: impossible to translate numeric values in options defined in wpml-config.xml +* Fix: call to undefined method PLL_Links::get_translation_url() with Avada theme +* Fix: manage_{$this->screen->taxonomy}_custom_icolumn is a filter and not an action + += 1.5.5 (2014-09-10) = + +* Fix: missing argument 4 in icl_translate +* Fix: conflict with Vantage theme +* Fix: possible issue with cookie domain on 'localhost' +* Fix: filtering string translations does not work when the group name contains a space +* Fix: Possible 404 error for attachments +* Fix: PHP notice when a shared term is not translated in all taxonomies + += 1.5.4 (2014-08-13) = + +* Add new API functions: pll_get_post_language, pll_get_term_language, pll_translate_string +* Add better compatibility with Jetpack 3 +* Fix: attachments don't get any language when uploaded from frontend +* Fix: authors cannot create tags +* Fix: too restrictive capability checks for some edge cases +* Fix: conflict with WPSEO: taxonomy metas cannot be saved + += 1.5.3 (2014-07-12) = + +* Add: Capability check before creating links in post list table +* Add: Possibility not to cache languages objects with option PLL_CACHE_LANGUAGES (for GoDaddy users) +* Fix: Saving a header or a background in menu Appearance resets nav menus locations (introduced in 1.5) +* Fix: sub-sub-options and deeper levels defined in wpml-config.xml are not translated +* Fix: Fatal error when creating a new site when Polylang is network activated (introduced in v1.5.1) +* Fix: Admin language forced to English when activating Polylang (before creating any new language) +* Fix: 'pll_count_posts' second parameter not taken into account +* Fix: 'edit-post' and 'create-posts' capabilities are not differentiated when saving a post + += 1.5.2 (2014-06-24) = + +* Fix: Revert post translations terms cleaning introduced in 1.5 as it seems to cause problems +* Fix: Impossible to delete a biographical info (introduced in 1.5) +* Fix: Security issue reported by [Gregory Viguier](http://www.screenfeed.fr/) + += 1.5.1 (2014-06-19) = + +* Add: filter 'pll_settings_tabs' and action 'pll_settings_active_tab_{$tab}' +* Add: possibility to add a path when using multiple domains (same path for all languages) +* Fix: Bad redirection if /language/ is added to urls (introduced in 1.5) +* Fix: Nav menu locations are not saved in customizer (introduced in 1.4) +* Fix: Unable to unset nav menu locations +* Fix: Incorrect link for date archives in language switcher (introduced in 1.5) +* Fix: Fatal error when using featured content in Twenty Fourteen +* Fix: Posts bulk edit broken (introduced in 1.5) +* Fix: Polylang does not play nice with switch_to_blog +* Fix: Warning: reset() expects parameter 1 to be array, null given in admin-filters-columns.php on line 81 + += 1.5 (2014-05-29) = + +* Add Ukrainian translation contributed by [http://getvoip.com/](http://getvoip.com/) +* Refresh translation metaboxes (again): now translated posts are chosen from an autocomplete input field +* Categories and post tags translations are also chosen in an autocomplete input field +* Better error management on languages pages +* Use Dashicons instead of Icomoon icons for WP 3.8+ +* Check if translated post is readable by the current user before displaying the language switcher +* Minimum Twenty Fourteen version is now 1.1 +* Code cleaning +* Add support for Quick draft introduced in WP 3.8 +* Add support for object cache plugins for recent posts and recent comments widgets +* Add support for pages with modified query in the language switcher (ex: when multiple post types queried on the same page) +* Add new API functions: pll_languages_list, pll_set_post_language, pll_set_term_language, pll_save_post_translations, pll_save_term_translations, pll_count_posts +* Add new filter pll_the_languages_args +* Add support for ICL_LANGUAGE_CODE == 'all' on admin side +* Fix: Galician flag +* Fix: static page on front pagination is broken +* Fix: search url may be broken +* Fix: PHP notice in icl_get_languages +* Fix: more robust way of detecting language in url when using directory +* Fix: delete translations terms orphans in database +* Fix: inconsistent behavior when setting page on front from customizer +* Fix: deleting a category assigns posts to wrong default category +* Fix: quick edit breaks synchronization +* Fix: some security issues + += 1.4.5 (2014-04-19) = + +* Fix: Notice when combined with WPSEO 1.5+ +* Fix: Impossible to disable a widget language filter once set (introduced in 1.4.4) +* Fix: Unexpected redirection of the homepage with language code when permalink structure has no trailing slash (introduced in 1.4.4) +* Fix: Some installs lead to wrong redirection when using domains (introduced in 1.4.4) +* Fix: Possible infinite redirection while previewing posts (introduced in 1.4.4) +* Fix: Uploaded medias don't get a language since WP 3.9 +* Fix: Compatibility with Twenty Fourteen Ephemera widget in the version shipped with WP 3.9 + += 1.4.4 (2014-04-09) = + +* Add: Compatibility with widgets customizer introduced in WP 3.9 +* Fix: No post in translation dropdown after switching the language in edit post (introduced in 1.4.3) +* Fix: No canonical redirection when there is no language code in url and the language code is not hidden for the default language +* Fix: Suppress language cookie when using multiple domains + += 1.4.3 (2014-03-22) = + +* Add: Serbian translation contributed by Sinisa +* Add: Myanmar translation contributed by Sithu Thwin +* Fix: comment form redirects to wp-admin when using multiple domains or subdomains. +* Fix: fatal error with old versions of PHP (tested on PHP 5.2.4) +* Fix: Bad gateway experienced by users hosted by wpengine.com +* Fix: links got from tiny MCE link button are filtered with admin language filter instead of current post language +* Fix: possibly wrong redirection in check_language_code_in_url when using multiple domains or subdomains + += 1.4.2 (2014-02-24) = + +* Add: check multiple post types in PLL_Model::count_posts +* Fix: error 404 on category links when setting the language by content (introduced in 1.4.1) +* Fix: PHP notices in frontend-nav-menu.php with Artisteer themes +* Fix: decrease the memory usage of untranslated posts list +* Fix: home page not correctly redirected to canonical when using page on front and page name is kept in url + += 1.4.1 (2014-02-16) = + +* Add: Czech translation contributed by [Přemysl Karbula](http://www.premyslkarbula.cz) +* Fix: the displayed language is not correct in quick edit for categories and post tags +* Fix: the language switcher does not display the correct link for translated parent categories if only children have posts +* Fix: 3rd parameter of icl_object_id is not optional +* Fix: issue when combining multiple domains and browser detection -> the combination is now forbidden +* Fix: conflict Shiba Media Library: link between media translations is lost when using media quick edit +* Fix: notice when using taxonomies in wpml-config.xml +* Fix: incorrect post format link +* Fix: Twenty Fourteen Ephemera widget strings are not translated + += 1.4 (2014-01-22) = + +* Add Traditional Chinese translation contributed by [香腸](http://sofree.cc/) +* Minimum WordPress version is now v3.5 +* Refresh translations metaboxes: now translated posts are chosen in a dropdown list +* Check if translated archives for category, tag and post format are empty before displaying the language switcher +* Add specific management of translated featured tag in Twenty Fourteen +* Add the possibility not to cache homepage urls with option PLL_CACHE_HOME_URL (for users having several domains). +* The function get_pages is now filtered by language +* Ajax requests on frontend are now automatically detected. It is no more necessary to set 'pll_load_front' :) +* Various performance improvements +* 'pll_get_post_types' and 'pll_get_taxonomies' filters must be added *before* 'after_setup_theme' is fired +* Pre 1.2 data will be removed from DB at first upgrade at least 60 days after upgrade to 1.4 +* Removed some duplicate code between admin and frontend +* Bug correction: incorrect pagination when using domains or subdomains +* Bug correction: post format link not translated +* Bug correction: impossible to use child terms with same name in hierarchical taxonomies +* Bug correction: the terms list table is filtered according to new translation language instead of admin language filter + += 1.3.1 (2013-12-13) = + +* Bug correction: fatal error on settings page if a static front page without language is set +* Bug correction: wrong home url when using different domains per language + += 1.3 (2013-12-11) = + +* Refresh admin UI for better look in WP 3.8 and more dynamic comportment +* The "Detect browser language" option does now also controls returning visits (based on cookie). +* Improved performance by optimizing some queries for WP 3.5+ +* The user biography in default language is now stored in default WordPress usermeta +* Add language parameter in API function pll_home_url and allow to call it on admin side +* Calling 'get_terms' with the 'lang' parameter now uses a cache object per language +* Bug correction: conflict with unstranslated taxonomies +* Bug correction: possible malformed translation archive url in language switcher +* Bug correction: a wrong language may be displayed in quick edit dropdown +* Bug correction: it is possible to add multiple translations (in the same language) for a single taxonomy term +* Bug correction: non public post types and taxonomies are visible in Polylang settings +* Bug correction: the language is always chosen from cookie (or browser preferences) in some installations +* Bug correction: Firefox language preference is not recognized when comparison is made on locale (instead of ISO 639-1 language code) +* Bug correction: incorrect tax_query in PLL_Auto_Translate + += 1.2.4 (2013-11-28) = + +* Better support for theme customizer +* Bug correction: admin bar search does not filter by language +* Bug correction: possible conflict on secondary query when querying taxonomies or single page +* Bug correction: post type is not included in url when editing or adding a term translation +* Bug correction: various warnings and PHP notices + += 1.2.3 (2013-11-17) = + +* Avoid fatal error when upgrading with Nextgen Gallery active +* Bug correction: menus locations of non default language are lost at theme deactivation +* Bug correction: impossible to set menus locations of non default language in some specific cases +* Bug correction: bbpress admin is broken + += 1.2.2 (2013-11-14) = + +* Updated Polish translation thanks to [Bartosz](http://www.dfactory.eu/) +* Delay strings translations upgrade from 'wp_loaded' to 'admin_init' to avoid fatal error when wp-ecommerce is active +* Remove Jetpack infinite scroll compatibility code as it seems useless with new Polylang 1.2 code structure +* Bug correction: fatal error when doing ajax on frontend +* Bug correction: ICL_LANGUAGE_CODE incorrectly defined when doing ajax on frontend +* Bug correction: ['current_lang'] and ['no-translation'] indexes disappeared from pll_the_languages raw output +* Bug correction: invalid argument supplied for foreach() in /polylang/include/mo.php on line 57 +* Bug correction: cookie may not be correctly set +* Bug correction: languages columns may not be displayed in custom post types and custom taxonomies tables + += 1.2.1 (2013-11-11) = + +* Update badly encoded Latvian translation +* Suppress one query in PLL_WPML_Config when not in multisite +* Bug correction: strings translations are not correctly upgraded +* Bug correction: nav menus locations are not correctly upgraded for non default language + += 1.2 (2013-11-10) = + +This version does include important changes in database. More than ever, make a database backup before upgrading + +* Add Arabic translation contributed by [Anas Sulaiman](http://ahs.pw/) +* Major rewrite with new structure +* Change the language and translations model from meta to taxonomy (no extra termmeta table created anymore) +* Move the strings translations from option to a custom post type +* Add support for language code in subdomain and for one different domain per language (experimental) +* Add support of WordPress Importer plugin. Export must have been done with Polylang 1.2+ (experimental) +* Add support for theme navigation customizer (was de-activated by Polylang since WP 3.4) +* Request confirmation for deleting a language +* Better management of default category for each language +* Now check if date and post type archives are translated before displaying the language switcher +* Update management of the 'copy' action of the custom fields section in wpml-config.xml +* Add support for ICL_LANGUAGE_CODE and ICL_LANGUAGE_NAME of the WPML API on admin side +* Add support of WPSEO custom strings translations when the language is set from content +* Modify admin language filter for valid html and better visibility +* Synchronization is now disabled by default (due to too much conflicts / questions on the forum) +* Include rel="alternate" hreflang="x" selflink per google recommendation +* Improve inline documentation +* Bug correction: wrong datatype for second argument in polylang/include/auto-translate.php (introduced in 1.1.6) +* Bug correction: same id is used for all language items in menu +* Bug correction: wpml-config.xml file not loaded for sitewide active plugins on network installations +* Bug correction: page parent dropdown list (in page attributes metabox) not correctly displayed when switching from a language with empty list + += 1.1.6 (2013-10-13) = + +* Add the possibility to display the upgrade notice on plugins page +* Bug correction: Illegal string offset 'taxonomy' in polylang/include/auto-translate.php +* Bug correction: user defined strings translations are not loaded on admin side +* Bug correction: untranslated post types are auto translated +* Bug correction: tags are not added to post when the name exists in several languages and they are not translations of each other + += 1.1.5 (2013-09-15) = + +* Add compatibility with Aqua Resizer (often used in porfolio themes) +* Add support of 'icl_get_default_language' function from the WPML API +* Remove the 3 characters limitation for the language code +* Change default names for zh_CN, zh_HK, zh_TW +* Bug correction: urls are modified in search forms + += 1.1.4 (2013-08-16) = + +* Add simplified Chinese language contributed by [Changmeng Hu](http://www.wpdaxue.com) +* Add Indonesian language contributed by [ajoull](http://www.ajoull.com/) +* Bug correction: nav menu locations are lost when using the admin language filter +* Bug correction: the cookie is not set when adding the language code to all urls (introduced in 1.1.3) + += 1.1.3 (2013-07-21) = + +* Add Venetian language contributed by Michele Brunelli +* Bug correction: wrong rewrite rules for non translated custom post type archives +* Bug correction: 'post_id' parameter of pll_the_languages does not work +* Bug correction: warning in wp_nav_menu_objects with Artisteer generated themes +* Bug correction: warning when used together with theme my login plugin +* Bug correction: language slug is modified and translations are lost when creating a nav menu with the same name as a language + += 1.1.2 (2013-06-18) = + +* Posts and terms now inherit parent's language if created outside the standard WordPress ui +* Improve the compatibility with the plugins Types and The Events Calendar, and again with WordPress SEO +* Improve performance +* Improve html validation +* Add 'raw' argument to 'pll_the_languages' +* Add the filter 'pll_translation_url' +* Bug correction: no language is set for a (translated custom taxonomy) term when added from a (non translated) custom post type edit page +* Bug correction: warning if 'get_terms' is called with a non-array 'include' argument (introduced in 1.1.1) +* Bug correction: warning if the menu language switcher has nothing to display + += 1.1.1 (2013-05-20) = + +* Move nav menu language switcher split from 'wp_nav_menu_objects' to 'wp_get_nav_menu_items' filter +* Add the filter 'pll_redirect_home' +* Automatically translate ids in 'include' argument of 'get_terms' (useful for the menus in the Suffusion theme) +* Add compatibility with Jetpack infinite scroll +* Bug correction: rtl text direction not set when adding the language code to all urls (introduced in 1.1) +* Bug correction: hide again navigation panel in theme customizer as it still doesn't work +* Bug correction: is_home not set on translated page when searching an empty string +* Bug correction: fatal error when creating a post or term from frontend (introduced in 1.1) +* Bug correction: attachments may load a wrong language when media translation was enabled then disabled +* Bug correction: warning when querying posts before the action 'wp_loaded' has been fired (in auto-translate.php) +* Bug correction: potential issue if other plugins use the filter 'get_nav_menu' +* Bug correction: interference between language inline edit and search in admin list tables +* Bug correction: auto-translate breaks queries tax_query when the 'field' is set to 'id' +* Bug correction: search is not filtered by language for default permalinks (introduced in 1.1) +* Tests done with WP 3.6 beta 3 and Twenty thirteen + += 1.1 (2013-05-10) = + +* When adding the language to all urls, the language is now defined in (plugins_loaded, 1) for better compatibility with some plugins (WordPress SEO) +* When querying posts and terms, ids are now automatically translated +* Add the possibility to group string translations +* Add the possibility to delete strings registered with 'icl_register_string' +* Move the option 'polylang_widgets' in general polylang options +* Better integration of the multilingual nav menus (everything is now integrated in the menus page of WordPress +* The language switcher is now a menu item which can be placed everywhere in a nav menu +* Posts or terms created from frontend are now assigned the current language (or another one if specified in the variable 'lang') +* Bug correction: continents-cities-xx_XX.mo not downloaded +* Bug correction: a gzipped 404 page is downloaded when a mo file does not exist on WordPress languages files repository +* Bug correction: post_date_gmt not synchronized together with post_date +* Tests done with WP 3.6 beta 2 and Twenty thirteen + += 1.0.4 (2013-04-08) = + +* Add Estonian translation contributed by [Ahto Naris](http://profiles.wordpress.org/ahtonaris/) +* Now compatible with languages files stored in wp-content/languages/themes +* Bug correction: page preview does not work when adding the language code to all urls +* Bug correction: error when a post type or taxonomy label is not a string +* Bug correction: admin text section of wpml-config.xml (introduced in 1.0.3) +* Bug correction: infinite redirect loop when querying an unattached media and the language code is added to all urls +* Bug correction: the text direction is not set from Polylang options when the language code is added to all urls +* Bug correction: get_adjacent_post is filtered by language even for post types without language +* Bug correction: the home url is not not in the correct language in wp-login.php +* Bug correction: the language is not correctly set when using date and name permalinks (introduced in 1.0.3) + += 1.0.3 (2013-03-17) = + +* Add Catalan translation contributed by [Núria Martínez Berenguer](http://nuriamb.capa.webfactional.com) +* Add Ukrainian translation contributed by [cmd soft](http://www.cmd-soft.com/) +* Improve compatibility with WordPress SEO (sitemap for categories and tags) +* A query is no more filtered by language when setting the parameter 'lang' to an empty value +* Add the possibility to create a custom wpml-config.xml file in wp-content/polylang/ +* Bug correction: custom menus are not displayed on search page (introduced in 1.0.2) +* Bug correction: sql error when filtering terms by language (introduced in 1.0.2) +* Bug correction: SSL doesn't work properly +* Bug correction: php notice on IIS servers +* Bug correction: clicking on the radio buttons in the admin language switcher does not work in Chrome +* Bug correction: on multisite, the signup page is redirected to the home page +* Bug correction: date archives are not correctly filtered for the default language when hiding the language code and using date and name permalinks +* Bug correction: only one wpml-config.xml file is parsed + += 1.0.2 (2013-02-26) = + +* Add the possibility to query comments by language +* Add the possibility not to set a cookie by defining PLL_COOKIE to false (Polylang may not work as expected on some pages) +* Now a returning visitor is redirected to its preferred language when visiting the front page in the default language +* Add compatibility with the plugin Custom field template (copy and synchronize custom fields) +* Improve compatibility with plugins or themes which overwrite columns in posts list table +* Add the filter 'pll_get_flag' +* Add support of 'icl_unregister_string' function from the WPML API +* Bug correction: synchronizing custom fields breaks the plugin Advanced Custom Fields +* Bug correction: 'pll_default_language' broken +* Bug correction: rewrite rules are not flushed when re-activating the plugin +* Bug correction: feed urls are not correctly escaped when using default permalinks +* Bug correction: notice Undefined index: media_support +* Bug correction: custom post types and taxonomies set in wpml-config.xml are not hidden +* Bug correction: get_terms cannot query multiple languages +* Bug correction: 'icl_register_string' is now persistent as in WPML (fixes Nextgen gallery translations which were not working) + += 1.0.1 (2013-01-28) = + +* Add Swedish translation contributed by [matsii](http://wordpress.org/support/profile/matsii) +* Add 2 new API functions : 'pll_is_translated_post_type' and 'pll_is_translated_taxonomy' +* Bug correction: when using a static front page, the posts page is not filtered by language (introduced in 1.0) +* Bug correction: disable translation for hard coded menu as it creates more problems than it solves (introduced in 1.0) + += 1.0 (2013-01-24) = + +* Add Hungarian translation contributed by Csaba Erdei +* Add Norwegian translation contributed by [Tom Boersma](http://www.oransje.com/) +* Add Slovak translation contributed by [Branco (WebHostingGeeks.com)](http://webhostinggeeks.com/user-reviews/) +* Code cleaning -> remove compatibility with versions older than 0.8 +* Add search in the string translations list table +* Add options to better control the synchronization of various metas for posts +* It is now possible to synchronize sticky posts and publication dates +* Add option to disable the multilingual support of media +* Add options to better control the multilingual capability of custom post types and taxonomies +* Better integration with new media management in WP 3.5 +* Improve menu translation for themes which register a theme location but don't use it in wp_nav_menu (hard coded menu) +* Add the pll_preferred_language filter allowing plugins to modify the language set by browser preferences detection +* Add support of the WPML config file +* Add support of 'icl_get_languages' and 'icl_link_to_element' functions from the WPML API +* Add compatibility with YARPP and improve compatibility with WordPress SEO +* Change cookie name which conflicts with Quick cache and allow users to overwrite it by defining the constant PLL_COOKIE +* Bug correction: again the canonical redirection +* Bug correction: the languages are not correctly displayed after they have been modified using quick edit +* Bug correction: undefined index notice when saving strings translation when the admin language filter is active +* Bug correction: rewrite rules are not correctly flushed when adding / deleting a language (introduced in 0.9.2) +* Bug correction: the list of pages is displayed when a static font page translation is not translated (now replaced by the list of posts) +* Bug correction: permalinks are not modified when doing cron and the language code is added to all urls +* Bug correction: creating a new term with the same name as a language may modify the language code (slug) + += 0.9.8 (2012-12-05) = + +* Bug correction: ajax on frontend does not work when adding the language code to all urls +* Bug correction: search forms using the get_search_form filter do not work + += 0.9.7 (2012-12-04) = + +* Bug correction: the admin language filter does filter non translatable post types +* Bug correction: again the canonical redirection +* Bug correction: fatal error when Polylang is used together with 'Author Avatars List' +* Bug correction: widget titles uselessly appear in the strings translations table when the widget is set for only one language +* Tests done with WordPress 3.5 RC3 and Twenty Twelve + += 0.9.6 (2012-11-26) = + +* It is now possible to query the terms by language using the WordPress function 'get_terms' +* Bug correction: search for empty string in default language displays posts in all languages when hiding the URL language information for default language +* Bug correction: completely reworked the canonical redirection introduced in 0.9.5 which created more problems than it solved +* Bug correction: ajax for media translations does not work +* Started tests with WordPress 3.5 RC1 and Twenty Twelve + += 0.9.5 (2012-11-13) = + +* The user can now choose the number of languages and strings translations to display +* Add compatibility with the 'icl_object_id' function and ICL_LANGUAGE_CODE and ICL_LANGUAGE_NAME constants from the WPML API +* Add 17 languages to the predefined list (automatic download and update of language files won't work) +* Bug correction: post preview does not work when adding the language code to all urls +* Bug correction: redirect to front page in default language when posting a comment on static front page +* Bug correction: impossible to create terms with the same name in different languages +* Bug correction: query string added by other plugins is erased when adding the language code to all urls +* Bug correction: redirect erase 'POST' variables on homepage when adding the language code to all urls +* Bug correction: English (en_US) loads rtl style when using a localized WordPress package with an rtl language +* Bug correction: on some installation strings translations do not work with some special characters +* Bug correction: incoming links are not redirected to canonical url when adding the language code to all urls and hiding the code for the default language +* Bug correction: search form does not work in non default language when using permalinks without trailing slash + += 0.9.4 (2012-10-23) = + +* Add Afrikaans translation contributed by [Kobus Joubert](http://translate3d.com/) +* Add Belarusian translation contributed by [Alexander Markevitch](http://fourfeathers.by/) +* Add Afrikaans (af) and Belarusian (be_BY) to predefined languages list (automatic download and update of language files won't work) +* Add the possibility to translate the date format and time format +* Add compatibility with the 'icl_get_home_url' function from the WPML API +* Bug correction: still some issues with string translations +* Bug correction: search is not filtered by the (default) language when the language is set by content and the language code is hidden for the default language +* Bug correction: posts & pages preview urls are broken when adding the language code to all urls +* Bug correction: automatically added new top-level pages to menus are not filtered by language +* Bug correction: the admin language filter messes the categories languages when editing a post and the parent dropdown list when editing a category +* Bug correction: search form does not work when using a static front page (introduced in 0.9.2) +* Bug correction: can't set languages for categories and post tags on blogs created after polylang has been activated at network level +* Bug correction: menus don't work with catch box theme ('has_nav_menu' not correctly filtered) + += 0.9.3 (2012-10-08) = + +* Add Bulgarian translation contributed by [pavelsof](http://wordpress.org/support/profile/pavelsof) +* Add compatibility with WPML API for strings translations +* Bug correction: dates are not translated (introduced in 0.9.2) +* Bug correction: the language is lost when keeping - No change - for language in bulk edit +* Bug correction: categories and tags are duplicate (when default language is set automatically to existing content and categories and tags share the same name) + += 0.9.2 (2012-09-30) = + +* Support new WordPress (WP 3.5+) convention for js and css files naming +* Improve performance, mainly on frontend +* Bug correction: the category language is not set when creating it in the post editor (introduced in 0.9) +* Bug correction: unable to add a query string when using a static front page +* Bug correction: ajax tag suggestion in "edit post" conflicts with the admin content language filter +* Bug correction: ugly notices when trying to access a static front page which has not been translated +* Bug correction: the language code is added to custom post types and taxonomies permalinks even if they are not translatable +* Bug correction: some arrays in wp_locale mix English and other language +* Bug correction: the media language is not correctly set when uploading from post if the post has not been saved after choosing the language + += 0.9.1 (2012-09-20) = + +* Add Finnish translation contributed by [Jani Alha](http://www.wysiwyg.fi) +* Bug correction: improve the robustness of the admin content language filter +* Bug correction: the language switcher displays languages which have no posts or pages (introduced in 0.9) +* Bug correction: wrong default language when adding a new media +* Bug correction: the dropdown language switcher does not switch language when there is no post translation +* Bug correction: issue with translations when using category quick edit +* Bug correction: home redirects to 404 when combining static front page + force_lang = 1 + hide_default = 0 + += 0.9 (2012-09-12) = + +* Add Turkish translation contributed by [darchws](http://darch.ws/) +* Add media translation support +* Add a persistent content language filter on admin side (WP 3.2+ required) +* Add biographical info translation +* Add multiline support for string translations +* Add the possibility to clean the strings translation database +* Add quick edit and bulk edit support for posts and pages +* Add quick edit support for categories and tags +* The language is now loaded with 'setup_theme' action instead of 'wp' action when always adding language information url +* Search form now does use javascript only for searchform.php when pretty permalinks are not used +* Add the option PLL_SEARCH_FORM_JS to disable the js code used to modify the search form +* Suppress the option PLL_SYNC, replaced by an option in the language settings ui +* Suppress the PLL_DISPLAY_ALL option +* Suppress the template tag 'the_languages' (replaced by 'pll_the_languages' since v0.5) +* Suppress the function 'pll_is_front_page' (useless since 0.8.2) +* Bug correction: the browser language is sometimes not correctly detected by Android +* Bug correction: the rtl text direction is not correct when editing an existing language +* Bug correction: rss feed does not work if translated site title or tagline contains special characters +* Bug correction: post types and taxonomies labels are not translated on frontend +* Bug correction: the filter 'pll_copy_post_metas' does not work for metas with multiple values +* Bug correction: translations table for post and terms are uselessly serialized two times +* Bug correction: attempt to suppress conflict with themes which hardcode the name of nav menus (but do define a theme location) +* Bug correction: homepage displays all posts when the front page displays a static page and no page is selected for front page (but one is selected for posts page) +* Bug correction: widgets disappear when Polylang is enabled + += 0.8.10 (2012-08-06) = + +* Add Lithuanian (lt_LT) to predefined languages list (automatic download and update of language files won't work) +* Add Lithuanian translation contributed by [Naglis Jonaitis](http://najo.lt/) +* Bug correction: empty string translation issue +* Bug correction: 'wp_list_pages' does not filter custom post types +* Bug correction: warning if posts are queried before the action 'wp_loaded' has been fired +* Bug correction: notice in twentyten when requesting a date archive with no posts + += 0.8.9 (2012-07-20) = + +* Add Portuguese translation contributed by [Vitor Carvalho](http://vcarvalho.com/) + += 0.8.8 (2012-07-18) = + +* Validation improvement thanks to kg69design +* Bug correction: custom post types rewrite rules are broken when registered with query_var=>false +* Bug correction: user admin language not deleted when uninstalling the plugin +* Bug correction: pll_current_language('name') returns locale instead of language name +* Bug correction: ajax on frontend does not work +* Bug correction: homepage pagination broken when redirecting the language page to a static front page +* Bug correction: taxonomies conflicts on custom post types +* Bug correction: the admin language is not updated when edited by other users + += 0.8.7 (2012-06-10) = + +* Add the possibility to load Polylang API for ajax requests on frontend +* Bug correction: search form is broken when using a static front page +* Bug correction: admin bar search does not work +* Tests done with WordPress 3.4 RC2 + += 0.8.6 (2012-05-23) = + +* Add the possibility to use a local config file to set options +* Improve robustness (less PHP notices) +* Bug correction: Menus not showing in preview mode +* Bug correction: fatal error when customizing a theme in WP 3.4 beta 4 +* Bug correction: second page of search results returns 404 when using pretty permalinks + += 0.8.5 (2012-05-14) = + +* Bug correction : sites using static front page are messed in v0.8.4 + += 0.8.4 (2012-05-13) = + +* Add a new argument 'post_id' to the function pll_the_languages to display posts translations within the loop +* Bug correction: every posts in every languages are shown on the homepage when requesting the wrong one with or without 'www.' +* Bug correction: every posts in every languages are shown when requesting /?p=string +* Bug correction: the language is not correctly set for wp-signup.php and wp-activate.php +* Bug correction: wrong home links when using permalinks with front with WP 3.3 and older +* Bug correction: wrong redirection after posting a comment when adding the language information to all urls +* Bug correction: term language may be lost in some situations +* Bug correction: post language is set to default if updated outside the edit post page +* Bug correction: javascript error in WP 3.1 +* Bug correction: can't toggle visibility of tags metabox in edit post panel +* Tests done with WordPress 3.4 beta 4 + += 0.8.3 (2012-04-10) = + +* Add Danish translation contributed by [Compute](http://wordpress.org/support/profile/compute) +* Add Spanish translation contributed by Curro +* Add the possibility to add a content in a different language than the current one by setting explicitly the lang parameter in the secondary query +* Add support of PATHINFO permalinks +* Bug correction: secondary queries not correctly filtered by language +* Bug correction: wrong archives links when using permalinks with front +* Bug correction: wrong homepage link when keeping 'language' in permalinks with front +* Bug correction: flush_rewrite_rules notice when setting up a static front page (introduced in 0.8.2) +* Bug correction: every posts in every languages are shown when hitting the homepage with a query string unknown to WP (thanks to Gonçalo Peres) +* Bug correction: every posts in every languages are shown on the homepage when PHP adds index.php to the url +* Tests done with WordPress 3.4 beta 1 + + += 0.8.2 (2012-03-20) = + +* Add Italian translation contributed by [Luca Barbetti](http://wordpress.org/support/profile/lucabarbetti) +* Improve performance on admin side +* Comment status and ping status are now copied when adding a new translation +* Deprecated API function 'pll_is_front_page' as it is now useless +* Bug correction: Wrong translation url for taxonomies when adding the language information to all urls +* Bug correction: "translation" of search page does not work if the site is only made of pages +* Bug correction: wrong language permalink structure introduced in 0.8.1 +* Bug correction: wrong language set when clicking on "add new" translation in edit category and edit tags panels +* Bug correction: site does not display if no languages are set +* Bug correction: get_author_posts_url is 404 +* Bug correction: homepage is 404 when using a static front page and adding the language information to all urls + += 0.8.1 (2012-03-11) = + +* Add Latvian translation contributed by [@AndyDeGroo](http://twitter.com/AndyDeGroo) +* It is now possible to synchronize multiple values for custom fields +* Add new API function pll_current_language +* Add the pll_rewrite_rules filter allowing plugins to filter rewrite rules by language +* WP 3.4 preparation: disable the menu section in the customize theme admin panel (unusable with Polylang) +* Bug correction: removing 'language' in permalinks does not work in WP 3.4 alpha +* Bug correction: problems with custom post type archives when 'has_archive' is set (thanks to AndyDeGroo) +* Bug correction: 404 error when combining %postname% permastructure with "Add language information to all URL" option +* Bug correction: translated custom strings are duplicated if registered several times +* Bug correction: queries with an array of post types are not correctly filtered +* Bug correction: wp-login.php always in English + += 0.8 (2012-02-29) = + +* Sticky posts are now filtered by language +* It is now possible to use the language page as home page +* Add an "About Polylang" metabox on the languages admin page +* Add the pll_the_languages filter allowing to filter the whole output of the language switcher +* Add a new argument 'display_names_as' to the function pll_the_languages +* Add pll_get_post_types & pll_get_taxonomies filters allowing to enable / disable the language filter for post types & taxonomies +* Add ckb to predefined languages list +* Completely reworked the string translation storage in the database +* Some performance improvements on admin side +* Improve compatibility with other plugins broken by the home url filter +* Add an option to disable the home url filter +* Add an option to disable synchronization of metas between translations +* Bug correction: body class 'home' is not set on translated homepage +* Bug correction: robots.txt is broken when adding the language code to all urls (including default language) +* Bug correction: bad name for the Czech flag +* Bug correction: bad language information in rss feed for WP < 3.4 +* Bug correction: signup broken on multisite +* Bug correction: the translation url is set to self when using a static front page and no page for posts and there is no translation +* Bug correction: problems with custom post type archive titles +* Bug correction: problems with custom post type if rewrite slug is different from post_type (thanks to AndyDeGroo) +* Bug correction: quick edit still breaks translation linking of pages (thanks to AndyDeGroo) +* Bug correction: bad rewrite rules for feeds (introduced in 0.7.2) +* Bug correction: the order is not saved when creating a language +* Bug correction: the categories list is not updated when adding a new category (ajax broken) + += 0.7.2 (2012-02-15) = + +* Add Polish translation contributed by [Peter Paciorkiewicz](http://www.paciorkiewicz.pl) +* Add 5 new languages to predefined list +* completely reworked rewrite rules +* WP 3.4 preparation: add new WordPress languages files to download when creating a new language +* Bug correction: custom nav menus do not work in Artisteer generated themes +* Bug correction: having a single language causes multiple warnings while saving post/page. +* Bug correction: custom nav menu broken on archives pages +* Bug correction: the language switcher does not link to translated post type archive when using pretty permalinks +* Bug correction: the tags are not saved in the right language when translated tags have the same name +* Bug correction: bad link in post preview when adding language code to all urls +* Bug correction: feed not filtered by language when adding language code to all urls +* Bug correction: duplicate canonical link when used together with WordPress SEO by Yoast +* Bug correction: the all posts admin page is messed if another plugin adds a column +* Bug correction: 404 error on static front page when adding language code to all urls (including default language) + += 0.7.1 (2012-02-06) = + +* Allow using 3 characters languages codes (ISO 639-2 or 639-3) +* The predefined languages dropdown list now displays the locale to help differentiate some languages +* Add 5 new languages to predefined list +* Bug correction: the filter 'pll_copy_post_metas' does not work +* Bug correction: impossible to add a tag in the edit post panel +* Bug correction: rewrite rules not correct +* Bug correction: cache issue with css and js files + += 0.7 (2012-01-30) = + +* Add Hebrew translation contributed by [ArielK](http://www.arielk.net) +* Add support for RTL languages for both frontend and admin +* Twenty Ten and Twenty Eleven languages files are now automatically downloaded when creating a new language +* Improve filtering tags by language in the edit post panel +* Category parent dropdown list is now filtered by language +* Category parents are now synchronized between translations +* Add the possibility to have the language information in all URL +* Add support for post formats +* Add option allowing not to show the current language in the language switcher (for both menu and widget) +* Add a title attribute (and the possibility to personalize it with a filter) to flags +* pll_get_post and pll_get_term second parameter is now optional and defaults to current language +* Add pll_the_language_link filter allowing to filter translation links outputted by the language switcher +* The option PLL_DISPLAY_ALL is no longer supported +* Bug correction: Autosave reset to default language +* Bug correction: blog info not translated in feeds +* Bug correction: post comments feed always in default language +* Bug correction: undefined index notice when setting up a custom menu widget +* Bug correction: rewrite rules are not correctly reset when deactivating the plugin +* Bug correction: is_home not correctly set on pages 2, 3... +* Bug correction: avoid naming conflicts (in sql queries) with other themes / plugins +* Bug correction: bad language detection and url rewriting of custom post types archives + += 0.6.1 (2012-01-12) = + +* Add Dutch translation contributed by [AlbertGn](http://wordpress.org/support/profile/albertgn) +* Disable everything except the languages management panel while no language has been created +* Bug correction: can't have the same featured image in translated posts +* Bug correction: parent page dropdown does appear only after the page has been saved +* Bug correction: archives widget not working anymore +* Bug correction: string translations does not work for WP < 3.3 +* Bug correction: fix fatal error in string translations caused by widgets using the old API +* Bug correction: the strings translation panel is unable to translate strings with special characters +* Bug correction: Polylang "is_front_page" returns true on archives pages + += 0.6 (2012-01-07) = + +* Add Greek translation contributed by [theodotos](http://www.ubuntucy.org) +* WordPress languages files are now automatically downloaded when creating a new language (and updated when updating WordPress) +* Add the possibility to change the order of the languages in the language switcher +* Add the possibility to translate the site title, tagline and widgets titles +* Categories, post tags, featured image, page parent, page template and menu order are now copied when adding a new translation +* Translations are now accessibles in the "Posts", "Pages", "Categories" and "Post tags" admin panels +* Improve the dropdown language switcher widget (sends now to translated page or home page based on options) +* Move custom flags from polylang/local_flags to wp_content/polylang +* Add two options to "pll_the_languages" ('hide_if_no_translation' and 'hide_current'). *The function does not output ul tag anymore* +* Improve API +* Bug correction: Twenty eleven custom Header problem with v0.5.1 +* Bug correction: front-page.php not loaded for translated front page + += 0.5.1 (2011-12-18) = + +* Improved German translation contributed by [Christian Ries](http://www.singbyfoot.lu) +* Bug correction: translated homepage not recognized as home page when it displays posts +* Bug correction: predefined language list does not work on IE8 +* Bug correction: on some installations, "Add New" post doesn't keep intended language +* Bug correction: fatal error when Polylang is used together with the plugin Tabbed Widgets +* Bug correction: language Switcher points sometimes to wrong places + += 0.5 (2011-12-07) = + +* Add multisite support +* Rework the Polylang admin panel. There is now a set of predefined languages +* Improve categories and tags language filter in the edit post panel +* Categories and tags created in the edit post panel are now created with the same language as the post +* The language switcher can now force the link to the front page instead of the translated page +* The nav menus can now display a language switcher +* Improved performance +* Optimized the calendar widget (less code and sql queries executed) +* Added the possibility to display posts and terms with no language set (see the documentation to know how to enable this functionality) +* Started the creation of a small API for theme and plugin programmers +* Bug correction: when using a static front page, the page for posts does not work when using the default permalink settings +* Bug correction: the search form does not work if a static front page is used +* Bug correction: quick edit breaks translations +* Bug correction: categories and post tags translations don't work for more than 2 languages +* Bug correction: the output of wp_page_menu is not correct for non default languages + += 0.4.4 (2011-11-28) = + +* Bug correction: When using a static front page, the translated home page displays posts instead of the translated page +* Bug correction: Automatic language setting of existing categories and post tags does not work correctly + += 0.4.3 (2011-11-19) = + +* Add Russian translation contributed by [yoyurec](http://yoyurec.in.ua) +* Bug correction: impossible to suppress the language name in the language switcher widget settings +* Bug correction: post's page does not work when using a static front page +* Bug correction: flags in local_flags directory are removed after an automatic upgrade (now works for an upgrade from 0.4.3+ to a higher version) +* Bug correction: switching to default language displays a 404 Error when hiding the default language in url and displaying the language switcher as dropdown +* Other minor bug corrections +* Tests done with WordPress 3.3 beta 3 + += 0.4.2 (2011-11-16) = + +* Bug correction: language settings page is broken in v0.4.1 + += 0.4.1 (2011-11-16) = + +* Bug correction: flags shows even when you set doesn't to show +* Bug correction: custom taxonomies do not work +* Bug correction: some users get the fatal error: call to undefined function wp_get_current_user() in /wp-includes/user.php on line 227 + += 0.4 (2011-11-10) = + +* Add a documentation (in English only) +* Add the possibility to hide the url language information for the default language +* Add the possibility to set the admin language in the user profile +* Add the possibility to fill existing posts, pages, categories & tags with the default language +* Add support for custom post types and custom taxonomies +* Add the possibility to display flags in the language switcher +* Add CSS classes to customize rendering of the language switcher +* Add the possibility to display the language switcher as a dropdown list +* Add support for calendar widget +* Improve performance: less sql queries +* Improve data validation when creating or updating languages +* Bug correction: 'wp_list_pages' page order is ignored when the plugin is enabled +* Bug correction: when using 'edit' or 'add new' (translation) for posts, the categories appear in the wrong language +* Bug correction: pages are not included in language post count +* Bug correction: the language switcher does not display languages if there are only pages +* Bug correction: the widget filter does not allow to come back to 'all languages' once a language has been set +* Other minor bug corrections + += 0.3.2 (2011-10-20) = + +* Bug correction: authors pages are not filtered by language +* Bug correction: language pages use the archive template +* Bug correction: database error for comments on posts and pages +* Bug correction: "Add new" translation for pages creates a post instead of a page +* Bug correction: the search query does not look into pages + += 0.3.1 (2011-10-16) = + +* Bug correction: the widget settings cannot be saved when activating Polylang +* Bug correction: the archives widget does not display any links +* Bug correction: ajax form for translations not working in the 'Categories' and 'Post tags' admin panels + += 0.3 (2011-10-07) = + +* Add language filter for widgets +* Improved performance for filtering pages by language +* Improved security +* Minor bug correction with versions management + += 0.2 (2011-10-05) = + +* Add language filter for nav menus +* Add German translation +* Add language filter for recent comments +* Add ajax to term edit form +* Add ajax to post metabox +* Improved performance for filtering terms by language +* Bugs correction + += 0.1 (2011-09-22) = +* Initial release diff --git a/wp-content/plugins/polylang-pro/css/build/admin-export-import.css b/wp-content/plugins/polylang-pro/css/build/admin-export-import.css new file mode 100644 index 000000000..d9b7b67ba --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/admin-export-import.css @@ -0,0 +1,55 @@ +/* Metaboxes holder in Strings translations screen */ +.languages_page_mlang_strings .metabox-holder > div { + display: flex; +} +.languages_page_mlang_strings .metabox-holder > div > div { + flex-grow: 1; +} +.languages_page_mlang_strings .metabox-holder > div > div:nth-child(2n) { + margin-left: 1rem; +} +.languages_page_mlang_strings .metabox-holder > div > div.closed { + border:0; + background: none; +} +.languages_page_mlang_strings .metabox-holder > div > div.closed .postbox-header{ + border: 1px solid #ccd0d4; + background: #fff; +} + +#pll-export-strings-box.postbox .submit, /* Override WordPress styles */ +#pll-import-translations-box.postbox .submit { + float: none; + padding: 0; +} + +#export-string-translation .pll-translation-flag { + margin: auto 10px auto 7px; +} + +#export-string-translation label, +#export-string-translation label[for="pll-select-format"] span, +#import-translation label { + display: block; + margin: 0.35em 0 0.5em; +} + +.pll-legend { + display: block; + padding: 2px 0; + color: #1d2327; + font-weight: 400; + text-shadow: none; + margin: 0.35em 0 0.5em; +} + +/* Narrow devices */ +@media screen and ( max-width: 782px ) { + /* Metaboxes holder in Strings translations screen */ + .languages_page_mlang_strings .metabox-holder > div { + flex-direction: column; + } + .languages_page_mlang_strings .metabox-holder > div > div:nth-child(2n) { + margin-left: 0; + } +} diff --git a/wp-content/plugins/polylang-pro/css/build/admin-export-import.min.css b/wp-content/plugins/polylang-pro/css/build/admin-export-import.min.css new file mode 100644 index 000000000..c7b7ca018 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/admin-export-import.min.css @@ -0,0 +1 @@ +.languages_page_mlang_strings .metabox-holder>div{display:flex}.languages_page_mlang_strings .metabox-holder>div>div{flex-grow:1}.languages_page_mlang_strings .metabox-holder>div>div:nth-child(2n){margin-left:1rem}.languages_page_mlang_strings .metabox-holder>div>div.closed{background:none;border:0}.languages_page_mlang_strings .metabox-holder>div>div.closed .postbox-header{background:#fff;border:1px solid #ccd0d4}#pll-export-strings-box.postbox .submit,#pll-import-translations-box.postbox .submit{float:none;padding:0}#export-string-translation .pll-translation-flag{margin:auto 10px auto 7px}#export-string-translation label,#export-string-translation label[for=pll-select-format] span,#import-translation label,.pll-legend{display:block;margin:.35em 0 .5em}.pll-legend{color:#1d2327;font-weight:400;padding:2px 0;text-shadow:none}@media screen and (max-width:782px){.languages_page_mlang_strings .metabox-holder>div{flex-direction:column}.languages_page_mlang_strings .metabox-holder>div>div:nth-child(2n){margin-left:0}} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/admin.css b/wp-content/plugins/polylang-pro/css/build/admin.css new file mode 100644 index 000000000..d71aad602 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/admin.css @@ -0,0 +1,459 @@ +/* languages admin panel */ +#add-lang select { + width: 95%; +} + +#add-lang label { + margin: 0.35em 0 0.5em; +} + +.pll-legend { + display: block; + padding: 2px 0; + color: #1d2327; + font-weight: 400; + text-shadow: none; + margin: 0.35em 0 0.5em; +} + +.column-locale, +.languages .column-slug { + width : 15% +} + +.column-default_lang { + width : 5%; +} + +.column-term_group, +.column-flag, .column-count { + width : 10%; +} + +td.column-default_lang .icon-default-lang:before, +.pll-wizard-content .icon-default-lang:before { + font-family: 'dashicons'; + content: "\f155"; +} + +.pll-icon:before{ + display: inline-block; + text-align: left; + width: 15px; +} +.pll-circle:before{ + content: "\25cf"; +} + +/* about Polylang metabox */ +#pll-about-box p, +#pll-recommended p { + text-align: justify; +} + +#pll-about-box input { + margin: 0; + padding: 0; + float: right; +} + +/* strings translation table */ +.stringstranslations .column-name, +.stringstranslations .column-context { + width: 10%; +} + +.stringstranslations .column-string { + width: 33%; +} + +.translation label { + display: inline-block; + width: 23%; + vertical-align: top; +} + +.translation { + display: flex; /* fix #691 to remove default margin bottom */ +} +@media screen and (max-width: 782px) { /* reset default display property for small device */ + .translation{ + display: block; + } +} +.translation textarea{ + display: block; /* fix #691 to remove default margin bottom */ +} +.translation input, +.translation textarea { + width: 72%; + box-sizing: border-box; /* to be sure field don't overrun outside their wrapper */ + margin-bottom: 4px; /* fix #691 set the same margin bottom for both textarea and input tags */ +} + +/* settings */ +.pll-settings { + margin-top: 20px; +} + +.pll-settings .plugin-title { + width: 25%; +} + +#wpbody-content .pll-settings .pll-configure tr { + display: table-row; +} + +#wpbody-content .pll-settings .pll-configure td { + display: table-cell; +} + +#wpbody-content .pll-settings .pll-configure > td { + padding: 20px 20px 20px 40px; +} + +.pll-configure legend { + font-size: 14px; + font-weight: 600; + margin-bottom: 0.5em; +} + +.pll-configure td .description { + margin-top: 2px; + margin-bottom: 0.5em; +} + +.pll-configure p.submit { + margin-top: 20px; +} + +.pll-configure .button { + margin-right: 20px; +} + +.pll-configure fieldset { + margin-bottom: 1.5em; +} + +.pll-inline-block-list { + margin: 0; +} + +.pll-inline-block-list li { + display: inline-block; + margin: 0; + width: 250px; +} + +/* settings URL modifications */ +#pll-domains-table td { + padding: 2px 2px 2px 1.5em; + -webkit-box-shadow: none; + box-shadow: none; + border: none; +} + +.pll-settings-url-col { + display: inline-block; + width: 49%; + vertical-align: top; +} + +/* settings Activation keys */ +.pll-table-top td { + vertical-align: top; +} + +#pll-licenses-table label { + font-size: 1em; + font-weight: 600; +} + +.pll-configure .pll-deactivate-license { + margin: 0 0 0 20px; +} + +/* language columns in edit.php and edit-tags.php */ +.wp-list-table th[class*='column-language_'], +.wp-list-table td[class*='column-language_'] { + width: 1.5em; + box-sizing: content-box; /* Override ACF 5.9.0 styles */ +} + +/* Text direction in post.php and edit-tags.php */ +.pll-dir-rtl textarea, +.pll-dir-rtl input[type="text"] { + direction: rtl; +} + +.pll-dir-ltr textarea, +.pll-dir-ltr input[type="text"] { + direction: ltr; +} + +.pll-dir-ltr .tr_lang, +.pll-dir-rtl .tr_lang { + direction: inherit; +} + +/* languages metabox in post.php */ +#ml_box p { + margin-top: 1em; +} + +#post-translations p { + float: left; + margin-top: 1em; +} + +.rtl #post-translations p { + float: right; +} + +#post-translations table { + table-layout: fixed; + width: 100%; + clear: both; +} + +#post-translations a { + text-decoration: none; +} + +#post-translations .pll-language-column, +#post-translations .pll-column-icon { + width: 20px; +} + +#post-translations .tr_lang { + width: 100%; +} + +#post-translations td { + padding: 2px; +} + +#post-translations .spinner, +#term-translations .spinner { + float: none; + margin: 0; + background-position: center; + width: auto; +} + +#select-post-language .pll-select-flag { + padding: 4px; + margin-right: 10px; +} + +.rtl #select-post-language .pll-select-flag { + padding: 4px; + margin-right: 0px; + margin-left: 10px; +} + +/* specific cases for media */ +#select-media-language .pll-select-flag { + padding: 4px; + margin-right: 10px; +} + +.pll-media-edit-column { + float: right; +} + +/* language and translations in edit-tags.php */ +.pll-translation-flag { /* also for media */ + margin-right: 14px; +} + +#select-add-term-language .pll-select-flag { + padding: 11px; + margin-right: 13px; +} + +#select-edit-term-language .pll-select-flag { + padding: 11px; + margin-right: 4px; +} + +#term-translations p { + /* same style as label */ + font-weight: 400; + font-style: normal; + padding: 2px; + color: #23282d; +} + +#add-term-translations, +#edit-term-translations { + width: 95%; +} + +#term-translations .pll-language-column { + line-height: 28px; + width: 20%; +} + +#term-translations .pll-edit-column, +#add-term-translations .pll-language-column { + width: 20px; +} + +#edit-term-translations .pll-language-column { + padding: 15px 10px; + font-weight: normal; +} + +/* icon fonts */ +.pll_icon_add:before { + content: "\f132"; +} + +.pll_icon_edit:before { + content: "\f464"; +} + +[class^="pll_icon_"] { + font: 20px/1 'dashicons'; + vertical-align: middle; +} + +/* admin bar */ +#wpadminbar #wp-admin-bar-languages .ab-item img { + margin: 0 8px 0 2px; +} + +#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon { + float: none; + top: 4px; +} + +#wpadminbar #wp-admin-bar-languages .ab-icon:before { + content: "\f326"; + top: 1px; +} + +#wp-admin-bar-languages.pll-filtered-languages { + background: #a03f3f; +} + +#wpadminbar #wp-admin-bar-languages.pll-filtered-languages span.ab-label{ /* Enforce white color for WordPress admin light theme. */ + color: #fff; +} + +/* Notices */ +.pll-notice.notice { + padding-right: 38px; + position: relative; +} + +.pll-notice a.notice-dismiss { + text-decoration: none; +} + +.pll-notice .button { + margin-right: 10px; +} + +@media screen and ( max-width: 782px ) { + /* settings */ + #wpbody-content .pll-settings .pll-configure > td { + padding: 20px; + } + + #wpbody-content .pll-settings #cb { + padding: 20px 9px; + } + + /* settings URL modifications */ + .pll-inline-block { + width: auto; + } + + .pll-settings-url-col { + display: block; + width: 100%; + } + + /* settings licenses */ + #wpbody-content .pll-settings #pll-licenses-table td { + display: block; + } + + .pll-configure .pll-deactivate-license { + margin: 10px 0 5px; + } + + /* strings translations table */ + .translation label { + display: block; + width: 95%; + padding-left: 0; + } + + .translation input, + .translation textarea { + width: 95%; + } + + /* hide selected language flag and translations language name */ + #select-add-term-language .pll-select-flag, + #select-edit-term-language .pll-select-flag, + #edit-term-translations .pll-language-name { + display: none; + } + + #edit-term-translations { + width: 100%; + } + + #add-term-translations .pll-language-column { + line-height: 38px; + } + + #edit-term-translations td { + padding: 8px 10px; + } + + #edit-term-translations .pll-language-column, + #edit-term-translations .pll-edit-column { + width: 20px; + } + + /* translations tables should be kept as table */ + .term-translations .pll-language-column, + .term-translations .pll-edit-column, + .term-translations .pll-translation-column { + display: table-cell; + } + + .term-translations .hidden { + display: none; + } + + /* admin bar */ + #wpadminbar #wp-admin-bar-languages { + display: block; /*shows our menu on mobile devices */ + } + + #wpadminbar #wp-admin-bar-languages > .ab-item { + width: 50px; + text-align: center; + } + + #wpadminbar #wp-admin-bar-languages > .ab-item .ab-icon:before { + font: 32px/1 'dashicons'; + top: -1px; + } + + #wpadminbar #wp-admin-bar-languages > .ab-item img { + margin: 19px 0; + } + + #wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon { + margin-right: 6px; + font-size: 20px !important; + line-height: 20px !important; + } +} diff --git a/wp-content/plugins/polylang-pro/css/build/admin.min.css b/wp-content/plugins/polylang-pro/css/build/admin.min.css new file mode 100644 index 000000000..81a59eb50 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/admin.min.css @@ -0,0 +1 @@ +#add-lang select{width:95%}#add-lang label,.pll-legend{margin:.35em 0 .5em}.pll-legend{color:#1d2327;display:block;font-weight:400;padding:2px 0;text-shadow:none}.column-locale,.languages .column-slug{width:15%}.column-default_lang{width:5%}.column-count,.column-flag,.column-term_group{width:10%}.pll-wizard-content .icon-default-lang:before,td.column-default_lang .icon-default-lang:before{content:"\f155";font-family:dashicons}.pll-icon:before{display:inline-block;text-align:left;width:15px}.pll-circle:before{content:"\25cf"}#pll-about-box p,#pll-recommended p{text-align:justify}#pll-about-box input{float:right;margin:0;padding:0}.stringstranslations .column-context,.stringstranslations .column-name{width:10%}.stringstranslations .column-string{width:33%}.translation label{display:inline-block;vertical-align:top;width:23%}.translation{display:flex}@media screen and (max-width:782px){.translation{display:block}}.translation textarea{display:block}.translation input,.translation textarea{box-sizing:border-box;margin-bottom:4px;width:72%}.pll-settings{margin-top:20px}.pll-settings .plugin-title{width:25%}#wpbody-content .pll-settings .pll-configure tr{display:table-row}#wpbody-content .pll-settings .pll-configure td{display:table-cell}#wpbody-content .pll-settings .pll-configure>td{padding:20px 20px 20px 40px}.pll-configure legend{font-size:14px;font-weight:600;margin-bottom:.5em}.pll-configure td .description{margin-bottom:.5em;margin-top:2px}.pll-configure p.submit{margin-top:20px}.pll-configure .button{margin-right:20px}.pll-configure fieldset{margin-bottom:1.5em}.pll-inline-block-list{margin:0}.pll-inline-block-list li{display:inline-block;margin:0;width:250px}#pll-domains-table td{border:none;-webkit-box-shadow:none;box-shadow:none;padding:2px 2px 2px 1.5em}.pll-settings-url-col{display:inline-block;vertical-align:top;width:49%}.pll-table-top td{vertical-align:top}#pll-licenses-table label{font-size:1em;font-weight:600}.pll-configure .pll-deactivate-license{margin:0 0 0 20px}.wp-list-table td[class*=column-language_],.wp-list-table th[class*=column-language_]{box-sizing:content-box;width:1.5em}.pll-dir-rtl input[type=text],.pll-dir-rtl textarea{direction:rtl}.pll-dir-ltr input[type=text],.pll-dir-ltr textarea{direction:ltr}.pll-dir-ltr .tr_lang,.pll-dir-rtl .tr_lang{direction:inherit}#ml_box p{margin-top:1em}#post-translations p{float:left;margin-top:1em}.rtl #post-translations p{float:right}#post-translations table{clear:both;table-layout:fixed;width:100%}#post-translations a{text-decoration:none}#post-translations .pll-column-icon,#post-translations .pll-language-column{width:20px}#post-translations .tr_lang{width:100%}#post-translations td{padding:2px}#post-translations .spinner,#term-translations .spinner{background-position:50%;float:none;margin:0;width:auto}#select-post-language .pll-select-flag{margin-right:10px;padding:4px}.rtl #select-post-language .pll-select-flag{margin-left:10px;margin-right:0;padding:4px}#select-media-language .pll-select-flag{margin-right:10px;padding:4px}.pll-media-edit-column{float:right}.pll-translation-flag{margin-right:14px}#select-add-term-language .pll-select-flag{margin-right:13px;padding:11px}#select-edit-term-language .pll-select-flag{margin-right:4px;padding:11px}#term-translations p{color:#23282d;font-style:normal;font-weight:400;padding:2px}#add-term-translations,#edit-term-translations{width:95%}#term-translations .pll-language-column{line-height:28px;width:20%}#add-term-translations .pll-language-column,#term-translations .pll-edit-column{width:20px}#edit-term-translations .pll-language-column{font-weight:400;padding:15px 10px}.pll_icon_add:before{content:"\f132"}.pll_icon_edit:before{content:"\f464"}[class^=pll_icon_]{font:20px/1 dashicons;vertical-align:middle}#wpadminbar #wp-admin-bar-languages .ab-item img{margin:0 8px 0 2px}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{float:none;top:4px}#wpadminbar #wp-admin-bar-languages .ab-icon:before{content:"\f326";top:1px}#wp-admin-bar-languages.pll-filtered-languages{background:#a03f3f}#wpadminbar #wp-admin-bar-languages.pll-filtered-languages span.ab-label{color:#fff}.pll-notice.notice{padding-right:38px;position:relative}.pll-notice a.notice-dismiss{text-decoration:none}.pll-notice .button{margin-right:10px}@media screen and (max-width:782px){#wpbody-content .pll-settings .pll-configure>td{padding:20px}#wpbody-content .pll-settings #cb{padding:20px 9px}.pll-inline-block{width:auto}.pll-settings-url-col{display:block;width:100%}#wpbody-content .pll-settings #pll-licenses-table td{display:block}.pll-configure .pll-deactivate-license{margin:10px 0 5px}.translation label{display:block;padding-left:0;width:95%}.translation input,.translation textarea{width:95%}#edit-term-translations .pll-language-name,#select-add-term-language .pll-select-flag,#select-edit-term-language .pll-select-flag{display:none}#edit-term-translations{width:100%}#add-term-translations .pll-language-column{line-height:38px}#edit-term-translations td{padding:8px 10px}#edit-term-translations .pll-edit-column,#edit-term-translations .pll-language-column{width:20px}.term-translations .pll-edit-column,.term-translations .pll-language-column,.term-translations .pll-translation-column{display:table-cell}.term-translations .hidden{display:none}#wpadminbar #wp-admin-bar-languages{display:block}#wpadminbar #wp-admin-bar-languages>.ab-item{text-align:center;width:50px}#wpadminbar #wp-admin-bar-languages>.ab-item .ab-icon:before{font:32px/1 dashicons;top:-1px}#wpadminbar #wp-admin-bar-languages>.ab-item img{margin:19px 0}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{font-size:20px!important;line-height:20px!important;margin-right:6px}} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/bulk-translate.css b/wp-content/plugins/polylang-pro/css/build/bulk-translate.css new file mode 100644 index 000000000..1821966d4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/bulk-translate.css @@ -0,0 +1,57 @@ +.bulk-translate-save .button { + margin-right: 20px; +} + +#wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper { + display: flex; +} + +#wpbody-content #pll-translate fieldset { + flex-basis: fit-content; + margin-right: 10%; +} + +#pll-translate .pll-translation-flag { + margin: auto 10px auto 7px; +} + +.rtl #pll-translate .pll-translation-flag { + margin: auto 7px auto 10px; +} + +#pll-translate .title { + display: block; + line-height: 2.5; +} + +#pll-translate label { + display: flex; + align-items: center; +} + +#pll-translate label span.description{ + line-height: normal; +} + +#pll-translate label[for="pll-select-format"] { + padding-left: 18px; +} + +#pll-translate #pll-select-format { + margin-left: 0.5rem; +} + +@supports(selector(:has(*))) { + #pll-translate label[for="pll-select-format"] { + display: none; + } + #pll-translate label:has([name="translate"][value="pll_export_post"]:checked) ~ [for="pll-select-format"] { + display: flex; + } +} + +@media screen and ( max-width: 782px ) { + #wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper { + flex-direction: column; + } +} diff --git a/wp-content/plugins/polylang-pro/css/build/bulk-translate.min.css b/wp-content/plugins/polylang-pro/css/build/bulk-translate.min.css new file mode 100644 index 000000000..1408b1599 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/bulk-translate.min.css @@ -0,0 +1 @@ +.bulk-translate-save .button{margin-right:20px}#wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper{display:flex}#wpbody-content #pll-translate fieldset{flex-basis:fit-content;margin-right:10%}#pll-translate .pll-translation-flag{margin:auto 10px auto 7px}.rtl #pll-translate .pll-translation-flag{margin:auto 7px auto 10px}#pll-translate .title{display:block;line-height:2.5}#pll-translate label{align-items:center;display:flex}#pll-translate label span.description{line-height:normal}#pll-translate label[for=pll-select-format]{padding-left:18px}#pll-translate #pll-select-format{margin-left:.5rem}@supports(selector(:has(*))){#pll-translate label[for=pll-select-format]{display:none}#pll-translate label:has([name=translate][value=pll_export_post]:checked)~[for=pll-select-format]{display:flex}}@media screen and (max-width:782px){#wpbody-content #pll-translate .pll-bulk-translate-fields-wrapper{flex-direction:column}} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/dialog.css b/wp-content/plugins/polylang-pro/css/build/dialog.css new file mode 100644 index 000000000..103d15af1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/dialog.css @@ -0,0 +1,85 @@ +/* By default Polylang dialog box use WordPress jQuery UI dialog styles. + However WooCommerce loads its own jQuery UI dialog styles and we need to override them by ours + to revert to the default WordPress ones. +*/ +.pll-confirmation-modal.ui-widget, +.pll-confirmation-modal.ui-widget .ui-widget, +.pll-confirmation-modal .ui-widget { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 13px; +} +.pll-confirmation-modal.ui-dialog { + padding: 0; + z-index: 100102; + background: #fff; + border: 0; + color: #444; + border-radius: 0; /* Override WooCommerce dialog styles - jQuery UI 1.11.4 - WP < 5.6 */ +} +.ui-dialog.pll-confirmation-modal .ui-dialog-titlebar { + background: #fcfcfc; + border-radius: 0; + border: 0; + border-bottom: 1px solid #dfdfdf; + height: 36px; + font-size: 18px; + font-weight: 600; + line-height: 2; + padding: 0 36px 0 16px; + color: #444; + position: static; +} +.ui-dialog.pll-confirmation-modal .ui-dialog-title { + float: none; + width: auto; + margin: 0; +} +.pll-confirmation-modal .ui-widget-header .ui-icon { + background: none; + position: static; +} +.pll-confirmation-modal .ui-button.ui-dialog-titlebar-close { + padding: 0; + margin: 0; + top: 0; + right: 0; + width: 36px; + height: 36px; + border: 0; /* Override WooCommerce dialog styles - jQuery UI 1.11.4 - WP < 5.6 */ + background: none; /* Override WooCommerce dialog styles - jQuery UI 1.11.4 - WP < 5.6 */ +} +.ui-dialog.pll-confirmation-modal .ui-dialog-content { + border: 0; + padding: 16px; + color: #444; + position: static; + box-sizing: border-box; +} +.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane{ + margin: 0; + padding: 16px; + border: 0; + background: #fcfcfc; + border-top: 1px solid #dfdfdf; +} +.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane .ui-button{ + margin: 0 0 0 16px; + padding: 0 10px 1px; + background: #f7f7f7; + border: 1px solid #cccccc; + border-radius: 3px; + position: static; + line-height: 2; + vertical-align: top; +} +.ui-dialog.pll-confirmation-modal .ui-button:hover, +.ui-dialog.pll-confirmation-modal .ui-button:focus { + background: #fafafa; + border-color: #999; + color: #23282d; +} +.pll-confirmation-modal + .ui-widget-overlay { + background: #000; + opacity: 0.7; + z-index: 100101; +} diff --git a/wp-content/plugins/polylang-pro/css/build/dialog.min.css b/wp-content/plugins/polylang-pro/css/build/dialog.min.css new file mode 100644 index 000000000..b5bd71857 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/dialog.min.css @@ -0,0 +1 @@ +.pll-confirmation-modal .ui-widget,.pll-confirmation-modal.ui-widget,.pll-confirmation-modal.ui-widget .ui-widget{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.pll-confirmation-modal.ui-dialog{background:#fff;border:0;border-radius:0;color:#444;padding:0;z-index:100102}.ui-dialog.pll-confirmation-modal .ui-dialog-titlebar{background:#fcfcfc;border:0;border-bottom:1px solid #dfdfdf;border-radius:0;color:#444;font-size:18px;font-weight:600;height:36px;line-height:2;padding:0 36px 0 16px;position:static}.ui-dialog.pll-confirmation-modal .ui-dialog-title{float:none;margin:0;width:auto}.pll-confirmation-modal .ui-widget-header .ui-icon{background:none;position:static}.pll-confirmation-modal .ui-button.ui-dialog-titlebar-close{background:none;border:0;height:36px;margin:0;padding:0;right:0;top:0;width:36px}.ui-dialog.pll-confirmation-modal .ui-dialog-content{border:0;box-sizing:border-box;color:#444;padding:16px;position:static}.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane{background:#fcfcfc;border:0;border-top:1px solid #dfdfdf;margin:0;padding:16px}.ui-dialog.pll-confirmation-modal .ui-dialog-buttonpane .ui-button{background:#f7f7f7;border:1px solid #ccc;border-radius:3px;line-height:2;margin:0 0 0 16px;padding:0 10px 1px;position:static;vertical-align:top}.ui-dialog.pll-confirmation-modal .ui-button:focus,.ui-dialog.pll-confirmation-modal .ui-button:hover{background:#fafafa;border-color:#999;color:#23282d}.pll-confirmation-modal+.ui-widget-overlay{background:#000;opacity:.7;z-index:100101} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.css b/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.css new file mode 100644 index 000000000..5e536e841 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.css @@ -0,0 +1,103 @@ +.pll-settings .pll-inner-notice { + margin: 5px 0 15px; + border: 1px solid #c3c4c7; + border-left-width: 4px; + padding: 1px 12px; + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); +} + +.form-table .pll-inner-notice { + margin-bottom: 5px; +} + +.pll-settings .notice-success { + border-left-color: #00a32a; +} + +.pll-settings .notice-warning { + border-left-color: #dba617; +} + +.pll-settings .notice-error { + border-left-color: #d63638; +} + +.pll-settings .pll-inner-notice p { + margin: 0.5em 0; + padding: 2px; +} + +.pll-settings .pll-message:not(.pll-origin-message), +.pll-settings .notice-success .pll-origin-message, +.pll-settings .notice-warning .pll-origin-message, +.pll-settings .notice-error .pll-origin-message { + display: none; +} + +.pll-settings .notice-success .pll-success-message, +.pll-settings .notice-warning .pll-warning-message.pll-message-shown, +.pll-settings .notice-error .pll-error-message.pll-message-shown { + display: block; +} + +.pll-settings [disabled] + .spinner, +.pll-progress-bar-wrapper .spinner { + visibility: visible; +} + +.pll-success-message .pll-icon { + color: rgb(18, 91, 145); +} + +.pll-error-message .pll-icon, +.pll-warning-message .pll-icon { + color: rgb(145, 30, 31); +} + +.pll-icon { + font-size: 1.8em; + margin-right: 3px; + margin-left: 1px; + vertical-align: -2px; +} + +.pll-progress-bar-wrapper { + position: relative; + max-width: 500px; + height: 2em; + line-height: 2em; + vertical-align: middle; + text-align: left; + font-size: 2em; + border: 1px solid rgb(64, 70, 72); + border-radius: 4px; + overflow: hidden; + white-space: nowrap; + color: rgb(23, 114, 181); + text-indent: 1em; +} + +.pll-progress-bar-wrapper div { + position: absolute; + height: 100%; + top: 0; + left: 0; + overflow: hidden; + background-color: rgb(23, 114, 181); + color: rgb(232, 230, 227); +} + +.pll-settings [type="password"] + .button { + margin-left: 20px; + margin-right: 0; +} + +.pll-settings [type="password"] + .button + .spinner { + float: none; +} + +.pll-progress-bar-wrapper .spinner { + float: none; + margin: 0; +} diff --git a/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.min.css b/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.min.css new file mode 100644 index 000000000..9fe31b161 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/machine-translation-settings.min.css @@ -0,0 +1 @@ +.pll-settings .pll-inner-notice{background:#fff;border:1px solid #c3c4c7;border-left-width:4px;box-shadow:0 1px 1px rgba(0,0,0,.04);margin:5px 0 15px;padding:1px 12px}.form-table .pll-inner-notice{margin-bottom:5px}.pll-settings .notice-success{border-left-color:#00a32a}.pll-settings .notice-warning{border-left-color:#dba617}.pll-settings .notice-error{border-left-color:#d63638}.pll-settings .pll-inner-notice p{margin:.5em 0;padding:2px}.pll-settings .notice-error .pll-origin-message,.pll-settings .notice-success .pll-origin-message,.pll-settings .notice-warning .pll-origin-message,.pll-settings .pll-message:not(.pll-origin-message){display:none}.pll-settings .notice-error .pll-error-message.pll-message-shown,.pll-settings .notice-success .pll-success-message,.pll-settings .notice-warning .pll-warning-message.pll-message-shown{display:block}.pll-progress-bar-wrapper .spinner,.pll-settings [disabled]+.spinner{visibility:visible}.pll-success-message .pll-icon{color:#125b91}.pll-error-message .pll-icon,.pll-warning-message .pll-icon{color:#911e1f}.pll-icon{font-size:1.8em;margin-left:1px;margin-right:3px;vertical-align:-2px}.pll-progress-bar-wrapper{border:1px solid #404648;border-radius:4px;color:#1772b5;font-size:2em;height:2em;line-height:2em;max-width:500px;overflow:hidden;position:relative;text-align:left;text-indent:1em;vertical-align:middle;white-space:nowrap}.pll-progress-bar-wrapper div{background-color:#1772b5;color:#e8e6e3;height:100%;left:0;overflow:hidden;position:absolute;top:0}.pll-settings [type=password]+.button{margin-left:20px;margin-right:0}.pll-settings [type=password]+.button+.spinner{float:none}.pll-progress-bar-wrapper .spinner{float:none;margin:0} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/metabox-button.css b/wp-content/plugins/polylang-pro/css/build/metabox-button.css new file mode 100644 index 000000000..04df336d4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/metabox-button.css @@ -0,0 +1,25 @@ +.pll-button { + padding: 0; + height: 20px; + background: none; + border: none; + font-size: 20px; + cursor: pointer; +} + +.pll-button:not(.wp-ui-text-highlight) { + color: #DDDDDD; +} + +.pll-button svg { + fill: currentColor; +} + +.pll-before-post-translations-button { + float: right; + margin: 13px 7px; +} + +.rtl .pll-before-post-translations-button { + float: left; +} diff --git a/wp-content/plugins/polylang-pro/css/build/metabox-button.min.css b/wp-content/plugins/polylang-pro/css/build/metabox-button.min.css new file mode 100644 index 000000000..422452d49 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/metabox-button.min.css @@ -0,0 +1 @@ +.pll-button{background:none;border:none;cursor:pointer;font-size:20px;height:20px;padding:0}.pll-button:not(.wp-ui-text-highlight){color:#ddd}.pll-button svg{fill:currentColor}.pll-before-post-translations-button{float:right;margin:13px 7px}.rtl .pll-before-post-translations-button{float:left} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/selectmenu.css b/wp-content/plugins/polylang-pro/css/build/selectmenu.css new file mode 100644 index 000000000..6040faa26 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/selectmenu.css @@ -0,0 +1,239 @@ +/* Greatly modified version of the jquery-ui.css */ + +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: none; +} + +.ui-menu .ui-menu { + position: absolute; +} + +.ui-menu .ui-menu-item { + position: relative; + margin: 0; + padding: 3px 1em 3px .4em; + cursor: pointer; + min-height: 0; /* support: IE7 */ + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} + +/* for jQuery UI 1.12 which introduces a wrapper */ +.ui-menu .ui-menu-item:not([role]) { + padding: 0; +} + +.ui-menu-item-wrapper { + padding: 3px 1em 3px 2em; +} +.rtl .ui-menu .ui-menu-item { + text-align: right; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} + +.ui-menu-icons .ui-menu-item[role] { + padding-left: 2em; +} + +.rtl .ui-menu-item-wrapper, /* for jQuery UI 1.12 which introduces a wrapper */ +.rtl .ui-menu-icons .ui-menu-item[role] { + padding-left: 1em; + padding-right: 2em; +} + +/* left-aligned */ +.ui-selectmenu-text .ui-icon, +.ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .3em; + margin: auto 0; +} + +.rtl .ui-selectmenu-text .ui-icon, +.rtl .ui-menu .ui-icon { + right: .3em; + left: auto; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + left: auto; + right: 0; +} + +.ui-selectmenu-menu { + padding: 0; + margin: 0; + position: absolute; + top: 0; + left: 0; + display: none; +} + +.ui-selectmenu-menu .ui-menu { + overflow: auto; + /* Support: IE7 */ + overflow-x: hidden; + padding-bottom: 1px; +} + +.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup { + font-size: 1em; + font-weight: bold; + line-height: 23px; + padding: 2px 0.4em; + margin: 0.5em 0 0 0; + height: auto; + border: 0; +} + +.ui-selectmenu-open { + display: block; +} + +.ui-selectmenu-button, /* jQuery UI 1.11.4 - WP < 5.6 */ +.ui-selectmenu-button.ui-button { + display: inline-block; + overflow: hidden; + position: relative; + text-decoration: none; + box-sizing: border-box; /* To keep width calculation in percent since WP 5.6 */ + text-align: left; + white-space: nowrap; + vertical-align: top; + padding: 0; + line-height: normal; /* Override WC Bookings styles with WP < 5.6 */ + height: 28px; /* Override WC Bookings styles with WP < 5.6 */ +} + +.ui-selectmenu-button span.ui-icon { + right: 0.5em; + left: auto; + position: absolute; + top: 26%; + width: 16px; + height: 16px; + text-indent: 0; /* due to text-indent for jquery ui-dialog in wizard */ + background: none; +} + +.rtl .ui-selectmenu-button span.ui-icon { + left: 0.5em; + right: auto; +} + + +.ui-selectmenu-button.ui-widget span.ui-selectmenu-text, /* Override WC Bookings styles with WP < 5.6 */ +.ui-selectmenu-button span.ui-selectmenu-text { + text-align: left; + padding: 0.1em 2.1em 0.2em 2em; + display: block; + line-height: 23px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin: 0; +} + +.rtl .ui-selectmenu-button span.ui-selectmenu-text { + text-align: right; + padding: 0.2em 2em 0.2em 2.1em; +} + +.ui-widget-content, +.ui-state-default, +.ui-selectmenu-button.ui-state-default, /* Override WC Bookings styles with WP < 5.6 */ +.ui-button.ui-selectmenu-button-closed, /* To be compatible jQuery UI 1.12.1 since WordPress 5.6 */ +.ui-button.ui-selectmenu-button-open, /* To be compatible jQuery UI 1.12.1 since WordPress 5.6 */ +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + background: #fff; + border: 1px solid #ddd; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07) inset; + color: #32373c; +} +/* Override to have same styles as WP form styles since WordPress 5.4 */ +.toplevel_page_mlang .ui-selectmenu-button.ui-state-default, +.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-closed, /* To be compatible jQuery UI 1.12.1 since WordPress 5.6 */ +.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-open{ /* To be compatible jQuery UI 1.12.1 since WordPress 5.6 */ + box-shadow: 0 0 0 transparent; + border-radius: 4px; + border: 1px solid #7e8993; +} + +/* From this line and below: override WooCommerce bookings plugin styles which overrides default WordPress styles */ +.pll-selectmenu-menu .ui-widget, +.pll-selectmenu-button.ui-widget { + font-size: 13px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; +} + +.toplevel_page_mlang .ui-button.ui-selectmenu-button:focus{ + color: #016087; /* Same color as WordPress focused select HTML tag */ + border-color: #007cba; + box-shadow: 0 0 0 1px #007cba; + outline: 2px solid transparent; + background: #fff; /* Override bookings plugin styles which overrides default WordPress styles */ +} + +.toplevel_page_mlang .ui-menu-item, +.toplevel_page_mlang .ui-widget-content .ui-state-hover, +.toplevel_page_mlang .ui-widget-content .ui-state-focus, +.toplevel_page_mlang .ui-widget-content .ui-state-active { + color: #016087; /* Same color as option in a WordPress focused select HTML tag */ + margin: 0; +} + +.ui-selectmenu-open .ui-widget-content .ui-state-hover, /* Override WC Bookings styles with WP < 5.6 */ +.ui-selectmenu-open .ui-widget-content .ui-state-focus, /* Override WC Bookings styles with WP < 5.6 */ +.ui-selectmenu-open .ui-widget-content .ui-state-active, /* Override WC Bookings styles with WP < 5.6 */ +.pll-selectmenu-menu .ui-widget-content .ui-state-hover, +.pll-selectmenu-menu .ui-widget-content .ui-state-focus, +.pll-selectmenu-menu .ui-widget-content .ui-state-active { /* To be compatible jQuery UI 1.12.1 since WordPress 5.6 */ + background: #d5d5d5; + border: 0; +} + +.ui-selectmenu-button.ui-state-focus { + border: 1px solid #5b9dd9; + box-shadow: 0 0 2px rgba(30, 140, 190, 0.8); +} + +.ui-icon-triangle-1-s:before { + content: ""; + background: #fff url(data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E) no-repeat right 0px top 55%; + background-size: 16px 16px; + box-sizing: border-box; + position: absolute; + width: 16px; + height: 16px; +} + +.pll-selectmenu-button.ui-button:hover, +.pll-wizard .ui-button:hover, +.pll-wizard .ui-button:focus { + background: #fff; /* To override jQuery ui-dialog styles provided by WordPress */ +} + +.ui-widget-content { + max-height: 231px; + box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3); +} diff --git a/wp-content/plugins/polylang-pro/css/build/selectmenu.min.css b/wp-content/plugins/polylang-pro/css/build/selectmenu.min.css new file mode 100644 index 000000000..92e0fbd3c --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/selectmenu.min.css @@ -0,0 +1 @@ +.ui-widget-overlay{height:100%;left:0;position:fixed;top:0;width:100%}.ui-menu{display:block;list-style:none;margin:0;outline:none;padding:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{cursor:pointer;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);margin:0;min-height:0;padding:3px 1em 3px .4em;position:relative}.ui-menu .ui-menu-item:not([role]){padding:0}.ui-menu-item-wrapper{padding:3px 1em 3px 2em}.rtl .ui-menu .ui-menu-item{text-align:right}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item[role]{padding-left:2em}.rtl .ui-menu-icons .ui-menu-item[role],.rtl .ui-menu-item-wrapper{padding-left:1em;padding-right:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{bottom:0;left:.3em;margin:auto 0;position:absolute;top:0}.rtl .ui-menu .ui-icon,.rtl .ui-selectmenu-text .ui-icon{left:auto;right:.3em}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{display:none;left:0;margin:0;padding:0;position:absolute;top:0}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{border:0;font-size:1em;font-weight:700;height:auto;line-height:23px;margin:.5em 0 0;padding:2px .4em}.ui-selectmenu-open{display:block}.ui-selectmenu-button,.ui-selectmenu-button.ui-button{box-sizing:border-box;display:inline-block;height:28px;line-height:normal;overflow:hidden;padding:0;position:relative;text-align:left;text-decoration:none;vertical-align:top;white-space:nowrap}.ui-selectmenu-button span.ui-icon{background:none;height:16px;left:auto;position:absolute;right:.5em;text-indent:0;top:26%;width:16px}.rtl .ui-selectmenu-button span.ui-icon{left:.5em;right:auto}.ui-selectmenu-button span.ui-selectmenu-text,.ui-selectmenu-button.ui-widget span.ui-selectmenu-text{display:block;line-height:23px;margin:0;overflow:hidden;padding:.1em 2.1em .2em 2em;text-align:left;text-overflow:ellipsis;white-space:nowrap}.rtl .ui-selectmenu-button span.ui-selectmenu-text{padding:.2em 2em .2em 2.1em;text-align:right}.ui-button.ui-selectmenu-button-closed,.ui-button.ui-selectmenu-button-open,.ui-selectmenu-button.ui-state-default,.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);color:#32373c}.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-closed,.toplevel_page_mlang .ui-selectmenu-button.ui-selectmenu-button-open,.toplevel_page_mlang .ui-selectmenu-button.ui-state-default{border:1px solid #7e8993;border-radius:4px;box-shadow:0 0 0 transparent}.pll-selectmenu-button.ui-widget,.pll-selectmenu-menu .ui-widget{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px}.toplevel_page_mlang .ui-button.ui-selectmenu-button:focus{background:#fff;border-color:#007cba;box-shadow:0 0 0 1px #007cba;color:#016087;outline:2px solid transparent}.toplevel_page_mlang .ui-menu-item,.toplevel_page_mlang .ui-widget-content .ui-state-active,.toplevel_page_mlang .ui-widget-content .ui-state-focus,.toplevel_page_mlang .ui-widget-content .ui-state-hover{color:#016087;margin:0}.pll-selectmenu-menu .ui-widget-content .ui-state-active,.pll-selectmenu-menu .ui-widget-content .ui-state-focus,.pll-selectmenu-menu .ui-widget-content .ui-state-hover,.ui-selectmenu-open .ui-widget-content .ui-state-active,.ui-selectmenu-open .ui-widget-content .ui-state-focus,.ui-selectmenu-open .ui-widget-content .ui-state-hover{background:#d5d5d5;border:0}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 0 top 55%;background-size:16px 16px;box-sizing:border-box;content:"";height:16px;position:absolute;width:16px}.pll-selectmenu-button.ui-button:hover,.pll-wizard .ui-button:focus,.pll-wizard .ui-button:hover{background:#fff}.ui-widget-content{box-shadow:0 2px 6px hsla(0,0%,39%,.3);max-height:231px} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/css/build/style.css b/wp-content/plugins/polylang-pro/css/build/style.css new file mode 100644 index 000000000..573a293b3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/style.css @@ -0,0 +1,289 @@ +/** +* Converts a hex value into the rgb equivalent. +* +* @param {string} hex - the hexadecimal value to convert +* @return {string} comma separated rgb values +*/ +/** + * Colors + */ +/** + * Breakpoints & Media Queries + */ +/** + * SCSS Variables. + * + * Please use variables from this sheet to ensure consistency across the UI. + * Don't add to this sheet unless you're pretty sure the value will be reused in many places. + * For example, don't add rules to this sheet that affect block visuals. It's purely for UI. + */ +/** +* Converts a hex value into the rgb equivalent. +* +* @param {string} hex - the hexadecimal value to convert +* @return {string} comma separated rgb values +*/ +/** + * Colors + */ +/** + * Fonts & basic variables. + */ +/** + * Typography + */ +/** + * Grid System. + * https://make.wordpress.org/design/2019/10/31/proposal-a-consistent-spacing-system-for-wordpress/ + */ +/** + * Radius scale. + */ +/** + * Elevation scale. + */ +/** + * Dimensions. + */ +/** + * Mobile specific styles + */ +/** + * Editor styles. + */ +/** + * Block & Editor UI. + */ +/** + * Block paddings. + */ +/** + * React Native specific. + * These variables do not appear to be used anywhere else. + */ +/** +* Converts a hex value into the rgb equivalent. +* +* @param {string} hex - the hexadecimal value to convert +* @return {string} comma separated rgb values +*/ +/** + * Long content fade mixin + * + * Creates a fading overlay to signify that the content is longer + * than the space allows. + */ +/** + * Typography + */ +/** + * Breakpoint mixins + */ +/** + * Focus styles. + */ +/** + * Applies editor left position to the selector passed as argument + */ +/** + * Styles that are reused verbatim in a few places + */ +/** + * Allows users to opt-out of animations via OS-level preferences. + */ +/** + * Reset default styles for JavaScript UI based pages. + * This is a WP-admin agnostic reset + */ +/** + * Reset the WP Admin page styles for Gutenberg-like pages. + */ +.flag { + width: 16px; + height: 11px; + display: inline-block; +} + +.components-modal__frame.confirmBox { + height: auto; +} +.components-modal__frame.confirmBox .buttons { + display: block; + text-align: right; +} +.components-modal__frame.confirmBox .buttons button:first-child { + margin-right: 1rem; +} + +.translations p { + margin-top: 1em; +} +.translations td span { + box-sizing: border-box; +} +.translations .pll-column-icon:not(.pll-delete-column) > a { + color: var(--wp-admin-theme-color); + width: 20px; + padding: 2px 0 0; +} +.translations .pll-column-icon > button { + padding: 0; +} +.translations .pll-column-icon.pll-delete-column > .pll-button:not(:disabled) { + color: #cc1818; +} + +body:not(.rtl) .translations .pll-translation-language { + margin-left: 10px; +} + +.rtl .translations .pll-translation-language { + margin-right: 10px; +} + +:not(.pll-delete-column) > .components-button.pll-button, :not(.pll-delete-column) > .components-button.pll-button:focus:enabled:not(.wp-ui-text-highlight), +:not(.pll-delete-column) > .components-button.pll-button, +:not(.pll-delete-column) > .components-button.pll-button:focus:enabled:not(.wp-ui-text-highlight) { + color: #ccc; +} + +:not(.pll-delete-column) > .components-button.pll-button.wp-ui-text-highlight, :not(.pll-delete-column) > .components-button.pll-button.wp-ui-text-highlight:focus:enabled, +:not(.pll-delete-column) > .components-button.pll-button.wp-ui-text-highlight, +:not(.pll-delete-column) > .components-button.pll-button.wp-ui-text-highlight:focus:enabled { + color: var(--wp-admin-theme-color); +} + +.pll-delete-column > .components-button.pll-button:disabled:hover { + color: #1e1e1e; +} + +.pll-before-post-translations-button { + float: right; + margin: 7px 0 0; +} + +.rtl .pll-before-post-translations-button { + float: left; +} + +.pll-button { + height: auto; +} +.pll-button.has-icon.has-text svg { + margin: 0; +} + +.pll-metabox-location .components-button.has-icon { + min-width: auto; +} + +.pll-metabox-error.components-notice { + margin: 0; +} + +.translation-input { + position: relative; +} +.translation-input .components-spinner { + position: absolute; + top: 7px; + right: 16px; + margin: 0; +} +.translation-input input { + width: 100%; +} +.translation-input input[dir=rtl] + .components-spinner { + left: 5px; + right: auto; +} + +.rtl .translation-input .components-spinner { + right: 8px; +} +.rtl .translation-input input[dir=rtl] + .components-spinner { + left: 18px; +} + +.translation-input__suggestions { + max-height: 200px; + transition: all 0.15s ease-in-out; + padding: 4px 0; + width: 302px; + overflow-y: auto; +} + +.translation-input__suggestion { + padding: 4px 8px; + color: #6c7781; + display: block; + font-size: 13px; + cursor: pointer; + background: #fff; + width: 100%; + border: none; + text-align: left; + border: none; + box-shadow: none; +} +.translation-input__suggestion:hover { + background: #e0e0e0; +} +.translation-input__suggestion:focus, .translation-input__suggestion.is-selected { + background: color(theme(primary) shade(15%)); + color: #fff; + outline: none; +} + +.block-editor-block-inspector #select-post-language { + margin: 10px auto 5px auto; +} +.block-editor-block-inspector #select-post-language .pll-translation-icon { + margin-right: 10px; + padding: 2px; + display: inline-block; + vertical-align: middle; +} + +.pll-language-item { + margin: 10px auto 5px auto; +} +.pll-language-item .pll-select-flag { + margin-right: 10px; + margin-left: 3px; + padding: 2px; + display: inline-block; +} +.pll-language-item .pll-language-name { + font-size: 1.1em; +} + +.pll-metabox-info { + font-style: italic; + color: #757575; + font-size: 0.9em; +} + +.pll-defaut-lang-icon { + width: 15px; + height: 15px; +} +.pll-defaut-lang-icon path { + fill: var(--wp-admin-theme-color); +} + +.pll-language-item .pll-defaut-lang-icon { + vertical-align: text-top; +} + +body:not(.rtl) .pll-language-item .pll-defaut-lang-icon { + margin-left: 5px; +} + +.rtl .pll-language-item .pll-defaut-lang-icon { + margin-right: 5px; +} + +.pll-default-lang-column .pll-defaut-lang-icon { + margin-top: 2px; +} diff --git a/wp-content/plugins/polylang-pro/css/build/style.min.css b/wp-content/plugins/polylang-pro/css/build/style.min.css new file mode 100644 index 000000000..5adfef5c3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/style.min.css @@ -0,0 +1 @@ +.flag{width:16px;height:11px;display:inline-block}.components-modal__frame.confirmBox{height:auto}.components-modal__frame.confirmBox .buttons{display:block;text-align:right}.components-modal__frame.confirmBox .buttons button:first-child{margin-right:1rem}.translations p{margin-top:1em}.translations td span{box-sizing:border-box}.translations .pll-column-icon:not(.pll-delete-column)>a{color:var(--wp-admin-theme-color);width:20px;padding:2px 0 0}.translations .pll-column-icon>button{padding:0}.translations .pll-column-icon.pll-delete-column>.pll-button:not(:disabled){color:#cc1818}body:not(.rtl) .translations .pll-translation-language{margin-left:10px}.rtl .translations .pll-translation-language{margin-right:10px}:not(.pll-delete-column)>.components-button.pll-button,:not(.pll-delete-column)>.components-button.pll-button:focus:enabled:not(.wp-ui-text-highlight),:not(.pll-delete-column)>.components-button.pll-button,:not(.pll-delete-column)>.components-button.pll-button:focus:enabled:not(.wp-ui-text-highlight){color:#ccc}:not(.pll-delete-column)>.components-button.pll-button.wp-ui-text-highlight,:not(.pll-delete-column)>.components-button.pll-button.wp-ui-text-highlight:focus:enabled,:not(.pll-delete-column)>.components-button.pll-button.wp-ui-text-highlight,:not(.pll-delete-column)>.components-button.pll-button.wp-ui-text-highlight:focus:enabled{color:var(--wp-admin-theme-color)}.pll-delete-column>.components-button.pll-button:disabled:hover{color:#1e1e1e}.pll-before-post-translations-button{float:right;margin:7px 0 0}.rtl .pll-before-post-translations-button{float:left}.pll-button{height:auto}.pll-button.has-icon.has-text svg{margin:0}.pll-metabox-location .components-button.has-icon{min-width:auto}.pll-metabox-error.components-notice{margin:0}.translation-input{position:relative}.translation-input .components-spinner{position:absolute;top:7px;right:16px;margin:0}.translation-input input{width:100%}.translation-input input[dir=rtl]+.components-spinner{left:5px;right:auto}.rtl .translation-input .components-spinner{right:8px}.rtl .translation-input input[dir=rtl]+.components-spinner{left:18px}.translation-input__suggestions{max-height:200px;transition:all .15s ease-in-out;padding:4px 0;width:302px;overflow-y:auto}.translation-input__suggestion{padding:4px 8px;color:#6c7781;display:block;font-size:13px;cursor:pointer;background:#fff;width:100%;border:none;text-align:left;border:none;box-shadow:none}.translation-input__suggestion:hover{background:#e0e0e0}.translation-input__suggestion:focus,.translation-input__suggestion.is-selected{background:color(theme(primary) shade(15%));color:#fff;outline:none}.block-editor-block-inspector #select-post-language{margin:10px auto 5px auto}.block-editor-block-inspector #select-post-language .pll-translation-icon{margin-right:10px;padding:2px;display:inline-block;vertical-align:middle}.pll-language-item{margin:10px auto 5px auto}.pll-language-item .pll-select-flag{margin-right:10px;margin-left:3px;padding:2px;display:inline-block}.pll-language-item .pll-language-name{font-size:1.1em}.pll-metabox-info{font-style:italic;color:#757575;font-size:.9em}.pll-defaut-lang-icon{width:15px;height:15px}.pll-defaut-lang-icon path{fill:var(--wp-admin-theme-color)}.pll-language-item .pll-defaut-lang-icon{vertical-align:text-top}body:not(.rtl) .pll-language-item .pll-defaut-lang-icon{margin-left:5px}.rtl .pll-language-item .pll-defaut-lang-icon{margin-right:5px}.pll-default-lang-column .pll-defaut-lang-icon{margin-top:2px} diff --git a/wp-content/plugins/polylang-pro/css/build/wizard.css b/wp-content/plugins/polylang-pro/css/build/wizard.css new file mode 100644 index 000000000..b6c6a62a9 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/wizard.css @@ -0,0 +1,951 @@ +@charset "UTF-8"; +body { + margin: 65px auto 24px; + box-shadow: none; + background: #f1f1f1; + padding: 0; + border: 0; /* fix-pro #856 override WP install.css */ +} + +#pll-logo { + border: 0; + margin: 0 0 24px; + padding: 0; + text-align: center; + font-family: sans-serif; + font-size: 64px; + text-transform: uppercase; + color: #000; + line-height: normal; +} +#pll-logo a { + display: flex; + justify-content: center; + color: #000; + text-decoration: none; +} + +#pll-logo img { + max-width: 100%; + margin-right: 16px; +} +.rtl #pll-logo img { + margin-right: 0; + margin-left: 16px; +} + +.pll-wizard-footer { + text-align: center +} + +.pll-wizard .select2-container { + text-align: left; + width: auto +} + +.pll-wizard .hidden { + display: none +} + +.pll-wizard-content { + box-shadow: 0 1px 3px rgba(0, 0, 0, .13); + padding: 2em; + margin: 0 0 20px; + background: #fff; + overflow: hidden; + zoom: 1; + text-align: left; +} +.rtl .pll-wizard-content{ + text-align: right; +} + +.pll-wizard-content h1, +.pll-wizard-content h2, +.pll-wizard-content h3, +.pll-wizard-content table { + margin: 0 0 20px; + border: 0; + padding: 0; + color: #666; + clear: none; + font-weight: 500 +} + +.pll-wizard-content p { + margin: 20px 0; + font-size: 1em; + line-height: 1.75em; + color: #666 +} + +.pll-wizard-content table { + font-size: 1em; + line-height: 1.75em; + color: #666; + width: 100%; + margin-top: 20px; +} +.pll-wizard-content table td span{ + display: inline-block; +} + +.pll-wizard-content table caption { + caption-side: bottom; + font-style: italic; + text-align: right; +} +.rtl .pll-wizard-content table caption { + text-align: left; +} + +.pll-wizard-content table caption .icon-default-lang{ + font-style: normal; +} + +.pll-wizard-content a { + color: #a03f3f; +} + +.pll-wizard-content a:focus, +.pll-wizard-content a:hover, +.pll-wizard-footer-links:hover { + color: #dd5454 +} + +.pll-wizard-content .pll-wizard-next-steps { + overflow: hidden; + margin: 0 0 24px; + padding-bottom: 2px +} + +.pll-wizard-content .pll-wizard-next-steps h2 { + margin-bottom: 12px +} + +.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-first { + float: left; + width: 50%; + box-sizing: border-box +} + +.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-last { + float: right; + width: 50%; + box-sizing: border-box +} + +.pll-wizard-content .pll-wizard-next-steps ul { + padding: 0 2em 0 0; + list-style: none outside; + margin: 0 +} + +.pll-wizard-content .pll-wizard-next-steps ul li a { + display: block; + padding: 0 0 .75em +} + +.pll-wizard-content .pll-wizard-next-steps ul li a::before { + color: #82878c; + font: normal 20px/1 dashicons; + speak: none; + display: inline-block; + padding: 0 10px 0 0; + top: 1px; + position: relative; + text-decoration: none!important; + vertical-align: top +} + +.pll-wizard-steps { + padding: 0 0 24px; + margin: 0; + list-style: none outside; + overflow: hidden; + color: #ccc; + width: 100%; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: inline-flex +} + +.pll-wizard-steps li { + width: 100%; + float: left; + padding: 0 0 .8em; + margin: 0; + text-align: center; + position: relative; + border-bottom: 4px solid #ccc; + line-height: 1.4em +} + +.pll-wizard-steps li a { + color: #a03f3f; + text-decoration: none; + padding: 1.5em; + margin: -1.5em; + position: relative; + z-index: 1 +} + +.pll-wizard-steps li a:focus, +.pll-wizard-steps li a:hover { + color: #dd5454; + text-decoration: underline +} + +.pll-wizard-steps li::before { + content: ""; + border: 4px solid #ccc; + border-radius: 100%; + width: 4px; + height: 4px; + position: absolute; + bottom: 0; + left: 50%; + margin-left: -6px; + margin-bottom: -8px; + background: #fff +} + +.pll-wizard-steps li.active { + border-color: #a03f3f; + color: #a03f3f; + font-weight: 700 +} + +.pll-wizard-steps li.active::before { + border-color: #a03f3f +} + +.pll-wizard-steps li.done { + border-color: #a03f3f; + color: #a03f3f +} + +.pll-wizard-steps li.done::before { + border-color: #a03f3f; + background: #a03f3f +} + +.pll-wizard .pll-wizard-actions { + overflow: hidden; + margin: 20px 0 0; + position: relative +} + +.pll-wizard .pll-wizard-actions .button { + font-size: 16px; + font-weight: 300; + padding: 1em 2em; + line-height: 1em; + margin-right: .5em; + margin-bottom: 2px; + margin-top: 10px; + height: auto; + border-radius: 4px; + box-shadow: none; + min-width: auto; + border-color: #a03f3f; + color: #a03f3f; +} + +.pll-wizard .pll-wizard-content .button { + border-color: #a03f3f; + color: #a03f3f; +} + +.pll-wizard .pll-wizard-content .button-primary, +.pll-wizard .pll-wizard-actions .button-primary { + background-color: #a03f3f; + border-color: #a03f3f; + color: #fff; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #a03f3f; + text-shadow: 0 -1px 1px #a03f3f, 1px 0 1px #a03f3f, 0 1px 1px #a03f3f, -1px 0 1px #a03f3f; + margin: 0; + opacity: 1 +} + +.pll-wizard .pll-wizard-content .button-small .dashicons { + font-size: 15px; + height: auto; + vertical-align: middle; +} + +.pll-wizard .button-primary:active, +.pll-wizard .button-primary:focus, +.pll-wizard input[type="checkbox"]:focus + label.button-primary, +.pll-wizard .button-primary:hover { + background: #dd5454; + border-color: #dd5454; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #dd5454 +} +.pll-wizard .pll-wizard-actions .button-primary[disabled], +.pll-wizard .pll-wizard-actions .button-primary:disabled, +.pll-wizard .pll-wizard-actions .button-primary.disabled { + cursor: wait; + background-color: #bb5454 !important; + border-color: #bb5454 !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #bb5454 !important; + text-shadow: 0 -1px 1px #bb5454, 1px 0 1px #bb5454, 0 1px 1px #bb5454, -1px 0 1px #bb5454 !important; + color: #ffa3a3 !important; +} +.pll-wizard-content p:last-child { + margin-bottom: 0 +} + +.pll-wizard-footer-links { + font-size: .85em; + color: #7b7b7b; + margin: 1.18em auto; + display: inline-block; + text-align: center +} + +.pll-wizard-services { + border: 1px solid #eee; + padding: 0; + margin: 0 0 1em; + list-style: none outside; + border-radius: 4px; + overflow: hidden +} + +.pll-wizard-services p { + margin: 0 0 1em 0; + padding: 0; + font-size: 1em; + line-height: 1.5em +} + +.pll-wizard-service-item { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + padding: 0; + border-bottom: 1px solid #eee; + color: #666; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center +} + +.media-step .pll-wizard-service-item{ + border: 0; +} + +.media-step .pll-wizard-service-item:last-child{ + display: block; +} + +.media-step .pll-wizard-service-item .pll-wizard-service-enable{ + padding-bottom: 0; +} + +.pll-wizard-service-item:last-child { + border-bottom: 0 +} + +.pll-wizard-service-item .pll-wizard-service-name { + -webkit-flex-basis: 0; + flex-basis: 0; + min-width: 160px; + text-align: center; + font-weight: 700; + padding: 2em 0; + -webkit-align-self: stretch; + align-self: stretch; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: baseline; + -webkit-align-items: baseline; + align-items: baseline +} + +.pll-wizard-service-item .pll-wizard-service-name img { + max-width: 75px +} + +.pll-wizard-service-item .pll-wizard-service-description { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + padding: 20px +} + +.pll-wizard-service-item .pll-wizard-service-example { + padding: 0 20px 20px +} + +.pll-wizard-service-item .pll-wizard-service-example p{ + text-align: right; +} +.rtl .pll-wizard-service-item .pll-wizard-service-example p{ + text-align: left; +} + +.pll-wizard-service-item .pll-wizard-service-description p { + margin-bottom: 1em +} + +.pll-wizard-service-item .pll-wizard-service-description p:last-child { + margin-bottom: 0 +} + +.pll-wizard-service-item .pll-wizard-service-description .pll-wizard-service-settings-description { + display: block; + font-style: italic; + color: #999 +} + +.pll-wizard-service-item .pll-wizard-service-enable { + -webkit-flex-basis: 0; + flex-basis: 0; + min-width: 75px; + text-align: center; + cursor: pointer; + padding: 2em 0; + position: relative; + max-height: 1.5em; + -webkit-align-self: flex-start; + align-self: flex-start; + -webkit-box-ordinal-group: 4; + -webkit-order: 3; + order: 3 +} + +.pll-wizard-service-item .pll-wizard-service-toggle { + position: relative +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] { + position:absolute; + opacity: 0; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label { + position: relative; + display: inline-block; + width: 44px; + height: 20px; + border-radius: 10em; + cursor: pointer; + text-indent: -9999px; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:focus + label { + border:1px dashed #777; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::before, +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::after { + content: ''; + position: absolute; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::before { + left: 0; + top: 0; + width: 44px; + height: 20px; + background: #ddd; + border-radius: 10em; + transition: background-color .2s; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::after { + width: 16px; + height: 16px; + transition: all .2s; + border-radius: 50%; + background: #fff; + margin: 2px; + top: 0; + left: 0; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked + label::before { + background:#a03f3f; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked + label::after { + right: 0; + left:auto; +} + +.pll-wizard-service-item .pll-wizard-service-settings { + display: none; + margin-top: .75em; + margin-bottom: 0; + cursor: default +} + +.pll-wizard-service-item .pll-wizard-service-settings.hide { + display: none +} + +.pll-wizard-service-item.checked .pll-wizard-service-settings { + display: inline-block +} + +.pll-wizard-service-item.checked .pll-wizard-service-settings.hide { + display: none +} + +.pll-wizard-service-item.closed { + border-bottom: 0 +} + +.step { + text-align: center +} + +.pll-wizard .button .dashicons{ + vertical-align: middle; +} +.rtl .dashicons-arrow-right-alt2:before { + content: "\f341"; +} +.pll-wizard .pll-wizard-actions .button:active, +.pll-wizard .pll-wizard-actions .button:focus, +.pll-wizard .pll-wizard-actions .button:hover { + box-shadow: none +} + +.pll-wizard-next-steps { + border: 1px solid #eee; + border-radius: 4px; + list-style: none; + padding: 0 +} + +.pll-wizard-next-steps li { + padding: 0 +} + +.pll-wizard-next-steps .pll-wizard-next-step-item { + display: -webkit-box; + display: -webkit-flex; + display: flex; + border-top: 1px solid #eee +} + +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border, +.pll-wizard-next-steps .pll-wizard-next-step-item:first-child { + border-top: 0 +} + +.pll-wizard-next-steps .pll-wizard-next-step-description { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + margin: 1.5em +} + +.pll-wizard-next-steps .pll-wizard-next-step-action { + -webkit-box-flex: 0; + -webkit-flex-grow: 0; + flex-grow: 0; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center +} + +.pll-wizard-next-steps .pll-wizard-next-step-action .button { + margin: 1em 1.5em +} + +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-description, +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-actions, +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-action .button{ + margin-top: 0; +} + + +.pll-wizard-next-steps p.next-step-heading { + margin: 0; + font-size: .95em; + font-weight: 400; + font-variant: all-petite-caps +} + +.pll-wizard-next-steps p.next-step-extra-info { + margin: 0 +} + +.pll-wizard-next-steps h3.next-step-description { + margin: 0; + font-size: 16px; + font-weight: 600; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps { + border-top: 1px solid #eee; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-next-step-description { + margin-bottom: 0 +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions { + margin: 0 0 1.5em 0; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button { + font-size: 15px; + margin: 1em 0 1em 1.5em; +} +.rtl .pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button { + margin: 1em 1.5em 1em 0; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button::last-child { + margin-right: 1.5em; +} + +.pll-wizard-content img{ + max-width: 100%; + margin-right: 0.5em; +} +.rtl .pll-wizard-content img{ + margin-left: 0.5em; +} + +.pll-wizard-content .form-field label{ + margin-bottom: 5px; + display: block; +} + +.pll-wizard-content .form-field select{ + padding: 3px; +} + +.pll-wizard-content .languages-step select, +.pll-wizard-content .untranslated-contents-step select{ + width: 100%; +} + +.languages-step .form-field .button{ + margin-left: 15px; +} +.languages-step .form-field .button > span{ + margin-right: 0.3em; +} +.rtl .languages-step .form-field .button{ + margin-left: 0; + margin-right: 15px; +} +.rtl .languages-step .form-field .button > span{ + margin-left: 0.3em; + margin-right: 0; +} + +.pll-wizard-content .languages-step .select-language-field{ + display: flex; +} + +.pll-wizard-content #languages{ + display: none; +} +.pll-wizard-content #languages tr th:first-child{ + width: 80%; +} +.pll-wizard-content #languages .dashicons{ + color: #a03f3f; +} +.pll-wizard-content #languages img{ + margin-right: 5px; +} +.pll-wizard-content .error{ + color: #a03f3f; + font-weight: bold; +} +.pll-wizard-content #messages .error{ + background: #fccfcf; + padding: 0.5rem; + border: 1px solid #a03f3f; + margin-bottom: 0.5rem; +} + +.pll-wizard-content #slide-toggle{ + position:absolute; + opacity: 0; +} + +.pll-wizard-content #slide-toggle + label{ + position:relative; +} +.pll-wizard-content #slide-toggle + label + span{ + display: block; +} + +.pll-wizard-content #slide-toggle + label .dashicons{ + margin-right: 0.3em; +} +.rtl .pll-wizard-content #slide-toggle + label .dashicons{ + margin-left: 0.3em; + margin-right: 0; +} +.pll-wizard-content #slide-toggle ~ #screenshot > img { + max-height: 500px; + margin-top: 10px; + -webkit-transition: all .5s cubic-bezier(0, 1, 0.5, 1); + transition: all .5s cubic-bezier(0, 1, 0.5, 1); +} +.pll-wizard-content #slide-toggle:checked ~ #screenshot > img { + max-height: 0; +} +.hide { + display: none; +} + +input[type="text"].field-in-error, +input[type="password"].field-in-error, +input[type="checkbox"].field-in-error, +input[type="color"].field-in-error, +input[type="date"].field-in-error, +input[type="datetime"].field-in-error, +input[type="datetime-local"].field-in-error, +input[type="email"].field-in-error, +input[type="month"].field-in-error, +input[type="number"].field-in-error, +input[type="search"].field-in-error, +input[type="radio"].field-in-error, +input[type="tel"].field-in-error, +input[type="text"].field-in-error, +input[type="time"].field-in-error, +input[type="url"].field-in-error, +input[type="week"].field-in-error, +select.field-in-error, +textarea.field-in-error, +span.field-in-error, +.field-in-error{ + border-color: #a03f3f; +} + +input[type="text"].field-in-error:focus, +input[type="password"].field-in-error:focus, +input[type="checkbox"].field-in-error:focus, +input[type="color"].field-in-error:focus, +input[type="date"].field-in-error:focus, +input[type="datetime"].field-in-error:focus, +input[type="datetime-local"].field-in-error:focus, +input[type="email"].field-in-error:focus, +input[type="month"].field-in-error:focus, +input[type="number"].field-in-error:focus, +input[type="search"].field-in-error:focus, +input[type="radio"].field-in-error:focus, +input[type="tel"].field-in-error:focus, +input[type="text"].field-in-error:focus, +input[type="time"].field-in-error:focus, +input[type="url"].field-in-error:focus, +input[type="week"].field-in-error:focus, +select.field-in-error:focus, +textarea.field-in-error:focus, +span.field-in-error:focus, +.field-in-error:focus{ + border: 1px solid #a03f3f; + box-shadow: 0 0 2px rgba(160, 63, 63, 0.8); + outline-color: #a03f3f; + outline-style: auto; + outline-width: thin; +} + +/* override install styles by returning back to forms styles */ +.form-table input.regular-text{ + width: 25em; +} +.form-table input.field-in-error{ + border-color: #a03f3f; +} +#pll-licenses-table td{ + padding: 10px 9px; +} +#pll-licenses-table .license-valid td p{ + min-width: 35em; +} +#pll-licenses-table .pll-deactivate-license{ + margin: 0 0 0 20px; +} +.rtl #pll-licenses-table .pll-deactivate-license{ + margin: 0 10px 0 0; +} +.pll-wizard-content .documentation { + padding: 24px 24px 0; + margin: 0 0 24px; + overflow: hidden; + background: #f5f5f5 +} + +.pll-wizard-content .documentation p { + padding: 0; + margin: 0 0 12px; +} +.documentation-container { + display: -webkit-box; + display: -webkit-flex; + display: flex; + justify-content: flex-end; +} + +.documentation-container .documentation-button-container { + -webkit-box-flex: 0; + -webkit-flex-grow: 0; + flex-grow: 0; +} + +.wc-setup .wc-setup-actions .button.documentation-button { + height: 42px; + padding: 0 1em; + margin: 0; +} +#dialog{ + display: none; +} +.pll-wizard .ui-dialog.ui-widget-content{ + max-height: none; +} +.pll-wizard .ui-dialog-title::before{ + content: "\f534"; + font-family: dashicons; + display: inline-block; + line-height: 1; + font-weight: 400; + font-style: normal; + speak: none; + text-decoration: inherit; + text-transform: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 20px; + height: 20px; + font-size: 20px; + vertical-align: middle; + text-align: center; + margin: 0 5px 5px 0; + transition: color 0.1s ease-in; +} +.rtl.pll-wizard .ui-dialog-title::before{ + margin-right: 0; + margin-left: 5px; +} +.pll-wizard .ui-dialog ul{ + list-style: disc; + padding-left: 20px; +} +.rtl.pll-wizard .ui-dialog ul{ + padding-left: 0; + padding-right: 20px; +} +.pll-wizard li{ + margin-bottom: 0; +} +#translations{ + border-collapse: collapse; +} +#translations tbody:nth-child(odd){ + background-color: #f9f9f9; +} +#translations.striped > tbody > :nth-child(odd) { + background-color: transparent; /* Override common WordPress style */ +} +.pll-wizard-content mark{ + background: transparent none; +} +.pll-wizard-content mark{ + color: #7ad03a; +} +@media screen and (max-width: 782px) { + /* Override WordPress button css rules */ + .languages-step .form-field .button{ + font-size: 13px; + line-height: 26px; + height: 28px; + padding: 0 10px 1px; + vertical-align: top; + } + + #pll-licenses-table .pll-deactivate-license{ + margin: 10px 0 5px; + } +} +@media only screen and (max-width:620px) { + /* Override dialog width rule */ + .ui-dialog{ + width: 100% !important; + } + +} +@media only screen and (max-width:500px) { + #pll-logo a, + .select-language-field{ + flex-direction: column; + } + .select-language-field .action-buttons{ + display: flex; + justify-content: flex-end; + } + .languages-step .form-field .button{ + margin: 5px 0 0; + } +} +@media only screen and (max-width:400px) { + #pll-logo { + font-size: 56px; + } + .pll-wizard-steps { + display: none + } + .pll-wizard-service-item { + -webkit-flex-wrap: wrap; + flex-wrap: wrap + } + .pll-wizard-service-item .pll-wizard-service-enable { + -webkit-box-ordinal-group: 3; + -webkit-order: 2; + order: 2; + padding: 20px 0 0 + } + .pll-wizard-service-item .pll-wizard-service-description { + -webkit-box-ordinal-group: 4; + -webkit-order: 3; + order: 3 + } + .pll-wizard-service-item .pll-wizard-service-name { + padding: 20px 20px 0; + text-align: left; + -webkit-box-pack: justify!important; + -webkit-justify-content: space-between!important; + justify-content: space-between!important + } + .pll-wizard-service-item .pll-wizard-service-name img { + margin: 0 + } + .pll-wizard-next-steps .pll-wizard-next-step-item { + -webkit-flex-wrap: wrap; + flex-wrap: wrap + } + .pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-description { + margin-bottom: 0 + } + .pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-action p { + margin: 0 + } +} +@media only screen and (max-width:360px) { + #pll-logo { + font-size: 48px; + } +} diff --git a/wp-content/plugins/polylang-pro/css/build/wizard.min.css b/wp-content/plugins/polylang-pro/css/build/wizard.min.css new file mode 100644 index 000000000..d5d262375 --- /dev/null +++ b/wp-content/plugins/polylang-pro/css/build/wizard.min.css @@ -0,0 +1 @@ +body{background:#f1f1f1;box-shadow:none;margin:65px auto 24px}#pll-logo,body{border:0;padding:0}#pll-logo{color:#000;font-family:sans-serif;font-size:64px;line-height:normal;margin:0 0 24px;text-align:center;text-transform:uppercase}#pll-logo a{color:#000;display:flex;justify-content:center;text-decoration:none}#pll-logo img{margin-right:16px;max-width:100%}.rtl #pll-logo img{margin-left:16px;margin-right:0}.pll-wizard-footer{text-align:center}.pll-wizard .select2-container{text-align:left;width:auto}.pll-wizard .hidden{display:none}.pll-wizard-content{zoom:1;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.13);margin:0 0 20px;overflow:hidden;padding:2em;text-align:left}.rtl .pll-wizard-content{text-align:right}.pll-wizard-content h1,.pll-wizard-content h2,.pll-wizard-content h3,.pll-wizard-content table{border:0;clear:none;color:#666;font-weight:500;margin:0 0 20px;padding:0}.pll-wizard-content p{color:#666;font-size:1em;line-height:1.75em;margin:20px 0}.pll-wizard-content table{color:#666;font-size:1em;line-height:1.75em;margin-top:20px;width:100%}.pll-wizard-content table td span{display:inline-block}.pll-wizard-content table caption{caption-side:bottom;font-style:italic;text-align:right}.rtl .pll-wizard-content table caption{text-align:left}.pll-wizard-content table caption .icon-default-lang{font-style:normal}.pll-wizard-content a{color:#a03f3f}.pll-wizard-content a:focus,.pll-wizard-content a:hover,.pll-wizard-footer-links:hover{color:#dd5454}.pll-wizard-content .pll-wizard-next-steps{margin:0 0 24px;overflow:hidden;padding-bottom:2px}.pll-wizard-content .pll-wizard-next-steps h2{margin-bottom:12px}.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-first{box-sizing:border-box;float:left;width:50%}.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-last{box-sizing:border-box;float:right;width:50%}.pll-wizard-content .pll-wizard-next-steps ul{list-style:none outside;margin:0;padding:0 2em 0 0}.pll-wizard-content .pll-wizard-next-steps ul li a{display:block;padding:0 0 .75em}.pll-wizard-content .pll-wizard-next-steps ul li a:before{speak:none;color:#82878c;display:inline-block;font:normal 20px/1 dashicons;padding:0 10px 0 0;position:relative;text-decoration:none!important;top:1px;vertical-align:top}.pll-wizard-steps{color:#ccc;display:-webkit-inline-box;display:-webkit-inline-flex;display:inline-flex;list-style:none outside;margin:0;overflow:hidden;padding:0 0 24px;width:100%}.pll-wizard-steps li{border-bottom:4px solid #ccc;float:left;line-height:1.4em;margin:0;padding:0 0 .8em;position:relative;text-align:center;width:100%}.pll-wizard-steps li a{color:#a03f3f;margin:-1.5em;padding:1.5em;position:relative;text-decoration:none;z-index:1}.pll-wizard-steps li a:focus,.pll-wizard-steps li a:hover{color:#dd5454;text-decoration:underline}.pll-wizard-steps li:before{background:#fff;border:4px solid #ccc;border-radius:100%;bottom:0;content:"";height:4px;left:50%;margin-bottom:-8px;margin-left:-6px;position:absolute;width:4px}.pll-wizard-steps li.active{border-color:#a03f3f;color:#a03f3f;font-weight:700}.pll-wizard-steps li.active:before{border-color:#a03f3f}.pll-wizard-steps li.done{border-color:#a03f3f;color:#a03f3f}.pll-wizard-steps li.done:before{background:#a03f3f;border-color:#a03f3f}.pll-wizard .pll-wizard-actions{margin:20px 0 0;overflow:hidden;position:relative}.pll-wizard .pll-wizard-actions .button{border-color:#a03f3f;border-radius:4px;box-shadow:none;color:#a03f3f;font-size:16px;font-weight:300;height:auto;line-height:1em;margin-bottom:2px;margin-right:.5em;margin-top:10px;min-width:auto;padding:1em 2em}.pll-wizard .pll-wizard-content .button{border-color:#a03f3f;color:#a03f3f}.pll-wizard .pll-wizard-actions .button-primary,.pll-wizard .pll-wizard-content .button-primary{background-color:#a03f3f;border-color:#a03f3f;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.25),0 1px 0 #a03f3f;color:#fff;margin:0;opacity:1;text-shadow:0 -1px 1px #a03f3f,1px 0 1px #a03f3f,0 1px 1px #a03f3f,-1px 0 1px #a03f3f}.pll-wizard .pll-wizard-content .button-small .dashicons{font-size:15px;height:auto;vertical-align:middle}.pll-wizard .button-primary:active,.pll-wizard .button-primary:focus,.pll-wizard .button-primary:hover,.pll-wizard input[type=checkbox]:focus+label.button-primary{background:#dd5454;border-color:#dd5454;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.25),0 1px 0 #dd5454}.pll-wizard .pll-wizard-actions .button-primary.disabled,.pll-wizard .pll-wizard-actions .button-primary:disabled,.pll-wizard .pll-wizard-actions .button-primary[disabled]{background-color:#bb5454!important;border-color:#bb5454!important;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.25),0 1px 0 #bb5454!important;color:#ffa3a3!important;cursor:wait;text-shadow:0 -1px 1px #bb5454,1px 0 1px #bb5454,0 1px 1px #bb5454,-1px 0 1px #bb5454!important}.pll-wizard-content p:last-child{margin-bottom:0}.pll-wizard-footer-links{color:#7b7b7b;display:inline-block;font-size:.85em;margin:1.18em auto;text-align:center}.pll-wizard-services{border:1px solid #eee;border-radius:4px;list-style:none outside;margin:0 0 1em;overflow:hidden;padding:0}.pll-wizard-services p{font-size:1em;line-height:1.5em;margin:0 0 1em;padding:0}.pll-wizard-service-item{-webkit-box-pack:justify;-webkit-box-align:center;-webkit-align-items:center;align-items:center;border-bottom:1px solid #eee;color:#666;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-justify-content:space-between;justify-content:space-between;padding:0}.media-step .pll-wizard-service-item{border:0}.media-step .pll-wizard-service-item:last-child{display:block}.media-step .pll-wizard-service-item .pll-wizard-service-enable{padding-bottom:0}.pll-wizard-service-item:last-child{border-bottom:0}.pll-wizard-service-item .pll-wizard-service-name{-webkit-box-align:baseline;-webkit-align-items:baseline;align-items:baseline;-webkit-align-self:stretch;align-self:stretch;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-basis:0;flex-basis:0;font-weight:700;min-width:160px;padding:2em 0;text-align:center}.pll-wizard-service-item .pll-wizard-service-name img{max-width:75px}.pll-wizard-service-item .pll-wizard-service-description{-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;padding:20px}.pll-wizard-service-item .pll-wizard-service-example{padding:0 20px 20px}.pll-wizard-service-item .pll-wizard-service-example p{text-align:right}.rtl .pll-wizard-service-item .pll-wizard-service-example p{text-align:left}.pll-wizard-service-item .pll-wizard-service-description p{margin-bottom:1em}.pll-wizard-service-item .pll-wizard-service-description p:last-child{margin-bottom:0}.pll-wizard-service-item .pll-wizard-service-description .pll-wizard-service-settings-description{color:#999;display:block;font-style:italic}.pll-wizard-service-item .pll-wizard-service-enable{-webkit-box-ordinal-group:4;-webkit-align-self:flex-start;align-self:flex-start;cursor:pointer;-webkit-flex-basis:0;flex-basis:0;max-height:1.5em;min-width:75px;-webkit-order:3;order:3;padding:2em 0;position:relative;text-align:center}.pll-wizard-service-item .pll-wizard-service-toggle{position:relative}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]{opacity:0;position:absolute}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]+label{border-radius:10em;cursor:pointer;display:inline-block;height:20px;position:relative;text-indent:-9999px;width:44px}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:focus+label{border:1px dashed #777}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]+label:after,.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]+label:before{content:"";position:absolute}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]+label:before{background:#ddd;border-radius:10em;height:20px;left:0;top:0;transition:background-color .2s;width:44px}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]+label:after{background:#fff;border-radius:50%;height:16px;left:0;margin:2px;top:0;transition:all .2s;width:16px}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked+label:before{background:#a03f3f}.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked+label:after{left:auto;right:0}.pll-wizard-service-item .pll-wizard-service-settings{cursor:default;display:none;margin-bottom:0;margin-top:.75em}.pll-wizard-service-item .pll-wizard-service-settings.hide{display:none}.pll-wizard-service-item.checked .pll-wizard-service-settings{display:inline-block}.pll-wizard-service-item.checked .pll-wizard-service-settings.hide{display:none}.pll-wizard-service-item.closed{border-bottom:0}.step{text-align:center}.pll-wizard .button .dashicons{vertical-align:middle}.rtl .dashicons-arrow-right-alt2:before{content:"\f341"}.pll-wizard .pll-wizard-actions .button:active,.pll-wizard .pll-wizard-actions .button:focus,.pll-wizard .pll-wizard-actions .button:hover{box-shadow:none}.pll-wizard-next-steps{border:1px solid #eee;border-radius:4px;list-style:none;padding:0}.pll-wizard-next-steps li{padding:0}.pll-wizard-next-steps .pll-wizard-next-step-item{border-top:1px solid #eee;display:-webkit-box;display:-webkit-flex;display:flex}.pll-wizard-next-steps .pll-wizard-next-step-item.no-border,.pll-wizard-next-steps .pll-wizard-next-step-item:first-child{border-top:0}.pll-wizard-next-steps .pll-wizard-next-step-description{-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1;margin:1.5em}.pll-wizard-next-steps .pll-wizard-next-step-action{-webkit-box-flex:0;-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-grow:0;flex-grow:0}.pll-wizard-next-steps .pll-wizard-next-step-action .button{margin:1em 1.5em}.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-actions,.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-action .button,.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-description{margin-top:0}.pll-wizard-next-steps p.next-step-heading{font-size:.95em;font-variant:all-petite-caps;font-weight:400;margin:0}.pll-wizard-next-steps p.next-step-extra-info{margin:0}.pll-wizard-next-steps h3.next-step-description{font-size:16px;font-weight:600;margin:0}.pll-wizard-next-steps .pll-wizard-additional-steps{border-top:1px solid #eee}.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-next-step-description{margin-bottom:0}.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions{margin:0 0 1.5em}.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button{font-size:15px;margin:1em 0 1em 1.5em}.rtl .pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button{margin:1em 1.5em 1em 0}.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button::last-child{margin-right:1.5em}.pll-wizard-content img{margin-right:.5em;max-width:100%}.rtl .pll-wizard-content img{margin-left:.5em}.pll-wizard-content .form-field label{display:block;margin-bottom:5px}.pll-wizard-content .form-field select{padding:3px}.pll-wizard-content .languages-step select,.pll-wizard-content .untranslated-contents-step select{width:100%}.languages-step .form-field .button{margin-left:15px}.languages-step .form-field .button>span{margin-right:.3em}.rtl .languages-step .form-field .button{margin-left:0;margin-right:15px}.rtl .languages-step .form-field .button>span{margin-left:.3em;margin-right:0}.pll-wizard-content .languages-step .select-language-field{display:flex}.pll-wizard-content #languages{display:none}.pll-wizard-content #languages tr th:first-child{width:80%}.pll-wizard-content #languages .dashicons{color:#a03f3f}.pll-wizard-content #languages img{margin-right:5px}.pll-wizard-content .error{color:#a03f3f;font-weight:700}.pll-wizard-content #messages .error{background:#fccfcf;border:1px solid #a03f3f;margin-bottom:.5rem;padding:.5rem}.pll-wizard-content #slide-toggle{opacity:0;position:absolute}.pll-wizard-content #slide-toggle+label{position:relative}.pll-wizard-content #slide-toggle+label+span{display:block}.pll-wizard-content #slide-toggle+label .dashicons{margin-right:.3em}.rtl .pll-wizard-content #slide-toggle+label .dashicons{margin-left:.3em;margin-right:0}.pll-wizard-content #slide-toggle~#screenshot>img{margin-top:10px;max-height:500px;-webkit-transition:all .5s cubic-bezier(0,1,.5,1);transition:all .5s cubic-bezier(0,1,.5,1)}.pll-wizard-content #slide-toggle:checked~#screenshot>img{max-height:0}.hide{display:none}.field-in-error,input[type=checkbox].field-in-error,input[type=color].field-in-error,input[type=date].field-in-error,input[type=datetime-local].field-in-error,input[type=datetime].field-in-error,input[type=email].field-in-error,input[type=month].field-in-error,input[type=number].field-in-error,input[type=password].field-in-error,input[type=radio].field-in-error,input[type=search].field-in-error,input[type=tel].field-in-error,input[type=text].field-in-error,input[type=time].field-in-error,input[type=url].field-in-error,input[type=week].field-in-error,select.field-in-error,span.field-in-error,textarea.field-in-error{border-color:#a03f3f}.field-in-error:focus,input[type=checkbox].field-in-error:focus,input[type=color].field-in-error:focus,input[type=date].field-in-error:focus,input[type=datetime-local].field-in-error:focus,input[type=datetime].field-in-error:focus,input[type=email].field-in-error:focus,input[type=month].field-in-error:focus,input[type=number].field-in-error:focus,input[type=password].field-in-error:focus,input[type=radio].field-in-error:focus,input[type=search].field-in-error:focus,input[type=tel].field-in-error:focus,input[type=text].field-in-error:focus,input[type=time].field-in-error:focus,input[type=url].field-in-error:focus,input[type=week].field-in-error:focus,select.field-in-error:focus,span.field-in-error:focus,textarea.field-in-error:focus{border:1px solid #a03f3f;box-shadow:0 0 2px rgba(160,63,63,.8);outline-color:#a03f3f;outline-style:auto;outline-width:thin}.form-table input.regular-text{width:25em}.form-table input.field-in-error{border-color:#a03f3f}#pll-licenses-table td{padding:10px 9px}#pll-licenses-table .license-valid td p{min-width:35em}#pll-licenses-table .pll-deactivate-license{margin:0 0 0 20px}.rtl #pll-licenses-table .pll-deactivate-license{margin:0 10px 0 0}.pll-wizard-content .documentation{background:#f5f5f5;margin:0 0 24px;overflow:hidden;padding:24px 24px 0}.pll-wizard-content .documentation p{margin:0 0 12px;padding:0}.documentation-container{display:-webkit-box;display:-webkit-flex;display:flex;justify-content:flex-end}.documentation-container .documentation-button-container{-webkit-box-flex:0;-webkit-flex-grow:0;flex-grow:0}.wc-setup .wc-setup-actions .button.documentation-button{height:42px;margin:0;padding:0 1em}#dialog{display:none}.pll-wizard .ui-dialog.ui-widget-content{max-height:none}.pll-wizard .ui-dialog-title:before{speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:"\f534";display:inline-block;font-family:dashicons;font-size:20px;font-style:normal;font-weight:400;height:20px;line-height:1;margin:0 5px 5px 0;text-align:center;text-decoration:inherit;text-rendering:auto;text-transform:none;transition:color .1s ease-in;vertical-align:middle;width:20px}.rtl.pll-wizard .ui-dialog-title:before{margin-left:5px;margin-right:0}.pll-wizard .ui-dialog ul{list-style:disc;padding-left:20px}.rtl.pll-wizard .ui-dialog ul{padding-left:0;padding-right:20px}.pll-wizard li{margin-bottom:0}#translations{border-collapse:collapse}#translations tbody:nth-child(odd){background-color:#f9f9f9}#translations.striped>tbody>:nth-child(odd){background-color:transparent}.pll-wizard-content mark{background:transparent none;color:#7ad03a}@media screen and (max-width:782px){.languages-step .form-field .button{font-size:13px;height:28px;line-height:26px;padding:0 10px 1px;vertical-align:top}#pll-licenses-table .pll-deactivate-license{margin:10px 0 5px}}@media only screen and (max-width:620px){.ui-dialog{width:100%!important}}@media only screen and (max-width:500px){#pll-logo a,.select-language-field{flex-direction:column}.select-language-field .action-buttons{display:flex;justify-content:flex-end}.languages-step .form-field .button{margin:5px 0 0}}@media only screen and (max-width:400px){#pll-logo{font-size:56px}.pll-wizard-steps{display:none}.pll-wizard-service-item{-webkit-flex-wrap:wrap;flex-wrap:wrap}.pll-wizard-service-item .pll-wizard-service-enable{-webkit-box-ordinal-group:3;-webkit-order:2;order:2;padding:20px 0 0}.pll-wizard-service-item .pll-wizard-service-description{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.pll-wizard-service-item .pll-wizard-service-name{-webkit-box-pack:justify!important;-webkit-justify-content:space-between!important;justify-content:space-between!important;padding:20px 20px 0;text-align:left}.pll-wizard-service-item .pll-wizard-service-name img{margin:0}.pll-wizard-next-steps .pll-wizard-next-step-item{-webkit-flex-wrap:wrap;flex-wrap:wrap}.pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-description{margin-bottom:0}.pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-action p{margin:0}}@media only screen and (max-width:360px){#pll-logo{font-size:48px}} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/include/format-util.php b/wp-content/plugins/polylang-pro/include/format-util.php new file mode 100644 index 000000000..751921d10 --- /dev/null +++ b/wp-content/plugins/polylang-pro/include/format-util.php @@ -0,0 +1,95 @@ + + */ + private $patterns = array(); + + /** + * Filters the given list to return only the values whose the key or value matches the given format. + * + * @since 3.6 + * + * @param array|Traversable $list An list with keys or values to match against `$format`. + * @param string $format A format, where `*` means "any characters" (`.*`), unless escaped. + * @param string $mode Optional. Tell if we should filter the keys or values from `$list`. + * Possible values are `'use_keys'` and `'use_values'`. Default is `'use_keys'`. + * @return array + * + * @template TArrayValue + * @phpstan-param ($mode is 'use_keys' ? array|Traversable : array|Traversable) $list + * @phpstan-param 'use_keys'|'values' $mode + * @phpstan-return ($mode is 'use_keys' ? array : array) + */ + public function filter_list( $list, string $format, string $mode = 'use_keys' ): array { + $filter = function ( $key ) use ( $format ) { + return $this->matches( (string) $key, $format ); + }; + + if ( ! is_array( $list ) ) { + $list = iterator_to_array( $list ); + } + + if ( 'use_values' === $mode ) { + return array_filter( $list, $filter ); + } + + return array_filter( $list, $filter, ARRAY_FILTER_USE_KEY ); + } + + /** + * Tells if the given string matches the given format. + * + * @since 3.6 + * + * @param string $key A string to test. + * @param string $format A format, where `*` means "any characters" (`.*`), unless escaped. + * @return bool + */ + public function matches( string $key, string $format ): bool { + if ( strpos( $format, '*' ) === false ) { + return $key === $format; + } + + if ( '*' === $format ) { + return true; + } + + if ( empty( $this->patterns[ $format ] ) ) { + $pattern = addcslashes( $format, '.+?[^]$(){}=!<>|:-#/' ); // Escape regular expression characters (list from `preg_quote()` but `*` and `\` are ignored). + $pattern = preg_replace( + array( + '/\\\(?!\*)/', // Escape `\` characters except if followed by `*`. + '/(?patterns[ $format ] = $pattern; + } else { + $pattern = $this->patterns[ $format ]; + } + + return (bool) preg_match( "/^{$pattern}$/", $key ); + } +} diff --git a/wp-content/plugins/polylang-pro/include/functions.php b/wp-content/plugins/polylang-pro/include/functions.php new file mode 100644 index 000000000..fef93f656 --- /dev/null +++ b/wp-content/plugins/polylang-pro/include/functions.php @@ -0,0 +1,20 @@ +get_method(), array( 'PATCH', 'POST', 'PUT' ), true ) ) { + return true; + } + + return 'GET' === $request->get_method() && 'edit' === $request->get_param( 'context' ); +} diff --git a/wp-content/plugins/polylang-pro/include/pro.php b/wp-content/plugins/polylang-pro/include/pro.php new file mode 100644 index 000000000..f1ff96cb1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/include/pro.php @@ -0,0 +1,103 @@ + POLYLANG_VERSION ); + $args['body']['plugins'] = wp_json_encode( $plugins ); + } + } + return $args; + } + + /** + * Remove Polylang from the list of plugins to update if it is not installed + * + * @since 2.1.1 + * + * @param stdClass $value The value stored in the update_plugins site transient. + * @return stdClass + */ + public function pre_set_site_transient_update_plugins( $value ) { + // We encountered a 3rd party plugin setting the transient before the function get_plugins() is available. + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + $plugins = get_plugins(); + + if ( isset( $value->response ) ) { + if ( empty( $plugins['polylang/polylang.php'] ) ) { + unset( $value->response['polylang/polylang.php'] ); + } elseif ( isset( $value->response['polylang/polylang.php']->new_version ) && $plugins['polylang/polylang.php']['Version'] === $value->response['polylang/polylang.php']->new_version ) { + $value->no_update['polylang/polylang.php'] = $value->response['polylang/polylang.php']; + unset( $value->response['polylang/polylang.php'] ); + } + } + return $value; + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/acf/acf-auto-translate.php b/wp-content/plugins/polylang-pro/integrations/acf/acf-auto-translate.php new file mode 100644 index 000000000..178a449e5 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/acf/acf-auto-translate.php @@ -0,0 +1,491 @@ +fields[ $field['name'] ] = $field; + return $value; + } + + /** + * Store fields when saving a term or when duplicating a term. + * + * @since 2.3 + * + * @param int $term_id Id of the term being saved. + * @return void + */ + public function store_term_fields( $term_id ) { + $this->fields = get_field_objects( 'term_' . $term_id ); + } + + /** + * Copies and possibly translates custom fields when creating a new term translation. + * + * @since 2.2 + * + * @param mixed $value Custom field value of the source term. + * @param string $post_id Expects term_{$term_id} for a term. + * @param array $field Custom field. + * @return mixed + */ + public function load_value( $value, $post_id, $field ) { + if ( 'term_0' === $post_id && isset( $_GET['taxonomy'], $_GET['from_tag'], $_GET['new_lang'] ) && taxonomy_exists( sanitize_key( $_GET['taxonomy'] ) ) && $lang = PLL()->model->get_language( sanitize_key( $_GET['new_lang'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification + + $from_tag = (int) $_GET['from_tag']; // phpcs:ignore WordPress.Security.NonceVerification + $tr_id = 'term_' . $from_tag; // Converts to ACF internal id. + $fields = get_field_objects( $tr_id ); + + if ( ! empty( $fields ) ) { + $keys = array_keys( $fields ); + + /** This filter is documented in /polylang/modules/sync/admin-sync.php */ + $keys = array_unique( apply_filters( 'pll_copy_term_metas', $keys, false, $from_tag, 0, $lang->slug ) ); + + // Second test to load the values of subfields of accepted fields. + if ( in_array( $field['name'], $keys ) || preg_match( '#^(' . implode( '|', $keys ) . ')_(.+)#', $field['name'] ) ) { + $value = acf_get_value( $tr_id, $field ); // Since ACF 5.0.0. + $empty = null; // Parameter 1 is useless in this context. + $value = $this->translate_fields( $empty, $value, $field['name'], $field, $lang->slug ); + + if ( pll_is_translated_post_type( 'acf-field-group' ) ) { + $references = $this->translate_fields_references( $tr_id, $lang->slug ); + $this->translate_references_in_value( $value, $references ); + } + } + } + } + return $value; + } + + /** + * Translates a custom field before it is copied or synchronized. + * + * @since 2.3 + * @since 2.4 Added parameter $to. + * + * @param mixed $value Meta value. + * @param string $key Meta key. + * @param string $lang Language of target. + * @param int $from Id of the object from which we copy informations. + * @param int $to Id of the object to which we copy informations. + * @return mixed + */ + public function translate_meta( $value, $key, $lang, $from, $to = 0 ) { + if ( ! empty( $value ) && $field = isset( $this->fields[ $key ] ) ? $this->fields[ $key ] : $this->get_field_object( $key, $from ) ) { + $create_if_not_exists = false; + + // Check if we should create translations if they don't exist. + // $to is not empty only when translating posts. + if ( ! empty( $to ) && ( $post_type = get_post_type( $to ) ) && pll_is_translated_post_type( $post_type ) ) { + $duplicate_options = get_user_meta( get_current_user_id(), 'pll_duplicate_content', true ); + $active = ! empty( $duplicate_options ) && ! empty( $duplicate_options[ $post_type ] ); + $create_if_not_exists = $active || PLL()->sync_post_model->are_synchronized( $from, $to ); + } + + $value = $this->translate_field( $value, $lang, $field, $create_if_not_exists ); + } + + if ( pll_is_translated_post_type( 'acf-field-group' ) && is_string( $value ) && acf_is_field_key( $value ) ) { + $references = $this->translate_fields_references( $from, $lang ); + + if ( isset( $references[ $value ] ) ) { + $value = $references[ $value ]; + } + } + + return $value; + } + + /** + * Returns an array containing all the field data for a given field name. + * Unlike the original ACF function, it works for clone fields. + * + * @since 2.6.2 + * + * @param string $key The field name or key. + * @param string|int $post_id The post_id of which the value is saved against. + * @return array|false + */ + protected function get_field_object( $key, $post_id ) { + $field = get_field_object( $key, $post_id ); + + if ( $field ) { + return $field; + } + + $post_id = acf_get_valid_post_id( $post_id ); + $field_key = acf_get_reference( $key, $post_id ); // Since ACF 5.6.5. + + if ( ! is_string( $field_key ) ) { + return false; + } + + $field_key = substr( $field_key, -19 ); // Keep the last key in field_xxx_field_yyy for clone fields. + + if ( ! acf_is_field_key( $field_key ) ) { + return false; + } + + $field = acf_get_field( $field_key ); + + if ( empty( $field ) ) { + return false; + } + + $field['value'] = acf_get_value( $post_id, $field ); + $field['value'] = acf_format_value( $field['value'], $post_id, $field ); + return $field; + } + + /** + * Translates a CPT archive link in a page link field. + * + * @since 2.3.6 + * + * @param string $link CPT archive link. + * @param string $lang Language slug. + * @return string Modified link. + */ + protected function translate_cpt_archive_link( $link, $lang ) { + $lang = PLL()->model->get_language( $lang ); + $link = PLL()->links_model->switch_language_in_link( $link, $lang ); + + foreach ( array_keys( PLL()->translate_slugs->slugs_model->get_translatable_slugs() ) as $type ) { + // Unfortunately ACF does not pass the post type, so let's try with all post type archives. + if ( 0 === strpos( $type, 'archive_' ) ) { + $link = PLL()->translate_slugs->slugs_model->switch_translated_slug( $link, $lang, $type ); + } + } + return $link; + } + + /** + * Translates a custom field value. + * + * @since 2.3 + * @since 2.4 Added parameter $create_if_not_exists. + * + * @param mixed $value Custom field value. + * @param string $lang Language slug. + * @param array $field Custom field. + * @param bool $create_if_not_exists Should we create the translation if it does not exist. + * @return mixed + */ + protected function translate_field( $value, $lang, $field, $create_if_not_exists = false ) { + $return = $value; + + switch ( $field['type'] ) { + case 'image': + case 'file': + if ( PLL()->options['media_support'] ) { + $return = 0; + if ( $tr_id = pll_get_post( $value, $lang ) ) { + $return = $tr_id; + } elseif ( $create_if_not_exists ) { + $return = PLL()->posts->create_media_translation( $value, $lang ); + } + } + break; + + case 'gallery': + if ( PLL()->options['media_support'] && is_array( $value ) ) { + $return = array(); + foreach ( $value as $img ) { + if ( $tr_id = pll_get_post( $img, $lang ) ) { + $return[] = $tr_id; + } elseif ( $create_if_not_exists ) { + $return[] = PLL()->posts->create_media_translation( $img, $lang ); + } + } + $return = array_map( 'strval', $return ); // See acf_field_gallery::update_value(). + } + break; + + case 'post_object': + case 'relationship': + if ( is_numeric( $value ) ) { + $return = 0; + if ( $tr_id = pll_get_post( $value, $lang ) ) { + $return = $tr_id; + } + } elseif ( is_array( $value ) ) { + $return = array(); + foreach ( $value as $p ) { + if ( $tr_id = pll_get_post( $p, $lang ) ) { + $return[] = $tr_id; + } + } + $return = array_map( 'strval', $return ); // See the method update_value() for these fields. + } + break; + + case 'page_link': + if ( is_numeric( $value ) ) { + // Unique translated post. + $return = 0; + if ( $tr_id = pll_get_post( $value, $lang ) ) { + $return = $tr_id; + } + } elseif ( is_array( $value ) ) { + // Multiple choice. + $return = array(); + foreach ( $value as $p ) { + if ( is_numeric( $p ) && $tr_id = pll_get_post( $p, $lang ) ) { + $return[] = $tr_id; + } else { + $return[] = $this->translate_cpt_archive_link( $p, $lang ); // Archive. + } + } + $return = array_map( 'strval', $return ); // See acf_field_page_link::update_value(). + } else { + $return = $this->translate_cpt_archive_link( $value, $lang ); // Archive. + } + break; + + case 'taxonomy': + if ( pll_is_translated_taxonomy( $field['taxonomy'] ) ) { + if ( is_numeric( $value ) ) { + $return = 0; + if ( $tr_id = pll_get_term( $value, $lang ) ) { + $return = $tr_id; + } + } elseif ( is_array( $value ) ) { + $return = array(); + foreach ( $value as $t ) { + if ( $tr_id = pll_get_term( $t, $lang ) ) { + $return[] = $tr_id; + } + } + } + } + break; + } + + return $return; + } + + /** + * Translates repeater and flexible content sub fields (for recursive translation of this fields). + * + * @since 2.2 + * + * @param array $r Reference to a flat list of translated custom fields. + * @param mixed $value Custom field value. + * @param string $name Custom field name. + * @param array $field ACF field or subfield. + * @param string $lang Language slug. + * @return array Hierarchical list of custom fields values. + */ + protected function translate_sub_fields( &$r, $value, $name, $field, $lang ) { + $return = array(); + + foreach ( $value as $row => $sub_fields ) { + $sub = array(); + foreach ( $sub_fields as $id => $sub_value ) { + $field = acf_get_field( substr( $id, -19 ) ); // Keep the last key in field_xxx_field_yyy for clone fields. + if ( $field ) { + $sub[ $id ] = $this->translate_fields( $r, $sub_value, $name . '_' . $row . '_' . $field['name'], $field, $lang ); + } else { + $sub[ $id ] = $sub_value; + } + } + $return[] = $sub; + } + + return $return; + } + + /** + * Recursively translates custom group, repeater and flexible content fields. + * + * @since 2.0 + * + * @param array $r Reference to a flat list of translated custom fields. + * @param mixed $value Custom field value. + * @param string $name Custom field name. + * @param array $field ACF field or subfield. + * @param string $lang Language slug. + * @return array Hierarchical list of custom fields values. + */ + protected function translate_fields( &$r, $value, $name, $field, $lang ) { + if ( empty( $value ) ) { + return; + } + + $r[ '_' . $name ] = $field['key']; + + $return = array(); + + switch ( $field['type'] ) { + case 'group': + $sub = array(); + foreach ( $value as $id => $sub_value ) { + if ( $field = acf_get_field( $id ) ) { + $sub[ $id ] = $this->translate_fields( $r, $sub_value, $name . '_' . $field['name'], $field, $lang ); + } else { + $sub[ $id ] = $sub_value; + } + } + $return[] = $sub; + break; + + case 'repeater': + case 'flexible_content': + $return = $this->translate_sub_fields( $r, $value, $name, $field, $lang ); + break; + + default: + $return = $this->translate_field( $value, $lang, $field ); + break; + } + + return empty( $return ) ? $value : $return; + } + + /** + * Translated field groups: + * Recursively translates the references in value for repeaters and flexible content. + * + * @since 2.2 + * + * @param array $value Reference to a custom field value. + * @param array $references List of custom fields references with source as key and translation as value. + * @return void + */ + protected function translate_references_in_value( &$value, $references ) { + if ( is_array( $value ) ) { + foreach ( $value as $row => $sub_fields ) { + if ( is_array( $sub_fields ) ) { + foreach ( $sub_fields as $id => $sub_value ) { + if ( is_array( $sub_value ) ) { + $this->translate_references_in_value( $sub_value, $references ); + } + if ( isset( $references[ $id ] ) ) { + $value[ $row ][ $references[ $id ] ] = $sub_value; + unset( $value[ $row ][ $id ] ); + } + } + } + } + } + } + + /** + * Translated field groups: + * Searches for fields having the same name in translated posts. + * + * @since 2.2 + * + * @param int|string $from Source post id. + * @param string $lang Target language code. + * @return array + */ + protected function translate_fields_references( $from, $lang ) { + $keys = array(); + $fields = get_field_objects( $from ); + + if ( is_array( $fields ) ) { + foreach ( $fields as $field ) { + if ( $tr_group = pll_get_post( $field['parent'], $lang ) ) { + $tr_fields = acf_get_fields( $tr_group ); + $this->translate_field_references( $keys, $field, $tr_fields ); + } + } + } + + return $keys; + } + + /** + * Translated field groups: + * Loops through sub fields in the recursive search for fields + * having the same name among translated fields groups. + * + * @since 2.2 + * + * @param array $keys Reference to an array mapping the fields keys of the translated post to the field keys of the currentpost. + * @param array $fields ACF Custom fields of the current post. + * @param array $tr_fields ACF Custom fields of a translation. + * @return void + */ + protected function translate_sub_fields_references( &$keys, $fields, $tr_fields ) { + foreach ( $fields as $field ) { + $this->translate_field_references( $keys, $field, $tr_fields ); + } + } + + /** + * Translated field groups: + * Recursively searches for fields having the same name among translated fields groups. + * + * @since 2.2 + * + * @param array $keys Reference to an array mapping the fields keys of the translated post to the field keys of the currentpost. + * @param array $field ACF Custom fields of the current post. + * @param array $tr_fields ACF Custom fields of a translation. + * @return void + */ + protected function translate_field_references( &$keys, $field, $tr_fields ) { + $k = array_search( $field['name'], wp_list_pluck( $tr_fields, 'name' ) ); + if ( false !== $k ) { + $keys[ $field['key'] ] = $tr_fields[ $k ]['key']; + if ( ! empty( $field['sub_fields'] ) ) { + $this->translate_sub_fields_references( $keys, $field['sub_fields'], $tr_fields[ $k ]['sub_fields'] ); + } + + if ( ! empty( $field['layouts'] ) ) { + foreach ( $field['layouts'] as $row => $layout ) { + if ( ! empty( $layout['sub_fields'] ) ) { + $this->translate_sub_fields_references( $keys, $layout['sub_fields'], $tr_fields[ $k ]['layouts'][ $row ]['sub_fields'] ); + } + } + } + } + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/acf/acf-sync-metas.php b/wp-content/plugins/polylang-pro/integrations/acf/acf-sync-metas.php new file mode 100644 index 000000000..235f2c6fd --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/acf/acf-sync-metas.php @@ -0,0 +1,305 @@ +category ) { + add_action( "acf/render_field_settings/type={$type->name}", array( $this, 'render_field_settings' ) ); + } + } + + // Get the metas to copy or synchronize. + add_filter( 'pll_copy_post_metas', array( $this, 'copy_metas' ), 1, 4 ); + add_filter( 'pll_copy_term_metas', array( $this, 'copy_term_metas' ), 1, 4 ); + + // Get the private metas to synchronize. Very late to wait for the complete list. + add_filter( 'pll_copy_post_metas', array( $this, 'copy_private_metas' ), 999, 3 ); + add_filter( 'pll_copy_term_metas', array( $this, 'copy_private_metas' ), 998, 3 ); + + // It handles the translations of meta fields for import export. + add_filter( 'pll_post_metas_to_export', array( $this, 'get_fields_to_export' ), 10, 2 ); + add_filter( 'pll_term_metas_to_export', array( $this, 'get_fields_to_export' ), 10, 2 ); + } + + /** + * Renders the translations setting. + * + * @since 2.7 + * + * @param array $field ACF field. + * @param array $choices An array of choices for the select (value as key and label as value). + * @param string $default Default value for the select. + * @return void + */ + protected function render_field_setting( $field, $choices, $default ) { + acf_render_field_setting( // Since ACF 5.7.10. + $field, + array( + 'label' => __( 'Translations', 'polylang-pro' ), + 'instructions' => '', + 'name' => 'translations', + 'type' => 'select', + 'choices' => $choices, + 'default_value' => $default, + ), + false // The setting is depending on the type of field. + ); + } + + /** + * Renders a default translations setting (no translate option). + * + * @since 2.7 + * @since 3.3.1 Renamed and merged two methods. + * + * @param array $field ACF field. + * @return void + */ + public function render_field_settings( $field ) { + $choices = array( + 'ignore' => __( 'Ignore', 'polylang-pro' ), + 'copy_once' => __( 'Copy once', 'polylang-pro' ), + 'sync' => __( 'Synchronize', 'polylang-pro' ), + ); + $default = in_array( 'post_meta', PLL()->options['sync'] ) ? 'sync' : 'copy_once'; + + switch ( $field['type'] ) { + case 'text': + case 'textarea': + case 'wysiwyg': + if ( empty( $field['ID'] ) ) { // Workaround a bug in ACF which doesn't save options added after a field has been created. + $default = 'translate'; + } + // Intentional fall-through to add the translate option below. + + case 'oembed': + case 'url': + case 'email': + // Add translate option at the 3rd position. + $choices = array_merge( + array_slice( $choices, 0, 2 ), + array( 'translate' => __( 'Translate', 'polylang-pro' ) ), + array_slice( $choices, -1 ) + ); + break; + } + $this->render_field_setting( $field, $choices, $default ); + } + + /** + * Recursively constructs the map of translations properties for all metas. + * + * @since 2.7 + * @since 3.2 Added the $sync_layout parameter. + * + * @param array $translations Reference to an array of meta keys. + * @param string $name Meta key. + * @param array $value ACF field value. + * @param array $field ACF field. + * @param bool $sync_layout Whether the layout field must be synchronized, passsed by reference. + * @return void + */ + protected function get_translations( &$translations, $name, $value, $field, &$sync_layout = false ) { + switch ( $field['type'] ) { + case 'group': + foreach ( $field['sub_fields'] as $sub_field ) { + if ( isset( $value[ $sub_field['name'] ] ) ) { + $this->get_translations( $translations, "{$name}_{$sub_field['name']}", $value[ $sub_field['name'] ], $sub_field, $sync_layout ); + } + } + break; + + case 'repeater': + if ( is_array( $value ) ) { + foreach ( array_keys( $value ) as $row ) { + foreach ( $field['sub_fields'] as $sub_field ) { + if ( is_array( $value[ $row ] ) && isset( $value[ $row ][ $sub_field['name'] ] ) ) { + $this->get_translations( $translations, "{$name}_{$row}_{$sub_field['name']}", $value[ $row ][ $sub_field['name'] ], $sub_field, $sync_layout ); + } + } + } + } + + // A child field is synchronized or translatable. Let's synchronize the repeater. + if ( $sync_layout ) { + $translations['sync'][] = $name; + } + break; + + case 'flexible_content': + if ( is_array( $value ) ) { + foreach ( array_keys( $value ) as $row ) { + foreach ( $field['layouts'] as $layout ) { + foreach ( $layout['sub_fields'] as $sub_field ) { + if ( is_array( $value[ $row ] ) && isset( $value[ $row ][ $sub_field['name'] ] ) ) { + $this->get_translations( $translations, "{$name}_{$row}_{$sub_field['name']}", $value[ $row ][ $sub_field['name'] ], $sub_field, $sync_layout ); + } + } + } + } + } + + // A child field is synchronized or translatable. Let's synchronize the flexible. + if ( $sync_layout ) { + $translations['sync'][] = $name; + } + break; + + default: + if ( isset( $field['translations'] ) ) { + $translations[ $field['translations'] ][] = $name; + + // If a field is synchronize or translatable, then all its parent layout fields must be synchronized. + if ( 'sync' === $field['translations'] || 'translate' === $field['translations'] ) { + $sync_layout = true; + } + } + break; + } + } + + /** + * Gets the meta fields to translate. + * + * @since 3.3 + * + * @param array $keys Array of metas keys to translate. + * @param int $from ID of the source object. + * @return array Array of updated metas keys to translate. + */ + public function get_fields_to_export( $keys, $from ) { + $translations = $this->get_translation_options( $from ); + + $fields_to_export = array(); + if ( ! empty( $translations['translate'] ) ) { + $fields_to_export = array_fill_keys( array_values( $translations['translate'] ), 1 ); + } + + return array_merge( $keys, $fields_to_export ); + } + + /** + * Gets the translation options. + * + * @since 2.7 + * @since 3.3 The function has been split from copy_metas(). + * + * @param string|int $from Id of the object from which we copy information. + * @param string|int $to Id of the object to which we copy information. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @return array[] A list of arrays 'ignore', 'copy_once', 'translate' and 'sync' with their associated metas. + * + * @phpstan-return array{'ignore': array, 'copy_once': array, 'translate': array, 'sync': array} + */ + protected function get_translation_options( $from, $to = 0, $sync = false ) { + // Init the translations array. + $translations = array_fill_keys( + array( + 'ignore', + 'copy_once', + 'translate', + 'sync', + ), + array() + ); + + $objects = get_field_objects( $from ); + + if ( $sync && empty( $objects ) ) { + // When saving a translation for the first, we don't have any field objects, so let's try to use fields of the target instead. + $objects = get_field_objects( $to ); + } + + // Get the metas sorted by their translations setting. + if ( is_array( $objects ) ) { + foreach ( $objects as $name => $object ) { + if ( ! empty( $object['value'] ) ) { + $this->get_translations( $translations, $name, $object['value'], $object ); + } + } + } + + return $translations; + } + + /** + * Selects the metas to be copied or synchronized. + * + * @since 2.7 + * + * @param string[] $metas List of custom fields names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param string|int $from Id of the object from which we copy information. + * @param string|int $to Id of the object to which we copy information. + * @return string[] + */ + public function copy_metas( $metas, $sync, $from, $to ) { + $translations = $this->get_translation_options( $from, $to, $sync ); + + if ( $sync ) { + $metas = array_diff( $metas, $translations['ignore'], $translations['copy_once'], $translations['translate'] ); + $metas = array_merge( $metas, $translations['sync'] ); + } else { + $metas = array_diff( $metas, $translations['ignore'] ); + $metas = array_merge( $metas, $translations['sync'], $translations['copy_once'], $translations['translate'] ); + } + + return $metas; + } + + /** + * Selects the term metas to be copied or synchronized. + * + * @since 2.7.4 + * + * @param string[] $metas List of custom fields names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the object from which we copy informations. + * @param int $to Id of the object to which we copy informations. + * @return string[] + */ + public function copy_term_metas( $metas, $sync, $from, $to ) { + return $this->copy_metas( $metas, $sync, 'term_' . $from, 'term_' . $to ); + } + + /** + * Selects the private ACF metas to be synchronized. + * + * @since 2.7 + * + * @param string[] $metas List of custom fields names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the object from which we copy informations. + * @return string[] + */ + public function copy_private_metas( $metas, $sync, $from ) { + $meta_type = substr( current_filter(), 9, 4 ); + + foreach ( get_metadata( $meta_type, $from ) as $key => $value ) { + $value = reset( $value ); + if ( is_string( $value ) && acf_is_field_key( $value ) ) { + $metas[] = $key; // Private keys added to non private. + } + } + + return $metas; + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/acf/acf.php b/wp-content/plugins/polylang-pro/integrations/acf/acf.php new file mode 100644 index 000000000..2a6bb31f3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/acf/acf.php @@ -0,0 +1,321 @@ +model->is_translated_post_type( 'acf-field-group' ) ) { + // Use a non-default priority to avoid changes in cache key due to undesired hooks order change. + add_filter( 'acf/get_cache_key', array( $this, 'filter_cache_key' ), 50, 2 ); + add_filter( 'acf/rest/get_fields', array( $this, 'fix_rest_get_fields' ), 10, 2 ); + } + + add_filter( 'acf/get_taxonomies', array( $this, 'get_taxonomies' ) ); + + add_action( 'add_meta_boxes_acf-field-group', array( $this, 'remove_sync' ) ); + add_action( 'add_meta_boxes_acf-field-group', array( $this, 'duplicate_field_group' ) ); + add_filter( 'acf/duplicate_field/type=clone', array( $this, 'duplicate_clone_field' ) ); + + add_filter( 'acf/location/rule_match/page_type', array( $this, 'rule_match_page_type' ), 20, 3 ); // After ACF. + + add_filter( 'pll_get_post_types', array( $this, 'get_post_types' ), 10, 2 ); + add_filter( 'pll_bulk_translate_post_types', array( $this, 'bulk_translate_post_types' ) ); + + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); + + add_action( 'wp_ajax_acf_post_lang_choice', array( $this, 'acf_post_lang_choice' ) ); + + $this->sync_metas = new PLL_ACF_Sync_Metas(); + $this->auto_translate = new PLL_ACF_Auto_Translate(); + } + + /** + * Adds the current language in the cache key to make sure that filtered queries + * are not cached for only one language. + * + * @since 3.2 + * + * @param string $key Cache key. + * @param string $original Original unfiltered cache key. + * @return string + */ + public function filter_cache_key( $key, $original ) { + $lang = pll_current_language(); + if ( $lang && 'acf_get_field_group_posts' === $original ) { + $key .= ':lang=' . $lang; + } + return $key; + } + + + /** + * Works around a bug in ACF_Rest_Api::get_fields() which unlike get_field_objects() + * returns fields which may not belong to the requested object ID. + * + * @since 3.3.1 + * + * @param array $fields An array of ACF fields. + * @param array $resource Contextual information about the current resource request. + * @return array + */ + public function fix_rest_get_fields( $fields, $resource ) { + $field_object_ids = wp_list_pluck( get_field_objects( $resource['id'] ), 'ID' ); + + $fields = array_filter( + $fields, + function ( $field ) use ( $field_object_ids ) { + return in_array( $field['ID'], $field_object_ids ); + } + ); + return $fields; + } + + /** + * Prevents ACF to display our private taxonomies. + * + * @since 2.8 + * + * @param string[] $taxonomies Taxonomy names. + * @return string[] + */ + public function get_taxonomies( $taxonomies ) { + return array_diff( $taxonomies, get_taxonomies( array( '_pll' => true ) ) ); + } + + /** + * Deactivates the synchronization for ACF field groups. + * + * @since 2.1 + * + * @return void + */ + public function remove_sync() { + foreach ( pll_languages_list() as $lang ) { + remove_action( "pll_before_post_translation_{$lang}", array( PLL()->sync_post->buttons[ $lang ], 'add_icon' ) ); + } + } + + /** + * Duplicates the field group if content duplication is activated. + * + * @since 2.3 + * + * @param WP_Post $post Current post object. + * @return void + */ + public function duplicate_field_group( $post ) { + if ( PLL()->model->is_translated_post_type( 'acf-field-group' ) && 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) { + // Capability check already done in post-new.php. + check_admin_referer( 'new-post-translation' ); + + $duplicate_options = get_user_meta( get_current_user_id(), 'pll_duplicate_content', true ); + + $active = ! empty( $duplicate_options ) && ! empty( $duplicate_options['acf-field-group'] ); + + if ( $active ) { + acf_duplicate_field_group( (int) $_GET['from_post'], $post->ID ); + } + } + } + + /** + * Recursively searches a field by its name in an array of fields. + * + * @since 2.3 + * + * @param string $name Field name. + * @param array $fields An array of fields. + * @return string Field key, empty string if not found. + */ + protected function search_field_by_name( $name, $fields ) { + foreach ( $fields as $field ) { + if ( $name === $field['name'] ) { + return $field['key']; + } elseif ( ! empty( $field['sub_fields'] ) && $key = $this->search_field_by_name( $name, $field['sub_fields'] ) ) { + return $key; + } elseif ( ! empty( $field['layouts'] ) ) { + foreach ( $field['layouts'] as $layout ) { + if ( ! empty( $layout['sub_fields'] ) && $key = $this->search_field_by_name( $name, $layout['sub_fields'] ) ) { + return $key; + } + } + } + } + return ''; + } + + /** + * Translates a clone field when creating a new field group translation. + * + * @since 2.3 + * + * @param array $field ACF Custom field. + * @return array + */ + public function duplicate_clone_field( $field ) { + if ( PLL()->model->is_translated_post_type( 'acf-field-group' ) && ! empty( $field['clone'] ) && 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) { + check_admin_referer( 'new-post-translation' ); + + foreach ( $field['clone'] as $k => $selector ) { + if ( acf_is_field_group_key( $selector ) ) { + // Can't use acf_get_field_group() as it is filtered by language. + $posts = get_posts( + array( + 'post_type' => 'acf-field-group', + 'post_status' => array( 'publish', 'acf-disabled', 'trash' ), + 'name' => $selector, + 'update_post_meta_cache' => false, + 'lang' => '', + ) + ); + + if ( ! empty( $posts ) && $tr_id = pll_get_post( $posts[0]->ID, sanitize_key( $_GET['new_lang'] ) ) ) { + $tr_group = acf_get_field_group( $tr_id ); + + $field['clone'][ $k ] = $tr_group['key']; + } + } elseif ( acf_is_field_key( $selector ) ) { + $_field = acf_get_field( $selector ); + $ancestors = get_post_ancestors( $_field['ID'] ); + $group_id = end( $ancestors ); + + if ( $tr_id = pll_get_post( $group_id, sanitize_key( $_GET['new_lang'] ) ) ) { + $tr_fields = acf_get_fields( $tr_id ); + + if ( $key = $this->search_field_by_name( $_field['name'], $tr_fields ) ) { + $field['clone'][ $k ] = $key; + } + } + } + } + } + return $field; + } + + /** + * Allows page on front and page for posts translations to match the corresponding page type. + * + * @since 2.0 + * + * @param bool $match Whether a location matches the rule. + * @param array $rule Field group location rule. + * @param array $screen Information on the current location. + * @return bool + */ + public function rule_match_page_type( $match, $rule, $screen ) { + if ( ! empty( $screen['post_id'] ) ) { + $post = get_post( $screen['post_id'] ); + + if ( 'front_page' === $rule['value'] && $front_page = (int) get_option( 'page_on_front' ) ) { + $translations = pll_get_post_translations( $front_page ); + + if ( '==' === $rule['operator'] ) { + $match = in_array( $post->ID, $translations ); + } elseif ( '!=' === $rule['operator'] ) { + $match = ! in_array( $post->ID, $translations ); + } + } elseif ( 'posts_page' === $rule['value'] && $posts_page = (int) get_option( 'page_for_posts' ) ) { + $translations = pll_get_post_translations( $posts_page ); + + if ( '==' === $rule['operator'] ) { + $match = in_array( $post->ID, $translations ); + } elseif ( '!=' === $rule['operator'] ) { + $match = ! in_array( $post->ID, $translations ); + } + } + } + + return $match; + } + + /** + * Add the Field Groups post type to the list of translatable post types. + * + * @since 2.0 + * + * @param string[] $post_types List of post types. + * @param bool $is_settings True when displaying the list of custom post types in Polylang settings. + * @return string[] + */ + public function get_post_types( $post_types, $is_settings ) { + if ( $is_settings ) { + $post_types['acf-field-group'] = 'acf-field-group'; + } + return $post_types; + } + + /** + * Remove the Field Groups post type from the bulk translate action. + * + * @since 2.8.4 + * + * @param string[] $types List of post type names for which Polylang manages the bulk translate. + * @return string[] + */ + public function bulk_translate_post_types( $types ) { + return array_diff( $types, array( 'acf-field-group' ) ); + } + + /** + * Enqueues javascript to react to a language change in the post metabox. + * + * @since 2.0 + * + * @return void + */ + public function admin_enqueue_scripts() { + global $pagenow, $typenow; + + if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ) ) && ! in_array( $typenow, array( 'acf-field-group', 'attachment' ) ) && PLL()->model->is_translated_post_type( $typenow ) ) { + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + wp_enqueue_script( 'pll_acf', plugins_url( '/js/build/acf' . $suffix . '.js', POLYLANG_ROOT_FILE ), array( 'acf-input' ), POLYLANG_VERSION ); + } + } + + /** + * Ajax response for changing the language in the post metabox + * + * @since 2.0 + * + * @return void + */ + public function acf_post_lang_choice() { + check_ajax_referer( 'pll_language', '_pll_nonce' ); + + if ( isset( $_POST['fields'] ) ) { + $x = new WP_Ajax_Response(); + foreach ( array_map( 'sanitize_key', $_POST['fields'] ) as $field ) { + ob_start(); + acf_render_field_wrap( acf_get_field( $field ), 'div', 'label' ); + $x->Add( array( 'what' => str_replace( '_', '-', $field ), 'data' => ob_get_contents() ) ); + ob_end_clean(); + } + + $x->send(); + } + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/acf/js/acf.js b/wp-content/plugins/polylang-pro/integrations/acf/js/acf.js new file mode 100644 index 000000000..33c6ca44a --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/acf/js/acf.js @@ -0,0 +1,57 @@ +/** + * @package Polylang-Pro + */ + +jQuery( + function ( $ ) { + /** + * Ajax for changing the post's language in the languages metabox. + */ + $( '.post_lang_choice' ).on( + 'change', + function () { + + // Reloads the relationship fields + if ( $( ".acf-field-relationship" ).length ) { + acf.doAction( 'ready' ); + } + + var fields = new Array(); + + $( '.acf-field-taxonomy' ).each( + function () { + var field = $( this ).attr( 'data-key' ); + fields.push( field ); + } + ); + + if ( 0 != fields.length ) { + var data = { + action: 'acf_post_lang_choice', + lang: $( this ).val(), + fields: fields, + _pll_nonce: $( '#_pll_nonce' ).val() + } + + $.post( + ajaxurl, + data, + function (response) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function () { + $el = $( '.acf-' + this.what ) + // Data come from ACF field and server side. + $el.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + acf.do_action( 'ready_field/type=' + $el.data( 'type' ), $el ); + } + ); + } + ); + } + } + ); + } +); diff --git a/wp-content/plugins/polylang-pro/integrations/acf/load.php b/wp-content/plugins/polylang-pro/integrations/acf/load.php new file mode 100644 index 000000000..42f2befe2 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/acf/load.php @@ -0,0 +1,29 @@ += 5.7.11. + return; + } + + if ( ! did_action( 'pll_init' ) || ! PLL()->model->has_languages() ) { + // Run only if Polylang (and its API) is loaded, and if there is at least one language. + return; + } + + add_action( 'init', array( PLL_Integrations::instance()->acf = new PLL_ACF(), 'init' ) ); + } +); diff --git a/wp-content/plugins/polylang-pro/integrations/admin-columns/cpac.php b/wp-content/plugins/polylang-pro/integrations/admin-columns/cpac.php new file mode 100644 index 000000000..a8038987f --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/admin-columns/cpac.php @@ -0,0 +1,72 @@ +model->get_translated_post_types() as $type ) { + if ( isset( $_REQUEST['list_screen'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + $filter = 'manage_' . ( 'attachment' === $type ? 'upload' : 'edit-' . $type ) . '_columns'; + add_filter( $filter, array( $this, 'remove_filter_lang' ), 90 ); // Before Polylang. + } + + $filter = 'option_cpac_options_' . ( 'attachment' === $type ? 'wp-media' : $type ) . '__default'; + add_filter( $filter, array( $this, 'filter_default_columns' ) ); + } + } + + /** + * Deactivates the admin language filter on Admin Columns settings page. + * + * @since 2.4 + * + * @param array $columns List of table columns. + * @return array + */ + public function remove_filter_lang( $columns ) { + PLL()->filters_columns->filter_lang = ''; + return $columns; + } + + /** + * Fixes the Polylang columns in default columns. + * + * @since 2.4 + * + * @param array $columns List of table columns. + * @return array + */ + public function filter_default_columns( $columns ) { + $screen = get_current_screen(); + + if ( isset( $screen->base ) ) { + $is_post_type = 'edit' === $screen->base && has_filter( 'manage_edit-' . $screen->post_type . '_columns', array( PLL()->filters_columns, 'add_post_column' ) ); + $is_media = 'upload' === $screen->base && has_filter( 'manage_upload_columns', array( PLL()->filters_columns, 'add_post_column' ) ); + + if ( $is_post_type || $is_media ) { + foreach ( pll_languages_list() as $lang ) { + unset( $columns[ 'language_' . $lang ] ); + } + + $columns = PLL()->filters_columns->add_post_column( $columns ); + } + } + + return $columns; + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/admin-columns/load.php b/wp-content/plugins/polylang-pro/integrations/admin-columns/load.php new file mode 100644 index 000000000..89b7586b6 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/admin-columns/load.php @@ -0,0 +1,17 @@ +cpac = new PLL_CPAC(), 'init' ) ); + } + } +); diff --git a/wp-content/plugins/polylang-pro/integrations/beaver-builder/flbuilder.php b/wp-content/plugins/polylang-pro/integrations/beaver-builder/flbuilder.php new file mode 100644 index 000000000..212ec6b04 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/beaver-builder/flbuilder.php @@ -0,0 +1,41 @@ +flbuilder = new PLL_FLBuilder(); + } + } +); diff --git a/wp-content/plugins/polylang-pro/integrations/content-blocks/content-blocks.php b/wp-content/plugins/polylang-pro/integrations/content-blocks/content-blocks.php new file mode 100644 index 000000000..b34c113ce --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/content-blocks/content-blocks.php @@ -0,0 +1,40 @@ +content_blocks = new PLL_Content_Blocks(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/integrations/cptui/cptui.php b/wp-content/plugins/polylang-pro/integrations/cptui/cptui.php new file mode 100644 index 000000000..5d020d281 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/cptui/cptui.php @@ -0,0 +1,98 @@ + array( + 'label' => 1, + 'singular_label' => 1, + 'description' => 1, + 'labels' => array( + '*' => 1, + ), + ), + ); + + new PLL_Translate_Option( 'cptui_post_types', $keys, array( 'context' => 'CPT UI' ) ); + new PLL_Translate_Option( 'cptui_taxonomies', $keys, array( 'context' => 'CPT UI' ) ); + + if ( PLL() instanceof PLL_Frontend && ! PLL()->options['force_lang'] ) { + // Special case when the language is set from the content as CPT and taxonomies are registered before the language is defined. + add_action( 'pll_language_defined', array( $this, 'pll_language_defined' ) ); + } + + + // Add CPT UI post types and taxonomies to Polylang settings. + add_filter( 'pll_get_post_types', array( $this, 'pll_get_types' ), 10, 2 ); + add_filter( 'pll_get_taxonomies', array( $this, 'pll_get_types' ), 10, 2 ); + } + + /** + * Translates custom post types and taxonomies labels when the language is set from the content. + * + * @since 2.1 + * + * @param array $types Array of registered post types or taxonomies. + * @param array $cptui_types Array of CPT UI post types or taxonomies. + */ + public function translate_registered_types( $types, $cptui_types ) { + foreach ( $types as $name => $type ) { + if ( in_array( $name, $cptui_types ) ) { + $type->label = pll__( $type->label ); + $type->description = pll__( $type->description ); + + foreach ( array_keys( get_object_vars( $type->labels ) ) as $key ) { + $type->labels->$key = pll__( $type->labels->$key ); + } + } + } + } + + /** + * Translates custom post types and taxonomies labels when the language is set from the content. + * + * @since 2.1 + */ + public function pll_language_defined() { + $this->translate_registered_types( $GLOBALS['wp_post_types'], array_keys( get_option( 'cptui_post_types', array() ) ) ); + $this->translate_registered_types( $GLOBALS['wp_taxonomies'], array_keys( get_option( 'cptui_taxonomies', array() ) ) ); + } + + /** + * Add CPT UI post types and taxonomies to Polylang settings. + * + * @since 2.1 + * + * @param string[] $types List of post type or taxonomy names. + * @param bool $is_settings True when displaying the list in Polylang settings. + * @return string[] + */ + public function pll_get_types( $types, $is_settings ) { + if ( $is_settings ) { + $type = substr( current_filter(), 8 ); + $cptui_types = get_option( "cptui_{$type}" ); + + if ( is_array( $cptui_types ) ) { + $types = array_merge( $types, array_keys( $cptui_types ) ); + } + } + return $types; + } +} diff --git a/wp-content/plugins/polylang-pro/integrations/cptui/load.php b/wp-content/plugins/polylang-pro/integrations/cptui/load.php new file mode 100644 index 000000000..a7eb0a80b --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/cptui/load.php @@ -0,0 +1,18 @@ +cptui = new PLL_CPTUI(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/integrations/divi/divi-builder.php b/wp-content/plugins/polylang-pro/integrations/divi/divi-builder.php new file mode 100644 index 000000000..926308ce1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/divi/divi-builder.php @@ -0,0 +1,49 @@ +divi_builder = new PLL_Divi_Builder(); + } + } +); diff --git a/wp-content/plugins/polylang-pro/integrations/events-calendar/load.php b/wp-content/plugins/polylang-pro/integrations/events-calendar/load.php new file mode 100644 index 000000000..30a18bdc1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/events-calendar/load.php @@ -0,0 +1,18 @@ +tec = new PLL_TEC(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/integrations/events-calendar/tec.php b/wp-content/plugins/polylang-pro/integrations/events-calendar/tec.php new file mode 100644 index 000000000..010cfd9b0 --- /dev/null +++ b/wp-content/plugins/polylang-pro/integrations/events-calendar/tec.php @@ -0,0 +1,1272 @@ +model->has_languages() ) { + return; + } + + $this->polylang = $polylang; + $this->curlang = null; + $this->slugs_model = ! empty( $polylang->translate_slugs ) && ! empty( $polylang->translate_slugs->slugs_model ) ? $polylang->translate_slugs->slugs_model : null; + $this->is_tec_rest_request = array(); + $this->translatable_slug_ids = array(); + + add_filter( 'pll_get_taxonomies', array( $this, 'translate_taxonomies' ), 10, 2 ); + add_filter( 'pll_get_post_types', array( $this, 'translate_types' ), 10, 2 ); + + add_action( 'save_post_' . Venue::POSTTYPE, array( $this, 'set_language' ), 10, 3 ); + add_action( 'save_post_' . Organizer::POSTTYPE, array( $this, 'set_language' ), 10, 3 ); + + $tec = TEC::instance(); + + if ( empty( $polylang->options['force_lang'] ) ) { + add_action( 'pll_language_defined', array( $this, 'fix_date_translations' ) ); + } + + self::$metas = array_merge( $tec->metaTags, $tec->venueTags, $tec->organizerTags, array( '_VenueShowMap', '_VenueShowMapLink' ) ); + + if ( isset( $GLOBALS['pagenow'], $_GET['from_post'], $_GET['new_lang'] ) && 'post-new.php' === $GLOBALS['pagenow'] ) { + check_admin_referer( 'new-post-translation' ); + + // Defaults values for events + foreach ( self::$metas as $meta ) { + $filter = str_replace( array( '_Event', '_Organizer', '_Venue' ), array( '', 'Organizer', 'Venue' ), $meta ); + add_filter( 'tribe_get_meta_default_value_' . $filter, array( $this, 'copy_event_meta' ), 10, 4 ); // Since TEC 4.0.7. + } + + add_filter( 'tribe_display_event_linked_post_dropdown_id', array( $this, 'translate_linked_post' ) ); + } + + add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 60 ); // After `Tribe__Events__Query->pre_get_posts()`. + + add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ) ); + add_filter( 'pll_translate_post_meta', array( $this, 'translate_meta' ), 10, 3 ); + + // Translate links with translated slugs + add_action( 'init', array( $this, 'reset_slugs' ), 11 ); // Just after `Tribe__Events__Main->init()`. + add_filter( 'register_taxonomy_args', array( $this, 'register_taxonomy_args' ), 10, 2 ); + add_filter( 'tribe_events_get_link', array( $this, 'get_link' ) ); + add_filter( 'pll_get_archive_url', array( $this, 'pll_get_archive_url' ), 10, 2 ); + add_filter( 'pll_term_link', array( $this, 'filter_tec_term_link' ), 5, 3 ); // Before `PLL_Translate_Slugs->pll_term_link()`. + add_filter( 'pll_translated_slugs', array( $this, 'pll_translated_slugs' ), 10, 3 ); + add_filter( 'pll_sanitize_string_translation', array( $this, 'sanitize_string_translation' ), 10, 2 ); + add_filter( 'tribe_events_rewrite_i18n_slugs_raw', array( $this, 'rewrite_slugs' ) ); + + // Options to translate. + $keys = array( + 'dateWithYearFormat' => 1, + 'dateWithoutYearFormat' => 1, + 'monthAndYearFormat' => 1, + 'dateTimeSeparator' => 1, + 'timeRangeSeparator' => 1, + 'tribeEventsBeforeHTML' => 1, + 'tribeEventsAfterHTML' => 1, + ); + + $args = array( + 'context' => 'The Events Calendar', + 'sanitize_callback' => array( $this, 'sanitize_strings' ), + ); + + new PLL_Translate_Option( 'tribe_events_calendar_options', $keys, $args ); + + // TEC views V2. + add_filter( 'tribe_events_rewrite_i18n_domains', '__return_empty_array', 10000 ); // No i18n domains, no translations to deal with. + add_filter( 'tribe_events_rewrite_i18n_slugs', array( $this, 'fix_escaped_dashes_in_slugs' ), 10, 2 ); + + add_filter( 'tribe_events_category_slug', array( $this, 'get_category_slug' ) ); + add_filter( 'tribe_events_tag_slug', array( $this, 'get_tag_slug' ) ); + + add_filter( 'tribe_events_views_v2_endpoint_url', array( $this, 'add_missing_lang_to_rest_url' ) ); + add_filter( 'locale', array( $this, 'filter_locale_for_rest' ), 5 ); + + add_filter( 'tribe_events_views_v2_publicly_visible_views_query_args', array( $this, 'add_language_to_publicly_visible_views_query_args' ), 5 ); + add_filter( 'tribe_events_views_v2_view_template_vars', array( $this, 'translate_widget_view_more_link' ), 5 ); + add_filter( 'tribe_rewrite_parse_query_vars', array( $this, 'force_language_on_tec_parse_query_vars' ), 10, 3 ); + add_filter( 'tribe_events_views_v2_url_query_args', array( $this, 'add_missing_lang_to_query_arg' ) ); + add_filter( 'tribe_rewrite_pre_canonical_url', array( $this, 'add_missing_lang_to_non_canonical_url' ), 10, 2 ); + add_filter( 'tribe_rewrite_pre_canonical_url', array( $this, 'remove_name_arg_from_non_canonical_url' ), 10, 2 ); + + add_filter( 'tribe_rewrite_canonical_url', array( $this, 'fix_language_in_canonical_url' ), 5, 2 ); + add_filter( 'tribe_rewrite_canonical_url', array( $this, 'translate_canonical_url' ), 5, 2 ); + } + + /** + * Language and translation management for taxonomies. + * + * @since 2.2 + * + * @param string[] $taxonomies List of taxonomy names for which Polylang manages language and translations. + * @param bool $hide True when displaying the list in Polylang settings. + * @return string[] List of taxonomy names for which Polylang manages language and translations. + */ + public function translate_taxonomies( $taxonomies, $hide ) { + // Hide from Polylang settings + return $hide ? array_diff( $taxonomies, array( TEC::TAXONOMY ) ) : array_merge( $taxonomies, array( TEC::TAXONOMY ) ); + } + + /** + * Language and translation management for custom post types. + * + * @since 2.2 + * + * @param string[] $types List of post type names for which Polylang manages language and translations. + * @param bool $hide True when displaying the list in Polylang settings. + * @return string[] List of post type names for which Polylang manages language and translations. + */ + public function translate_types( $types, $hide ) { + $tec_types = array( TEC::POSTTYPE, TEC::VENUE_POST_TYPE, TEC::ORGANIZER_POST_TYPE ); + return $hide ? array_diff( $types, $tec_types ) : array_merge( $types, $tec_types ); + } + + /** + * Save the language of Venues and Organizers. + * Needed when they are created from the Event form. + * + * @since 2.2 + * + * @param int $post_id Post id. + * @param WP_Post $post Post object. + * @param bool $update Whether it is an update or not. + * @return void + */ + public function set_language( $post_id, $post, $update ) { + if ( $update || ! isset( $_POST['post_lang_choice'] ) ) { + return; + } + + $post_type_object = get_post_type_object( $post->post_type ); + + if ( ! $post_type_object || ! current_user_can( $post_type_object->cap->create_posts ) ) { + return; + } + + check_admin_referer( 'pll_language', '_pll_nonce' ); + $lang = $this->polylang->model->get_language( sanitize_key( $_POST['post_lang_choice'] ) ); + + if ( ! $lang ) { + return; + } + + $this->polylang->model->post->set_language( $post_id, $lang ); + } + + /** + * Once the language is set from content, this resets all the date-related translations in TEC to the current lang. + * In `Tribe__Date_Utils`, TEC stores these translations in static private properties before the language is set in + * PLL. Then these translations are use later, AFTER the language is set in PLL, leading to views exploding due to + * array keys not being set. + * The filter 'tribe_events_get_days_of_week' can't be used because it doesn't include the function's arg `$format`. + * + * @since 3.1 + * @see tribe_events_get_days_of_week() + * + * @return void + */ + public function fix_date_translations() { + $properties = array( + 'localized_months_full', + 'localized_months_short', + 'localized_weekdays', + 'localized_months', + ); + + foreach ( $properties as $property ) { + $property = new ReflectionProperty( Tribe__Date_Utils::class, $property ); + $property->setAccessible( true ); + $property->setValue( array() ); + } + + TEC::instance()->setup_l10n_strings(); + } + + /** + * Populates default event metas for a newly created event translation + * + * @since 2.2 + * + * @param mixed $value Meta value. + * @param int $id Post id. + * @param string $meta Meta key. + * @param bool $single Whether to return a single value. + * @return mixed + */ + public function copy_event_meta( $value, $id, $meta, $single ) { + if ( ! empty( $_GET['from_post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + $value = get_post_meta( (int) $_GET['from_post'], $meta, $single ); // phpcs:ignore WordPress.Security.NonceVerification + } + return $value; + } + + /** + * Populates default values for venues and organizers for a newly created event translation. + * + * @since 2.2 + * + * @param array $posts Array of linked posts. + * @return array + */ + public function translate_linked_post( $posts ) { + if ( empty( $posts ) || ! isset( $_GET['new_lang'] ) ) { + return $posts; + } + + check_admin_referer( 'new-post-translation' ); + + $lang = $this->polylang->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // Make sure this is a valid language. + + if ( empty( $lang ) ) { + return $posts; + } + + $lang = $lang->slug; + $post_metas = ! empty( $this->polylang->sync ) && ! empty( $this->polylang->sync->post_metas ) ? $this->polylang->sync->post_metas : false; + + foreach ( $posts as $key => $post_id ) { + $tr_id = pll_get_post( $post_id, $lang ); + + if ( ! empty( $tr_id ) ) { + $posts[ $key ] = $tr_id; + continue; + } + + // If the translated venue or organizer doesn't exist, create it. + $post = get_post( $post_id, ARRAY_A ); // Output as an array for `wp_insert_post()`. + + if ( empty( $post ) ) { + // `null` value. + continue; + } + + unset( $post['ID'] ); + + $tr_id = wp_insert_post( wp_slash( $post ) ); + + if ( ! is_int( $tr_id ) ) { + // `WP_Error` value. + continue; + } + + $translations = pll_get_post_translations( $post_id ); + $translations[ $lang ] = $tr_id; + + pll_set_post_language( $tr_id, $lang ); + pll_save_post_translations( $translations ); + + if ( ! empty( $post_metas ) ) { + $post_metas->copy( $post_id, $tr_id, $lang ); + } + + $posts[ $key ] = $tr_id; + } + + return $posts; + } + + /** + * Removes date filters when searching for untranslated events in the metabox autocomplete field + * + * @since 2.2.8 + * + * @return void + */ + public function pre_get_posts() { + if ( wp_doing_ajax() && isset( $_GET['action'] ) && 'pll_posts_not_translated' === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification + // See Tribe__Events__Query::pre_get_posts() when should_remove_date_filters() returns true + remove_filter( 'posts_where', array( 'Tribe__Events__Query', 'posts_where' ) ); + remove_filter( 'posts_fields', array( 'Tribe__Events__Query', 'posts_fields' ) ); + remove_filter( 'posts_orderby', array( 'Tribe__Events__Query', 'posts_orderby' ) ); + } + } + + /** + * Synchronize event metas. + * + * @since 2.2 + * + * @param array $metas Custom fields to copy or synchronize. + * @return array + */ + public function copy_post_metas( $metas ) { + return array_merge( $metas, self::$metas ); + } + + /** + * Translate venues and organizers before they are copied or synchronized. + * + * @since 2.3 + * + * @param mixed $value Meta value. + * @param string $key Meta key. + * @param string $lang Language of target. + * @return mixed + */ + public function translate_meta( $value, $key, $lang ) { + if ( ( '_EventVenueID' === $key || '_EventOrganizerID' === $key ) && $tr_value = pll_get_post( $value, $lang ) ) { + $value = $tr_value; + } + return $value; + } + + /** + * Resets all TEC translated slugs to an English value as the TEC slug translation system + * does not work in a multilingual context (TEC 4.4.5 + WP 4.7.3). + * + * @since 2.2 + * + * @return void + */ + public function reset_slugs() { + $tec = TEC::instance(); + + foreach ( $this->get_slugs_to_reset() as $key => $slug ) { + $tec->$key = $slug; + } + + // Those are deprecated since TEC 4.0 and should not appear in the list of translatable strings anymore. + $tec->taxRewriteSlug = $tec->rewriteSlug . '/category'; + $tec->tagRewriteSlug = $tec->rewriteSlug . '/tag'; + } + + /** + * Resets the category base rewrite slug in taxonomy. + * + * @since 2.2 + * + * @param array $args Array of arguments for registering a taxonomy. + * @param string $taxonomy Taxonomy key. + * @return array + */ + public function register_taxonomy_args( $args, $taxonomy ) { + if ( TEC::TAXONOMY === $taxonomy && is_array( $args['rewrite'] ) ) { + $args['rewrite']['slug'] = TEC::instance()->rewriteSlug . '/category'; + } + + return $args; + } + + /** + * Filters the links to add the language code. + * + * @since 2.2 + * + * @param string $link Link generated by The Events Calendar. + * @return string + */ + public function get_link( $link ) { + $curlang = $this->get_curlang(); + + if ( empty( $curlang ) || empty( $this->slugs_model ) ) { + return $link; + } + + $link = $this->polylang->links_model->add_language_to_link( $link, $curlang ); + + foreach ( $this->get_translatable_slug_ids() as $slug_id ) { + $link = $this->slugs_model->translate_slug( $link, $curlang, $slug_id ); + } + + return $link; + } + + /** + * Translates slugs in the language switcher. + * + * @since 2.2 + * + * @param string $url Url in the language switcher. + * @param PLL_Language $language Language object. + * @return string Modified url. + */ + public function pll_get_archive_url( $url, $language ) { + if ( empty( $this->slugs_model ) || ! is_post_type_archive( TEC::POSTTYPE ) ) { + return $url; + } + + foreach ( $this->get_translatable_slug_ids() as $slug_id ) { + $url = $this->slugs_model->switch_translated_slug( $url, $language, $slug_id ); + } + + return $url; + } + + /** + * Modifies term links for the taxonomies used by TEC. + * In `PLL_TEC->reset_slugs()` we don't include the full taxonomy slug (`Tribe__Events__Main->taxRewriteSlug`) in + * our translated strings, as it is deprecated in TEC 4.0 and also a composite of + * `{post type archive slug}/{tax base slug}`. This explains why this method is needed. + * + * @since 3.1 + * @see PLL_TEC->reset_slugs() + * @see PLL_TEC->pll_translated_slugs() + * + * @param string $url The term link. + * @param PLL_Language $lang The term language. + * @param WP_Term $term The term object. + * @return string + */ + public function filter_tec_term_link( $url, $lang, $term ) { + if ( empty( $this->slugs_model ) || TEC::TAXONOMY !== $term->taxonomy ) { + return $url; + } + + $url = $this->slugs_model->translate_slug( $url, $lang, 'archive_' . TEC::POSTTYPE ); + return $this->slugs_model->translate_slug( $url, $lang, 'tribe_category' ); + } + + /** + * Fixes the events slug in translatable slugs. + * Translates other TEC slugs. + * + * @since 2.2 + * + * @param array $slugs Translated slugs. + * @param PLL_Language $language Language object. + * @param PLL_MO $mo Strings translations object. + * @return array + */ + public function pll_translated_slugs( $slugs, $language, &$mo ) { + /** + * In `PLL_TEC->reset_slugs()` we don't include the full taxonomy slug (`Tribe__Events__Main->taxRewriteSlug`) in + * our translated strings, as it is deprecated in TEC 4.0 and also a composite of + * `{post type archive slug}/{tax base slug}`. This is why we unset `$slugs[ TEC::TAXONOMY ]` here. + */ + unset( $slugs[ 'archive_' . TEC::POSTTYPE ]['hide'], $slugs[ TEC::TAXONOMY ] ); + + $slugs[ 'archive_' . TEC::POSTTYPE ]['slug'] = $slug = TEC::instance()->getRewriteSlug(); + $tr_slug = $mo->translate( $slug ); + $slugs[ 'archive_' . TEC::POSTTYPE ]['translations'][ $language->slug ] = empty( $tr_slug ) ? $slug : $tr_slug; + + foreach ( $this->get_slugs_to_reset() as $slug ) { + $slugs[ 'tribe_' . $slug ]['slug'] = $slug; + $tr_slug = $mo->translate( $slug ); + $slugs[ 'tribe_' . $slug ]['translations'][ $language->slug ] = empty( $tr_slug ) ? $slug : $tr_slug; + } + + return $slugs; + } + + /** + * Performs the sanitization ( before saving in DB ) of slugs translations + * The Events Calendar does not accept accents, but let's accept slashes for the event category slug + * + * @since 1.9 + * + * @param string $translation Translation to sanitize. + * @param string $name Unique name for the string. + * @return string + */ + public function sanitize_string_translation( $translation, $name ) { + if ( 'slug_archive_tribe_events' === $name || 0 === strpos( $name, 'slug_tribe_' ) ) { + $slugs = explode( '/', $translation ); + $slugs = array_map( 'sanitize_title', $slugs ); + return implode( '/', $slugs ); + } + return $translation; + } + + /** + * Add translated slugs to specific TEC rewrite rules. + * + * @since 2.2 + * + * @param array $bases Array of arrays of rewrite base slugs. + * @return array + */ + public function rewrite_slugs( $bases ) { + $translatable_slugs = $this->get_translatable_slugs(); + + if ( empty( $translatable_slugs ) ) { + return $bases; + } + + foreach ( $bases as $type => $base ) { + $default_slug = reset( $base ); + + foreach ( $translatable_slugs as $slugs ) { + if ( $slugs['slug'] === $default_slug ) { + $bases[ $type ] = array_unique( array_merge( array( $default_slug ), $slugs['translations'] ) ); + break; + } + } + } + + return $bases; + } + + /** + * Translated strings must be sanitized the same way The Events Calendar does before they are saved. + * All are of validation_type 'html'. + * + * @since 2.2 + * + * @param string $translation Translated string. + * @param string $name String name. + * @param string $context String context. + * @return string Sanitized translation. + */ + public function sanitize_strings( $translation, $name, $context ) { + if ( 'The Events Calendar' === $context ) { + $translation = balanceTags( $translation ); + } + + return $translation; + } + + /** + * Filters TEC's base slugs to unescape dashes. + * + * If `$method` is 'regex', `Tribe__Events__Rewrite->get_bases()` will use `preg_quote()` to get + * its slugs ready as regex patterns. However, `-` characters are valid in this context and + * should not be escaped (reminder: they come from PLL's string translations). + * + * @since 3.1 + * @see $this->rewrite_slugs() + * + * @param string[] $bases An array of rewrite bases that have been generated. + * @param string $method The method that's being used to generate the bases; defaults to `regex`. + * @return string[] + */ + public function fix_escaped_dashes_in_slugs( $bases, $method ) { + if ( 'regex' !== $method ) { + return $bases; + } + + return array_map( + function ( $base ) { + return str_replace( '\\-', '-', $base ); + }, + $bases + ); + } + + /** + * Filters the string to be used as the taxonomy slug. + * This replaces TEC's translated category slug by the untranslated one, as it is returned by the public method + * `Tribe__Events__Main->get_category_slug()`. + * + * @since 3.1 + * + * @return string + */ + public function get_category_slug() { + return 'category'; + } + + /** + * Filters the string to be used as the tag slug. + * This replaces TEC's translated tag slug by the untranslated one, as it is returned by a public method + * `Tribe__Events__Main->get_tag_slug()`. + * + * @since 3.1 + * + * @return string + */ + public function get_tag_slug() { + return 'tag'; + } + + /** + * Adds the lang to TEC's REST URL. + * This provides a way to identify in whish language PLL should work in the REST request. + * + * @since 3.1 + * + * @param string $url The View endpoint URL, either a REST API URL or a admin-ajax.php fallback URL if REST API + * is not available. + * @return string + */ + public function add_missing_lang_to_rest_url( $url ) { + $curlang = $this->get_curlang(); + + if ( empty( $curlang ) ) { + return $url; + } + + $lang = $this->get_lang_from_url_query_arg( $url ); + + if ( ! empty( $lang ) ) { + return $url; + } + + return add_query_arg( array( 'lang' => $curlang->slug ), $url ); + } + + /** + * Filters the locale when TEC is performing a REST request. + * + * @since 3.1 + * + * @param string $locale The locale ID. + * @return string + */ + public function filter_locale_for_rest( $locale ) { + if ( ! $this->is_tec_rest_request() ) { + return $locale; + } + + $curlang = $this->get_curlang(); + + if ( empty( $curlang->locale ) ) { + return $locale; + } + + return $curlang->locale; + } + + /** + * Filters the query arguments that should be applied to the View links to add the missing language. + * The added language is the global current language. + * + * @since 3.1 + * + * @param mixed[] $url_args The current URL query arguments, created from a filtered version of the current + * request context. + * @return mixed[] + */ + public function add_language_to_publicly_visible_views_query_args( $url_args ) { + $curlang = $this->get_curlang(); + + if ( ! empty( $curlang ) ) { + $url_args['lang'] = $curlang->slug; + } + return $url_args; + } + + /** + * Fixes the "upcoming events" widget link. + * + * @since 3.1 + * + * @param mixed[] $template_vars An associative array of template variables. Variables will be extracted in the + * template hence the key will be the name of the variable available in the template. + * @return mixed[] + */ + public function translate_widget_view_more_link( $template_vars ) { + if ( ! isset( $template_vars['view_more_link'] ) ) { + return $template_vars; + } + + $curlang = $this->get_curlang(); + + if ( empty( $curlang ) || empty( $this->slugs_model ) ) { + return $template_vars; + } + + $template_vars['view_more_link'] = home_url( '/' . tribe_get_option( 'eventsSlug', 'events' ) ); + $template_vars['view_more_link'] = $this->polylang->links_model->add_language_to_link( $template_vars['view_more_link'], $curlang ); + $template_vars['view_more_link'] = $this->slugs_model->translate_slug( $template_vars['view_more_link'], $curlang, 'archive_' . TEC::POSTTYPE ); + $template_vars['view_more_link'] = user_trailingslashit( $template_vars['view_more_link'] ); + + return $template_vars; + } + + /** + * Filters the array of query variables parsed by TEC to force the use of the right language. + * For example, `example.com/events?lang=de` would return the default language instead of using the provided query + * arg because TEC tries to use the WP rewrite rules to match the query path, and `events` => default language. + * However, this is not needed for `example.com/de/events-de/` and `example.com/?lang=de` because the right + * language will be set in these cases. + * + * @since 3.1 + * @see Tribe__Rewrite->parse_request() + * @see PLL_TEC->add_language_to_publicly_visible_views_query_args() + * + * @param string[] $query_vars The parsed query vars array. + * @param string[] $extra_query_vars An associative array of extra query vars that will be processed before + * the WordPress defined ones. + * @param string $url The URL to parse. + * @return string[] + */ + public function force_language_on_tec_parse_query_vars( $query_vars, $extra_query_vars, $url ) { + // Find the lang in the URL... + $lang = $this->get_lang_from_url_query_arg( $url ); + + if ( ! empty( $lang ) ) { + // ... and add it to the query vars. + $query_vars['lang'] = $lang->slug; + } + + return $query_vars; + } + + /** + * Adds the lang to TEC's query arguments that will be used to build a View URL. + * This insures that a lang arg is available when building the view's URL. + * + * @since 3.1 + * + * @param mixed[] $query_args An array of query args that will be used to build the URL for the View. + * @return mixed[] + */ + public function add_missing_lang_to_query_arg( $query_args ) { + if ( isset( $query_args['lang'] ) ) { + return $query_args; + } + + $curlang = $this->get_curlang(); + + $query_args['lang'] = ! empty( $curlang ) ? $curlang->slug : $this->polylang->options['default_lang']; + + return $query_args; + } + + /** + * Adds the lang to the URL passed to `Tribe__Rewrite->get_canonical_url()`. + * This insures that a lang arg is available when building a URL. + * + * @since 3.1 + * + * @param string|null $canonical_url The canonical URL, defaults to `null`; returning a non `null` value will + * make the logic bail and return the value. + * @param string $url The input URL to resolve to a canonical one. + * @return string|null + */ + public function add_missing_lang_to_non_canonical_url( $canonical_url, $url ) { + $lang = $this->get_lang_from_url_query_arg( $url ); + + if ( ! empty( $lang ) ) { + // All good. + return $canonical_url; + } + + $curlang = $this->get_curlang(); + + if ( empty( $curlang ) ) { + // We're screwed. + return $canonical_url; + } + + // Re-inject the URL with the current lang. `$this->get_lang_from_url_query_arg()` will prevent an infinite loop. + return Tribe__Rewrite::instance()->get_canonical_url( add_query_arg( 'lang', $curlang->slug, $url ) ); + } + + /** + * Removes the `name` arg from the URL passed to `Tribe__Rewrite->get_canonical_url()` when there is already a + * `post_type` arg: this seems to mess up the process. + * + * @since 3.1 + * + * @param string|null $canonical_url The canonical URL, defaults to `null`; returning a non `null` value will + * make the logic bail and return the value. + * @param string $url The input URL to resolve to a canonical one. + * @return string|null + */ + public function remove_name_arg_from_non_canonical_url( $canonical_url, $url ) { + $url_query = wp_parse_url( $url, PHP_URL_QUERY ); + + if ( empty( $url_query ) ) { + return $canonical_url; + } + + $parsed_query = array(); + wp_parse_str( $url_query, $parsed_query ); + + if ( empty( $parsed_query ) ) { + return $canonical_url; + } + + if ( empty( $parsed_query['post_type'] ) || empty( $parsed_query['name'] ) || ! empty( $parsed_query['ical'] ) ) { + return $canonical_url; + } + + if ( TEC::POSTTYPE !== $parsed_query['post_type'] ) { + return $canonical_url; + } + + if ( ! empty( $parsed_query['lang'] ) && $parsed_query['lang'] === $parsed_query['name'] ) { + // ¯\(°_o)/¯. + $remove = true; + } elseif ( tribe_get_option( 'eventsSlug' ) === $parsed_query['name'] ) { + $remove = true; + } + + if ( empty( $remove ) ) { + return $canonical_url; + } + + // Re-inject the URL. Tests against `$parsed_query['name']` will prevent an infinite loop. + return Tribe__Rewrite::instance()->get_canonical_url( remove_query_arg( 'name', $url ) ); + } + + /** + * Filters TEC's canonical URL to fix the language slug in it. + * Because of TEC's method to build URLs, using the rewrite rules array, the language slug is not replaced and is + * outputed like the rewrite rule pattern: `/(en|fr|de)/`. This filter replaces the pattern by the language + * contained in the original URL. If not found in the original URL, falls back to the current language or the default + * one. + * + * @since 3.1 + * + * @param string $resolved The resolved, canonical URL. + * @param string $url The original URL to resolve. + * @return string + */ + public function fix_language_in_canonical_url( $resolved, $url ) { + $options = $this->polylang->options; + + // Remove the default language if it must be hidden in the URLs. + $languages = $this->polylang->model->get_languages_list( + array( + 'hide_default' => $options['hide_default'], + 'fields' => 'slug', + ) + ); + + if ( empty( $languages ) ) { + return $resolved; + } + + /** + * What we want to modify in the URL. + * Ex: `/(en|fr|de)`, `/language/(fr|de)`. + */ + $language_path = $options['rewrite'] ? '' : '/language'; + $to_replace = $language_path . '/(' . implode( '|', $languages ) . ')/'; + + if ( strpos( $resolved, $to_replace ) === false ) { + return $resolved; + } + + // Find the lang in the URL (or fallback). + $lang = $this->get_lang_from_url_query_arg( $url ); + + if ( empty( $lang ) ) { + // We need a lang, whichever it is. + $curlang = $this->get_curlang(); + $lang = ! empty( $curlang ) ? $curlang->slug : $options['default_lang']; + } else { + $lang = $lang->slug; + } + + // Make the final replacement. + if ( $options['hide_default'] && $options['default_lang'] === $lang ) { + // The default language is hidden in the URL. + $replacement = '/'; + } else { + $replacement = "{$language_path}/{$lang}/"; + } + + return str_replace( $to_replace, $replacement, $resolved ); + } + + /** + * Filters TEC's canonical URL to translate all slugs in it. + * This is possible because a `lang` arg is available in the "uggly" URL. + * + * @since 3.1 + * @see Tribe__Events__Rewrite->get_dynamic_matchers() + * + * @param string $resolved The resolved, canonical URL. + * @param string $url The original URL to resolve. + * @return string + */ + public function translate_canonical_url( $resolved, $url ) { + if ( empty( $this->slugs_model ) ) { + return $resolved; + } + + // Find the lang in the URL (or fallback). + $lang = $this->get_lang_from_url_query_arg_or_fallback( $url ); + + if ( empty( $lang ) ) { + // What? + return $resolved; + } + + // Make sure the language is well formatted. + $resolved = remove_query_arg( 'lang', $resolved ); + $resolved = $this->polylang->links_model->add_language_to_link( $resolved, $lang ); + + foreach ( $this->get_translatable_slugs() as $slug_id => $translations ) { + $resolved = $this->slugs_model->switch_translated_slug( $resolved, $lang, $slug_id ); + } + + return $resolved; + } + + /** + * Tells if a request is a TEC REST API request. + * TEC does a good job for their REST URL by providing a `admin-ajax.php` fallback in case the REST API is not + * available. Unfortunately, this choice is late in the process so we have to test the given URL against the 2 + * possibilities. + * + * @since 3.1 + * @see Tribe\Events\Views\V2\Rest_Endpoint->get_url() + * + * @param string $requested_url The requested URL. Falls back to the current URL. + * @return bool|null Whether the request is a TEC REST API request. Null if not ready to answer yet. + */ + protected function is_tec_rest_request( $requested_url = null ) { + if ( ! isset( $this->is_tec_rest_request['views_v2_is_enabled'] ) ) { + if ( ! function_exists( 'tribe_events_views_v2_is_enabled' ) ) { + return null; + } + + $this->is_tec_rest_request['views_v2_is_enabled'] = tribe_events_views_v2_is_enabled(); + } + + if ( ! $this->is_tec_rest_request['views_v2_is_enabled'] ) { + // If the views V2 are not enabled, no REST requests. + return false; + } + + if ( empty( $requested_url ) || ! is_string( $requested_url ) ) { + // Fall back to the current URL. + if ( ! isset( $this->is_tec_rest_request['pll_requested_url'] ) ) { + $this->is_tec_rest_request['pll_requested_url'] = (string) set_url_scheme( pll_get_requested_url() ); + } + + $requested_url = $this->is_tec_rest_request['pll_requested_url']; + } else { + $requested_url = (string) set_url_scheme( $requested_url ); + } + + if ( isset( $this->is_tec_rest_request[ 'is:' . $requested_url ] ) ) { + return $this->is_tec_rest_request[ 'is:' . $requested_url ]; + } + + if ( false === strpos( $requested_url, '/admin-ajax.php' ) ) { + // Test against the REST URL. + if ( ! isset( $this->is_tec_rest_request['tec_rest_url_pattern'] ) ) { + $url = $this->get_tec_rest_url( true ); + + if ( empty( $url ) ) { + // `$wp_rewrite` is probably not set yet. + return null; + } + + $this->is_tec_rest_request['tec_rest_url_pattern'] = preg_replace( '@[#?].*$@', '', $url ); + $this->is_tec_rest_request['tec_rest_url_pattern'] = sprintf( '@^%s[/?#]@i', preg_quote( $this->is_tec_rest_request['tec_rest_url_pattern'], '@' ) ); + } + + $this->is_tec_rest_request[ 'is:' . $requested_url ] = (bool) preg_match( $this->is_tec_rest_request['tec_rest_url_pattern'], $requested_url ); + + return $this->is_tec_rest_request[ 'is:' . $requested_url ]; + } + + // Test against the admin ajax URL. + if ( ! isset( $this->is_tec_rest_request['tec_ajax_url_action'] ) ) { + $this->is_tec_rest_request['tec_ajax_url_action'] = $this->get_tec_rest_url( false ); + $this->is_tec_rest_request['tec_ajax_url_action'] = $this->get_query_arg_from_url( $this->is_tec_rest_request['tec_ajax_url_action'], 'action' ); + } + + if ( empty( $this->is_tec_rest_request['tec_ajax_url_action'] ) ) { + // Uh? + $this->is_tec_rest_request[ 'is:' . $requested_url ] = false; + return false; + } + + $requested_action = $this->get_query_arg_from_url( $requested_url, 'action' ); + + $this->is_tec_rest_request[ 'is:' . $requested_url ] = $requested_action === $this->is_tec_rest_request['tec_ajax_url_action']; + + return $this->is_tec_rest_request[ 'is:' . $requested_url ]; + } + + /** + * Returns the current language object. + * Can return `null` if not defined yet. + * + * @since 3.1 + * + * @return PLL_Language|null + */ + protected function get_curlang() { + if ( ! empty( $this->curlang ) ) { + return $this->curlang; + } + + if ( ! empty( $_REQUEST['lang'] ) && is_string( $_REQUEST['lang'] ) && Polylang::is_rest_request() ) { // phpcs:ignore WordPress.Security.NonceVerification + // REST request. + $curlang = $this->polylang->model->get_language( sanitize_key( $_REQUEST['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification + + if ( ! empty( $curlang ) ) { + $this->curlang = $curlang; + $this->polylang->curlang = $this->curlang; + return $this->curlang; + } + } + + if ( ! empty( $this->polylang->curlang ) ) { + // Global context. + $this->curlang = &$this->polylang->curlang; + return $this->curlang; + } + + if ( empty( $this->polylang->options['force_lang'] ) && $this->polylang instanceof PLL_Frontend && ! did_action( 'pll_language_defined' ) ) { + // Lang defined by content: too soon. + return null; + } + + $curlang = $this->polylang->model->get_default_language(); + + if ( empty( $curlang ) ) { + // We're screwed. + return null; + } + + // Default lang. + $this->curlang = $curlang; + return $this->curlang; + } + + /** + * Returns the list of slugs that need to be reset in TEC, except the deprecated ones. + * + * @since 3.1 + * @see PLL_TEC->reset_slugs() + * + * @return string[] Array keys match `Tribe__Events__Main`'s properties name. + */ + protected function get_slugs_to_reset() { + return array( + 'category_slug' => 'category', + 'tag_slug' => 'tag', + 'monthSlug' => 'month', + 'listSlug' => 'list', + 'upcomingSlug' => 'upcoming', + 'pastSlug' => 'past', + 'daySlug' => 'day', + 'todaySlug' => 'today', + 'featured_slug' => 'featured', + 'all_slug' => 'all', + ); + } + + /** + * Returns the list of IDs of translatable slugs dedicated to TEC. + * Ex: `tribe_venue`, `archive_tribe_events`, `paged`, `tribe_today`. + * + * @since 3.1 + * + * @return string[] + */ + protected function get_translatable_slug_ids() { + if ( ! empty( $this->translatable_slug_ids ) ) { + return $this->translatable_slug_ids; + } + + $slug_ids = array( + Venue::POSTTYPE, + Organizer::POSTTYPE, + TEC::POSTTYPE, + 'archive_' . TEC::POSTTYPE, + 'post_tag', + 'paged', + ); + + foreach ( $this->get_slugs_to_reset() as $slug ) { + $slug_ids[] = 'tribe_' . $slug; + } + + $this->translatable_slug_ids = array_combine( $slug_ids, $slug_ids ); + + return $this->translatable_slug_ids; + } + + /** + * Returns the list of translatable slugs dedicated to TEC. + * + * @since 3.1 + * + * @return mixed[] + */ + protected function get_translatable_slugs() { + if ( empty( $this->slugs_model ) ) { + return array(); + } + + return array_intersect_key( $this->slugs_model->get_translatable_slugs(), $this->get_translatable_slug_ids() ); + } + + /** + * Returns the value of the `lang` query arg from the given URL. + * + * @since 3.1 + * + * @param string $url The URL to retrieve the arg from. + * @return PLL_Language|null The lang object. Null if not found or invalid. + */ + protected function get_lang_from_url_query_arg( $url ) { + $lang = $this->get_query_arg_from_url( $url, 'lang' ); + + if ( empty( $lang ) || ! is_string( $lang ) ) { + return null; + } + + $lang = $this->polylang->model->get_language( sanitize_key( $lang ) ); + + if ( empty( $lang ) ) { + return null; + } + + return $lang; + } + + /** + * Returns the value of the `lang` query arg from the given URL. + * + * @since 3.1 + * + * @param string $url The URL to retrieve the arg from. + * @return PLL_Language|null The lang object. Null if not found or invalid. + */ + protected function get_lang_from_url_query_arg_or_fallback( $url ) { + $lang = $this->get_lang_from_url_query_arg( $url ); + + if ( ! empty( $lang ) ) { + return $lang; + } + + $lang = $this->get_curlang(); + + if ( ! empty( $lang ) ) { + return $lang; + } + + // Uh? + $lang = $this->polylang->model->get_default_language(); + + if ( ! empty( $lang ) ) { + return $lang; + } + + // What? + return null; + } + + /** + * Returns the value of a query arg from the given URL. + * + * @since 3.1 + * + * @param string $url The URL to retrieve the arg from. + * @param string $query_arg_name The name of the query arg to retrieve. + * @return string|null The raw value of the query arg. Null if not found. + */ + protected function get_query_arg_from_url( $url, $query_arg_name ) { + if ( empty( $url ) || ! is_string( $url ) ) { + return null; + } + + if ( empty( $query_arg_name ) || ! is_string( $query_arg_name ) ) { + return null; + } + + $url_query = wp_parse_url( $url, PHP_URL_QUERY ); + + if ( empty( $url_query ) ) { + return null; + } + + $parsed = array(); + wp_parse_str( $url_query, $parsed ); + + if ( empty( $parsed[ $query_arg_name ] ) || ! is_string( $parsed[ $query_arg_name ] ) ) { + return null; + } + + return sanitize_key( $parsed[ $query_arg_name ] ); + } + + /** + * Returns TEC's REST URL. + * + * @since 3.1 + * + * @param bool $enable_rest True to get the REST URL. False to get the admin ajax URL. + * @return string|null The REST URL. Null if too soon to be determinated: this may happen when requesting the + * the real REST URL (`$enable_rest` is true) but `$wp_rewrite` is not ready. + */ + protected function get_tec_rest_url( $enable_rest ) { + global $wp_rewrite; + + if ( $enable_rest ) { + // In this case, `Rest_Endpoint->get_url()` will use `get_rest_url()`. + if ( is_multisite() && get_blog_option( 0, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) { // See the same test done in `get_rest_url()`. + // We test `$wp_rewrite` to prevent `get_rest_url()` to explode. + if ( ! $wp_rewrite instanceof WP_Rewrite ) { + return null; + } + } + } + + // Force `Rest_Endpoint->is_available()`'s behavior with this filter callback. + $priority = 100000; + $callback = function () use ( $enable_rest ) { + return (bool) $enable_rest; + }; + + add_filter( 'tribe_events_views_v2_rest_endpoint_available', $callback, $priority ); + $url = ( new Rest_Endpoint() )->get_url(); + remove_filter( 'tribe_events_views_v2_rest_endpoint_available', $callback, $priority ); + + return $url; + } +} diff --git a/wp-content/plugins/polylang-pro/js/build/acf.js b/wp-content/plugins/polylang-pro/js/build/acf.js new file mode 100644 index 000000000..6a8ddc58d --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/acf.js @@ -0,0 +1,58 @@ +/** + * @package Polylang-Pro + */ + +jQuery( + function ( $ ) { + /** + * Ajax for changing the post's language in the languages metabox. + */ + $( '.post_lang_choice' ).on( + 'change', + function () { + + // Reloads the relationship fields + if ( $( ".acf-field-relationship" ).length ) { + acf.doAction( 'ready' ); + } + + var fields = new Array(); + + $( '.acf-field-taxonomy' ).each( + function () { + var field = $( this ).attr( 'data-key' ); + fields.push( field ); + } + ); + + if ( 0 != fields.length ) { + var data = { + action: 'acf_post_lang_choice', + lang: $( this ).val(), + fields: fields, + _pll_nonce: $( '#_pll_nonce' ).val() + } + + $.post( + ajaxurl, + data, + function (response) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function () { + $el = $( '.acf-' + this.what ) + // Data come from ACF field and server side. + $el.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + acf.do_action( 'ready_field/type=' + $el.data( 'type' ), $el ); + } + ); + } + ); + } + } + ); + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/acf.min.js b/wp-content/plugins/polylang-pro/js/build/acf.min.js new file mode 100644 index 000000000..182b5a575 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/acf.min.js @@ -0,0 +1 @@ +jQuery((function(a){a(".post_lang_choice").on("change",(function(){a(".acf-field-relationship").length&&acf.doAction("ready");var e=new Array;if(a(".acf-field-taxonomy").each((function(){var n=a(this).attr("data-key");e.push(n)})),0!=e.length){var n={action:"acf_post_lang_choice",lang:a(this).val(),fields:e,_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,n,(function(e){var n=wpAjax.parseAjaxResponse(e,"pll-ajax-response");a.each(n.responses,(function(){$el=a(".acf-"+this.what),$el.html(this.data),acf.do_action("ready_field/type="+$el.data("type"),$el)}))}))}}))})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/admin.js b/wp-content/plugins/polylang-pro/js/build/admin.js new file mode 100644 index 000000000..091a95e9a --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/admin.js @@ -0,0 +1,427 @@ +/** + * @package Polylang + */ + +jQuery( + function( $ ) { + + // languages list table + // accessibility to row actions on focus + // mainly copy paste of WP code from common.js + var transitionTimeout; + $( 'table.languages' ).on( + { // restricted to languages list table + focusin: function() { + clearTimeout( transitionTimeout ); + var focusedRowActions = $( this ).find( '.row-actions' ); + // transitionTimeout is necessary for Firefox, but Chrome won't remove the CSS class without a little help. + $( '.row-actions' ).not( this ).removeClass( 'visible' ); + focusedRowActions.addClass( 'visible' ); + }, + focusout: function() { + // Tabbing between post title and .row-actions links needs a brief pause, otherwise + // the .row-actions div gets hidden in transit in some browsers ( ahem, Firefox ). + transitionTimeout = setTimeout( + function() { + focusedRowActions.removeClass( 'visible' ); + }, + 30 + ); + } + }, + 'tr' + ); // acts on the whole tr instead of single td as we have actions links in several columns + + /** + * Common functions and variables for overriding languages and flags dropdown list by a jQuery UI selectmenu widget. + */ + + // Add a boolean variable to be able to check jQuery UI >= 1.12 which is introduced in WP 5.6. + // Backward compatibility WP < 5.6 + var isJqueryUImin112 = $.ui.version >= '1.12.0'; + // Allow to check if a flag list dropdown is present. Not present in the Wizard steps or other settings page. + var flagListExist = $( "#flag_list" ).length; + // Allow to check if a language list dropdown is present. Not present in other settings page. + var langListExist = $( "#lang_list" ).length; + // jQuery UI selectmenu widget width option + var defaultSelectmenuWidth = '95%'; + var wizardSelectmenuWidth = '100%'; + + // Inject flag image when jQuery UI selectmenu is created or an item is selected. + // jQuery UI 1.12 introduce a wrapper inside de li tag which is necessary to selectmenu widget to work correctly. + // Mainly copy from the original jQuery UI 1.12 selectmenu widget _renderItem method. + // Note this code works fine with jQuery UI 1.11.4 too. + var selectmenuRenderItem = function( ul, item ) { + var li = $( '
  • ' ); + var wrapper = $( '
    '); + + if ( item.disabled ) { + this._addClass( li, null, "ui-state-disabled" ); + } + this._setText( wrapper, item.label ); + + // Add the flag from the data attribute in the selected element. + wrapper.prepend( $( item.element ).data( 'flag-html' ) ); + wrapper.children( 'img' ).addClass( 'ui-icon' ); + + return li.append( wrapper ).appendTo( ul ); + }; + // Override selected item to inject flag for jQuery UI less than 1.12. + var selectmenuRefreshButtonText = function( selectElement ) { + var buttonText = $( selectElement ).selectmenu( 'instance' ).buttonText; + buttonText.prepend( $( selectElement ).children( ':selected' ).data( 'flag-html' ) ); + buttonText.children( 'img' ).addClass( 'ui-icon' ); + }; + // Override selected item since jQuery UI 1.12 which introduces extension point method _renderButtonItem. + // @see https://api.jqueryui.com/1.12/selectmenu/#method-_renderButtonItem _renderButtonItem documentation. + var selectmenuRenderButtonItem = function ( selectElement ) { + var buttonItem = $( '' ); + this._setText( buttonItem, selectElement.label ); + this._addClass( buttonItem, "ui-selectmenu-text" ); + + // Add the flag from the data attribute in the selected element. + buttonItem.prepend( $( selectElement.element ).data( 'flag-html' ) ); + buttonItem.children( 'img' ).addClass( 'ui-icon' ); + + return buttonItem; + } + + /** + * Initialize a jQuery UI selectmenu widget on a DOM element + * + * @param {*} element - The jQuery object representing the DOM element to attach the widget with. + * @param {*} config - All the parameters - options and callbacks - necessary to configure the jQuery UI selectmenu widget. + * @return {Object} - The jQuery UI selectmenu widget object instance. + */ + function initializeSelectmenuWidget( element, config ) { + // Create the jQuery UI selectmenu widget for flags list dropdown and return its instance. + var selectmenuWidgetInstance = element.selectmenu( config ).selectmenu( 'instance' ); + // Overrides each item in the jQuery UI selectmenu list by injecting flag image. + selectmenuWidgetInstance._renderItem = selectmenuRenderItem; + // Override the selected item rendering for jQuery UI 1.12 + if ( isJqueryUImin112 ) { + selectmenuWidgetInstance._renderButtonItem = selectmenuRenderButtonItem; + // Need to refresh to take in account the new button item rendering method after the selectmenu widget instanciaion. + selectmenuWidgetInstance.refresh(); + } + return selectmenuWidgetInstance + } + /** + * Selectmenu widget common parameters for its configuration: options and callbacks. + */ + + // Selectmenu widget options + var selectmenuOptions = { + width: defaultSelectmenuWidth, + classes: { + 'ui-selectmenu-menu': 'pll-selectmenu-menu', + 'ui-selectmenu-button': 'pll-selectmenu-button', + } + }; + + // Selectmenu widget callbacks + var selectmenuFlagListCallbacks = {}; + // Callbacks when Selectmenu widget create or select event is triggered. + var createSelectCallback = function( event, ui ) { + selectmenuRefreshButtonText( event.target ); + } + + /** + * Overrides the flag dropdown list with our customized jquery ui selectmenu. + */ + + // Callbacks when Selectmenu widget change or open event is triggered. + // Needed to correctly refresh the selected element in the list when editing an existing language or when the value change is triggered by the language choice. + // jQuery UI 1.11 callback version. + var changeOpenCallback = function( event, ui ){ + selectmenuRefreshButtonText( $( event.target ).selectmenu( 'refresh' ) ); + } + // jQueryUI 1.12 callback version. + var changeOpenCallbackjQueryUI112 = function( event, ui ){ + // Just a refresh of the menu is needed with jQuery UI 1.12 because _renderButtonItem is triggered and then inject correctly the flag. + $( event.target ).selectmenu( 'refresh' ); + } + // There is no need of create and select callbacks with jQuery UI 1.12 because overriding _renderButtonItem method do the job. + if ( isJqueryUImin112 ) { + selectmenuFlagListCallbacks = + { + change: changeOpenCallbackjQueryUI112, + open: changeOpenCallbackjQueryUI112, + }; + } else { + selectmenuFlagListCallbacks = { + create: createSelectCallback, + select: createSelectCallback, + change: changeOpenCallback, + open: changeOpenCallback, + }; + } + + // Create the selectmenu widget only if the field is present. + if ( flagListExist ) { + // Create the jQuery UI selectmenu widget for flags list dropdown and return its instance. + var selectmenuFlagList = initializeSelectmenuWidget( $( '#flag_list' ), Object.assign( {}, selectmenuOptions, selectmenuFlagListCallbacks ) ); + $( '#lang_list' ).on( + 'languageChanged', + function( event, flag ) { + // Refresh the flag field + selectmenuFlagList.element.val( flag ); + selectmenuFlagList._trigger( 'change' ); + } + ); + } + + /** + * Language choice in predefined languages in Polylang Languages settings page and wizard. + * Overrides the predefined language dropdown list with our customized jQuery ui selectmenu widget. + */ + + /** + * Fill the other language form fields from the language element selected in the language list dropdown. + * + * @param {Object} language - language object of the selected element in the language list dropdown. + */ + function fillLanguageFields( language ) { + $( '#lang_slug' ).val( language.slug ); + $( '#lang_locale' ).val( language.locale ); + $( 'input[name="rtl"]' ).val( language.rtl ); + $( '#lang_name' ).val( language.name ); + } + + /** + * Parse selected language element in the language list dropdown. + * + * @param {object} event - jQuery triggered event. + * @return {object} The language object with its named properties. + */ + function parseSelectedLanguage( event ) { + var selectedElement = $('option:selected', event.target); + var values = selectedElement.val().split(':') + return { + slug: values[0], + locale: values[1], + rtl: [values[2]], + flag: values[3], + name: selectedElement.text().split(' - ')[0] // At the moment there is no need of the 2nd part because it corresponds on the locale which is already known by splitting the selected element value + }; + } + + // Callback when selectmenu widget change event is triggered. + var changeCallback = function( event, ui ) { + var language = parseSelectedLanguage( event ); + + fillLanguageFields( language ); + + $( event.target ).trigger( 'languageChanged', language.flag ); + }; + + // Create the jQuery UI selectmenu widget languages list dropdown and return its instance. + var selectmenuLangListCallbacks = {}; + // For the wizard we need a 100% width. So we override the previous defined value of selectmenuOptions. + if( $( '#lang_list' ).closest( '.pll-wizard-content' ).length > 0 ) { + selectmenuOptions = Object.assign( selectmenuOptions, { width: wizardSelectmenuWidth } ); + } + + // There is no need of create and select callbacks with jQuery UI 1.12 because overrinding _renderButtonItem method do the job. + if ( isJqueryUImin112 ) { + selectmenuLangListCallbacks = { + change: changeCallback, + }; + } else { + selectmenuLangListCallbacks = { + create: createSelectCallback, + select: createSelectCallback, + change: changeCallback, + }; + } + if ( langListExist ) { + initializeSelectmenuWidget( $( '#lang_list' ), Object.assign( {}, selectmenuOptions, selectmenuLangListCallbacks ) ); + } + + // strings translations + // save translations when pressing enter + $( '.translation input' ).on( + 'keydown', + function( event ){ + if ( 'Enter' === event.key ) { + event.preventDefault(); + $( '#submit' ).trigger( 'click' ); + } + } + ); + + // settings page + // click on configure link + $( '#the-list' ).on( + 'click', + '.configure>a', + function(){ + $( '.pll-configure' ).hide().prev().show(); + $( this ).closest( 'tr' ).hide().next().show(); + return false; + } + ); + + // cancel + $( '#the-list' ).on( + 'click', + '.cancel', + function(){ + $( this ).closest( 'tr' ).hide().prev().show(); + } + ); + + // save settings + $( '#the-list' ).on( + 'click', + '.save', + function(){ + var tr = $( this ).closest( 'tr' ); + var parts = tr.attr( 'id' ).split( '-' ); + + var data = { + action: 'pll_save_options', + pll_ajax_settings: true, + module: parts[parts.length - 1], + _pll_nonce: $( '#_pll_nonce' ).val() + }; + + data = tr.find( ':input' ).serialize() + '&' + $.param( data ); + + $.post( + ajaxurl, + data, + function( response ) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function() { + /** + * Fires after saving the settings, before applying changes to the DOM. + * + * @since 3.6.0 + * + * @param {Object} response The response from the AJAX call. + * @param {HTMLElement} tr The HTML element containing the fields. + */ + wp.hooks.doAction( 'pll_settings_saved', this, tr.get( 0 ) ); + + switch ( this.what ) { + case 'license-update': + $( '#pll-license-' + this.data ).replaceWith( this.supplemental.html ); + break; + case 'success': + tr.hide().prev().show(); // close only if there is no error + case 'error': + $( '.settings-error' ).remove(); // remove previous messages if any + $( 'h1' ).after( this.data ); + + // Make notices dismissible + // copy paste of common.js from WP 4.2.2 + $( '.notice.is-dismissible' ).each( + function() { + var $this = $( this ), + $button = $( '' ), + btnText = pll_admin.dismiss_notice || ''; + + // Ensure plain text + $button.find( '.screen-reader-text' ).text( btnText ); + + // Whitelist because of how the button is built. See above + $this.append( $button ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + $button.on( + 'click.wp-dismiss-notice', + function( event ) { + event.preventDefault(); + $this.fadeTo( + 100, + 0, + function() { + $( this ).slideUp( + 100, + function() { + $( this ).remove(); + } + ); + } + ); + } + ); + } + ); + break; + } + } + ); + } + ); + } + ); + + // act when pressing enter or esc in configurations + $( '.pll-configure' ).on( + 'keydown', + function( event ){ + if ( 'Enter' === event.key ) { + event.preventDefault(); + $( this ).find( '.save' ).trigger( 'click' ); + } + + if ( 'Escape' === event.key ) { + event.preventDefault(); + $( this ).find( '.cancel' ).trigger( 'click' ); + } + } + ); + + // settings URL modifications + // manages visibility of fields + $( "input[name='force_lang']" ).on( + 'change', + function() { + function pll_toggle( a, test ) { + test ? a.show() : a.hide(); + } + + var value = $( this ).val(); + pll_toggle( $( '#pll-domains-table' ), 3 == value ); + pll_toggle( $( "#pll-hide-default" ), 3 > value ); + pll_toggle( $( "#pll-rewrite" ), 2 > value ); + pll_toggle( $( "#pll-redirect-lang" ), 2 > value ); + } + ); + + // settings license + // deactivate button + $( '.pll-deactivate-license' ).on( + 'click', + function() { + var data = { + action: 'pll_deactivate_license', + pll_ajax_settings: true, + id: $( this ).attr( 'id' ), + _pll_nonce: $( '#_pll_nonce' ).val() + }; + $.post( + ajaxurl, + data, + function( response ){ + $( '#pll-license-' + response.id ).replaceWith( response.html ); + } + ); + } + ); + + // Manage closing the metabox. + // close postboxes that should be closed + $( '.if-js-closed' ).removeClass( 'if-js-closed' ).addClass( 'closed' ); + // postboxes setup + if ( 'undefined' !== typeof postboxes ) { + postboxes.add_postbox_toggles( pagenow ); + } + } +); + + diff --git a/wp-content/plugins/polylang-pro/js/build/admin.min.js b/wp-content/plugins/polylang-pro/js/build/admin.min.js new file mode 100644 index 000000000..9919e052b --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/admin.min.js @@ -0,0 +1 @@ +jQuery((function(e){var t;e("table.languages").on({focusin:function(){clearTimeout(t);var n=e(this).find(".row-actions");e(".row-actions").not(this).removeClass("visible"),n.addClass("visible")},focusout:function(){t=setTimeout((function(){focusedRowActions.removeClass("visible")}),30)}},"tr");var n=e.ui.version>="1.12.0",l=e("#flag_list").length,s=e("#lang_list").length,i=function(t,n){var l=e("
  • "),s=e("
    ");return n.disabled&&this._addClass(l,null,"ui-state-disabled"),this._setText(s,n.label),s.prepend(e(n.element).data("flag-html")),s.children("img").addClass("ui-icon"),l.append(s).appendTo(t)},a=function(t){var n=e(t).selectmenu("instance").buttonText;n.prepend(e(t).children(":selected").data("flag-html")),n.children("img").addClass("ui-icon")},c=function(t){var n=e("");return this._setText(n,t.label),this._addClass(n,"ui-selectmenu-text"),n.prepend(e(t.element).data("flag-html")),n.children("img").addClass("ui-icon"),n};function o(e,t){var l=e.selectmenu(t).selectmenu("instance");return l._renderItem=i,n&&(l._renderButtonItem=c,l.refresh()),l}var r={width:"95%",classes:{"ui-selectmenu-menu":"pll-selectmenu-menu","ui-selectmenu-button":"pll-selectmenu-button"}},u={},d=function(e,t){a(e.target)},p=function(t,n){a(e(t.target).selectmenu("refresh"))},g=function(t,n){e(t.target).selectmenu("refresh")};if(u=n?{change:g,open:g}:{create:d,select:d,change:p,open:p},l){var h=o(e("#flag_list"),Object.assign({},r,u));e("#lang_list").on("languageChanged",(function(e,t){h.element.val(t),h._trigger("change")}))}var f=function(t,n){var l=function(t){var n=e("option:selected",t.target),l=n.val().split(":");return{slug:l[0],locale:l[1],rtl:[l[2]],flag:l[3],name:n.text().split(" - ")[0]}}(t);!function(t){e("#lang_slug").val(t.slug),e("#lang_locale").val(t.locale),e('input[name="rtl"]').val(t.rtl),e("#lang_name").val(t.name)}(l),e(t.target).trigger("languageChanged",l.flag)},v={};e("#lang_list").closest(".pll-wizard-content").length>0&&(r=Object.assign(r,{width:"100%"})),v=n?{change:f}:{create:d,select:d,change:f},s&&o(e("#lang_list"),Object.assign({},r,v)),e(".translation input").on("keydown",(function(t){"Enter"===t.key&&(t.preventDefault(),e("#submit").trigger("click"))})),e("#the-list").on("click",".configure>a",(function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1})),e("#the-list").on("click",".cancel",(function(){e(this).closest("tr").hide().prev().show()})),e("#the-list").on("click",".save",(function(){var t=e(this).closest("tr"),n=t.attr("id").split("-"),l={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};l=t.find(":input").serialize()+"&"+e.param(l),e.post(ajaxurl,l,(function(n){var l=wpAjax.parseAjaxResponse(n,"pll-ajax-response");e.each(l.responses,(function(){switch(wp.hooks.doAction("pll_settings_saved",this,t.get(0)),this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each((function(){var t=e(this),n=e(''),l=pll_admin.dismiss_notice||"";n.find(".screen-reader-text").text(l),t.append(n),n.on("click.wp-dismiss-notice",(function(n){n.preventDefault(),t.fadeTo(100,0,(function(){e(this).slideUp(100,(function(){e(this).remove()}))}))}))}))}}))}))})),e(".pll-configure").on("keydown",(function(t){"Enter"===t.key&&(t.preventDefault(),e(this).find(".save").trigger("click")),"Escape"===t.key&&(t.preventDefault(),e(this).find(".cancel").trigger("click"))})),e("input[name='force_lang']").on("change",(function(){function t(e,t){t?e.show():e.hide()}var n=e(this).val();t(e("#pll-domains-table"),3==n),t(e("#pll-hide-default"),3>n),t(e("#pll-rewrite"),2>n),t(e("#pll-redirect-lang"),2>n)})),e(".pll-deactivate-license").on("click",(function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,(function(t){e("#pll-license-"+t.id).replaceWith(t.html)}))})),e(".if-js-closed").removeClass("if-js-closed").addClass("closed"),"undefined"!=typeof postboxes&&postboxes.add_postbox_toggles(pagenow)})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.js b/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.js new file mode 100644 index 000000000..629901897 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.js @@ -0,0 +1,924 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 419: +/***/ ((module) => { + +module.exports = (function() { return this["lodash"]; }()); + +/***/ }), + +/***/ 631: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["apiFetch"]; }()); + +/***/ }), + +/***/ 987: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["data"]; }()); + +/***/ }), + +/***/ 172: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["url"]; }()); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; + +// EXTERNAL MODULE: external {"this":["wp","apiFetch"]} +var external_this_wp_apiFetch_ = __webpack_require__(631); +var external_this_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_this_wp_apiFetch_); +// EXTERNAL MODULE: external {"this":["wp","data"]} +var external_this_wp_data_ = __webpack_require__(987); +// EXTERNAL MODULE: external "lodash" +var external_lodash_ = __webpack_require__(419); +// EXTERNAL MODULE: external {"this":["wp","url"]} +var external_this_wp_url_ = __webpack_require__(172); +;// ./modules/block-editor/js/sidebar/settings.js +/** + * Module Constants + * + * @package Polylang-Pro + */ + +const settings_MODULE_KEY = 'pll/metabox'; +const settings_MODULE_CORE_EDITOR_KEY = 'core/editor'; +const settings_MODULE_SITE_EDITOR_KEY = 'core/edit-site'; +const MODULE_POST_EDITOR_KEY = 'core/edit-post'; +const MODULE_CORE_KEY = 'core'; +const DEFAULT_STATE = { + languages: [], + selectedLanguage: {}, + translatedPosts: {}, + fromPost: null, + currentTemplatePart: {} +}; +const UNTRANSLATABLE_POST_TYPE = (/* unused pure expression or super */ null && (['wp_template', 'wp_global_styles'])); +const POST_TYPE_WITH_TRASH = (/* unused pure expression or super */ null && (['page'])); +const settings_TEMPLATE_PART_SLUG_SEPARATOR = '___'; // Its value must be synchronized with its equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR +const settings_TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN = '[a-z_-]+'; // Its value must be synchronized with it equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR + + +;// ./modules/block-editor/js/sidebar/utils.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + + +/** + * Internal dependencies + */ + + +/** + * Converts array of object to a map. + * + * @param {array} array Array to convert. + * @param {*} key The key in the object used as key to build the map. + * @returns {Map} + */ +function convertArrayToMap( array, key ){ + const map = new Map(); + array.reduce( + function (accumulator, currentValue) { + accumulator.set( currentValue[key], currentValue ); + return accumulator; + }, + map + ); + return map; +} + +/** + * Converts map to an associative array. + * + * @param {Map} map The map to convert. + * @returns {Object} + */ +function utils_convertMapToObject( map ){ + const object = {}; + map.forEach( + function ( value, key, map ) { + const obj = this; + this[key] = isBoolean( value ) ? value.toString() : value; + }, + object + ); + return object; +} + +/** + * Checks whether the current screen is block-based post type editor. + * + * @returns {boolean} True if block editor for post type; false otherwise. + */ +function isPostTypeBlockEditor() { + return !! document.getElementById( 'editor' ); +} + +/** + * Checks whether the current screen is the block-based widgets editor. + * + * @returns {boolean} True if we are in the widgets block editor; false otherwise. + */ +function isWidgetsBlockEditor() { + return !! document.getElementById( 'widgets-editor' ); +} + +/** + * Checks whether the current screen is the customizer widgets editor. + * + * @returns {boolean} True if we are in the customizer widgets editor; false otherwise. + */ +function isWidgetsCustomizerEditor() { + return !! document.getElementById( 'customize-controls' ); +} + + +/** + * Checks whether the current screen is the site editor. + * Takes in account if Gutenberg is activated. + * + * @returns {boolean} True if site editor screen, false otherwise. + */ +function isSiteBlockEditor() { + return !! ( document.getElementById( 'site-editor' ) || document.getElementById( 'edit-site-editor' ) ); +} + +/** + * Returns the post type URL for REST API calls or undefined if the user hasn't the rights. + * + * @param {string} name The post type name. + * @returns {string|undefined} + */ +function getPostsUrl( name ) { + const postTypes = (0,external_this_wp_data_.select)( 'core' ).getEntitiesByKind( 'postType' ); + const postType = (0,external_lodash_.find)( postTypes, { name } ); + return postType?.baseURL; +} + +/** + * Gets all query string parameters and convert them in a URLSearchParams object. + * + * @returns {Object} + */ +function utils_getSearchParams() { + // Variable window.location.search is just read for creating and returning a URLSearchParams object to be able to manipulate it more easily. + if ( ! isEmpty( window.location.search ) ) { // phpcs:ignore WordPressVIPMinimum.JS.Window.location + return new URLSearchParams( window.location.search ); // phpcs:ignore WordPressVIPMinimum.JS.Window.location + } else { + return null; + } +} + +/** + * Gets selected language. + * + * @param {string} lang The post language code. + * @returns {Object} The selected language. + */ +function getSelectedLanguage( lang ) { + const languages = select( MODULE_KEY ).getLanguages(); + // Pick up this language as selected in languages list + return languages.get( lang ); +} + +/** + * Gets the default language. + * + * @returns {Object} The default Language. + */ +function getDefaultLanguage() { + const languages = (0,external_this_wp_data_.select)( settings_MODULE_KEY ).getLanguages(); + return Array.from( languages.values() ).find( lang => lang.is_default ); +} + +/** + * Checks if the given language is the default one. + * + * @param {string} lang The language code to compare with. + * @returns {boolean} True if the given language is the default one. + */ +function isDefaultLanguage( lang ) { + return lang === getDefaultLanguage().slug; +} + +/** + * Gets translated posts. + * + * @param {Object} translations The translated posts object with language codes as keys and ids as values. + * @param {Object.} translations_table The translations table data with language codes as keys and data object as values. + * @returns {Map} + */ +function utils_getTranslatedPosts( translations, translations_table, lang ) { + const translationsTable = getTranslationsTable( translations_table, lang ); + const fromPost = select( MODULE_KEY ).getFromPost(); + let translatedPosts = new Map( Object.entries( [] ) ); + if ( ! isUndefined( translations ) ) { + translatedPosts = new Map( Object.entries( translations ) ); + } + // If we come from another post for creating a new one, we have to update translated posts from the original post + // to be able to update translations attribute of the post + if ( ! isNil( fromPost ) && ! isNil( fromPost.id ) ) { + translationsTable.forEach( + ( translationData, lang ) => { + if ( ! isNil( translationData.translated_post ) && ! isNil( translationData.translated_post.id ) ) { + translatedPosts.set( lang, translationData.translated_post.id ); + } + } + ); + } + return translatedPosts; +} + +/** + * Gets synchronized posts. + * + * @param {Object.} pll_sync_post The synchronized posts object with language codes as keys and boolean values to say if the post is synchronized or not. + * @returns {Map} + */ +function getSynchronizedPosts( pll_sync_post ){ + let synchronizedPosts = new Map( Object.entries( [] ) ); + if ( ! isUndefined( pll_sync_post ) ) { + synchronizedPosts = new Map( Object.entries( pll_sync_post ) ); + } + return synchronizedPosts; +} + +/** + * Gets translations table. + * + * @param {Object.} translationsTableDatas The translations table data object with language codes as keys and data object as values. + * @returns {Map} + */ +function getTranslationsTable( translationsTableDatas ){ + let translationsTable = new Map( Object.entries( [] ) ); + // get translations table datas from post + if ( ! isUndefined( translationsTableDatas ) ) { + // Build translations table map with language slug as key + translationsTable = new Map( Object.entries( translationsTableDatas ) ); + } + return translationsTable; +} + +/** + * Checks if the given request is for saving. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request is for saving. + */ +function isSaveRequest( options ){ + // If data is defined we are in a PUT or POST request method otherwise a GET request method + // Test options.method property isn't efficient because most of REST request which use fetch API doesn't pass this property. + // So, test options.data is necessary to know if the REST request is to save datas. + // However test if options.data is undefined isn't sufficient because some REST request pass a null value as the ServerSideRender Gutenberg component. + if ( ! (0,external_lodash_.isNil)( options.data ) ) { + return true; + } else { + return false; + } +} + +/** + * Checks if the given request concerns the current post type. + * + * Useful when saving a reusable block contained in another post type. + * Indeed a reusable block is also a post, but its saving request doesn't concern the post currently edited. + * As we don't know the language of the reusable block when the user triggers the reusable block saving action, + * we need to pass the current post language to be sure that the reusable block will have a language. + * + * @see https://github.com/polylang/polylang/issues/437 - Reusable block has no language when it's saved from another post type editing. + * + * @param {Object} options the initial request + * @returns {boolean} True if the request concerns the current post. + */ +function isCurrentPostRequest( options ){ + // Saving translation data is needed only for all post types. + // It's done by verifying options.path matches with one of baseURL of all post types + // and compare current post id with this sent in the request. + + // List of post type baseURLs. + const postTypeURLs = (0,external_lodash_.map)( (0,external_this_wp_data_.select)( 'core' ).getEntitiesByKind( 'postType' ), (0,external_lodash_.property)( 'baseURL' ) ); + + // Id from the post currently edited. + const postId = (0,external_this_wp_data_.select)( 'core/editor' ).getCurrentPostId(); + + // Id from the REST request. + // options.data never isNil here because it's already verified before in isSaveRequest() function. + const id = options.data.id; + + // Return true + // if REST request baseURL matches with one of the known post type baseURLs + // and the id from the post currently edited corresponds on the id passed to the REST request + // Return false otherwise + return -1 !== postTypeURLs.findIndex( + function ( element ) { + return new RegExp( `${ (0,external_lodash_.escapeRegExp)( element ) }` ).test( options.path ); + } + ) && postId === id; +} + +/** + * Checks if the given REST request is for the creation of a new template part translation. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part translation creation. + */ +function isTemplatePartTranslationCreationRequest( options ) { + return 'POST' === options.method + && options.path.match( /^\/wp\/v2\/template-parts(?:\/|\?|$)/ ) + && ! (0,external_lodash_.isNil)( options.data.from_post ) + && ! (0,external_lodash_.isNil)( options.data.lang ); +} + +/** + * Checks if the given REST request is for the creation of a new template part. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part creation. + */ +function isNewTemplatePartCreationRequest( options ) { + return 'POST' === options.method + && options.path.match( /^\/wp\/v2\/template-parts(?:\/|\?|$)/ ) + && (0,external_lodash_.isNil)( options.data.from_post ) + && (0,external_lodash_.isNil)( options.data.lang ); +} + +/** + * Adds language as query string parameter to the given request. + * + * @param {Object} options The initial request. + * @param {string} currentLanguage The language code to add to the request. + */ +function addLanguageToRequest( options, currentLanguage ){ + const hasLangArg= (0,external_this_wp_url_.hasQueryArg)( options.path, 'lang' ); + const filterLang = (0,external_lodash_.isUndefined)( options.filterLang ) || options.filterLang; + if ( filterLang && ! hasLangArg ) { + options.path = (0,external_this_wp_url_.addQueryArgs)( + options.path, + { + lang: currentLanguage + } + ); + } +} + +/** + * Adds `include_untranslated` parameter to the request. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function addIncludeUntranslatedParam( options ) { + options.path = (0,external_this_wp_url_.addQueryArgs)( + options.path, + { + include_untranslated: true + } + ); +} + +/** + * Use addIncludeUntranslatedParam if the given page is a template part page. + * Or if the template editing mode is enabled inside post editing. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function maybeRequireIncludeUntranslatedTemplate( options ) { + const params = ( new URL( document.location ) ).searchParams; + const postType = params.get( 'postType' ); + const postId = params.get( 'postId' ); + const isEditingTemplate = (0,external_this_wp_data_.select)( MODULE_POST_EDITOR_KEY )?.isEditingTemplate(); + if ( ( "wp_template_part" === postType && ! (0,external_lodash_.isNil)( postId ) ) || isEditingTemplate ) { + addIncludeUntranslatedParam( options ); + } +} + +/** + * Returns true if the given post is a template part, false otherwise. + * + * @param {Object} post A post object. + * @returns {boolean} Whether it is a template part or not. + */ +function isTemplatePart( post ) { + return 'wp_template_part' === post.type; +} + +/** + * Returns the current post type considering the Site Editor or Post Editor. + * + * @returns {string} The current post type. + */ +function getCurrentPostType() { + if ( isSiteBlockEditor() ) { + return (0,external_this_wp_data_.select)( settings_MODULE_SITE_EDITOR_KEY ).getEditedPostType(); + } + + return (0,external_this_wp_data_.select)( settings_MODULE_CORE_EDITOR_KEY ).getCurrentPostType(); +} + +/** + * Returns a regular expression ready to use to perform search and replace. + * + * @returns {RegExp} The regular expression. + */ +function getLangSlugRegex() { + let languageCheckPattern = TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN; + const languages = select( MODULE_KEY ).getLanguages(); + const languageSlugs = Array.from( languages.keys() ); + if ( ! isEmpty( languageSlugs ) ) { + languageCheckPattern = languageSlugs.join( '|' ); + } + + return new RegExp( `${TEMPLATE_PART_SLUG_SEPARATOR}(?:${languageCheckPattern})$` ); +} + +;// ./modules/block-editor/js/sidebar/store/utils.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + +/** + * Internal dependencies + */ + + + +/** + * Wait for the whole post block editor context has been initialized: current post loaded and languages list initialized. + */ +const isBlockPostEditorContextInitialized = () => { + if ( isNil( select( MODULE_CORE_EDITOR_KEY ) ) ) { + return Promise.reject( "Polylang languages panel can't be initialized because block editor isn't fully initialized." ); + } + + // save url params espacially when a new translation is creating + saveURLParams(); + // call to getCurrentUser to force call to resolvers and initialize state + const currentUser = select( MODULE_KEY ).getCurrentUser(); + + /** + * Set a promise for waiting for the current post has been fully loaded before making other processes. + */ + const isCurrentPostLoaded = new Promise( + function ( resolve ) { + let unsubscribe = subscribe( + function () { + const currentPost = select( MODULE_CORE_EDITOR_KEY ).getCurrentPost(); + if ( ! isEmpty( currentPost ) ) { + unsubscribe(); + resolve(); + } + } + ); + } + ); + + // Wait for current post has been loaded and languages list initialized. + return Promise.all( [ isCurrentPostLoaded, isLanguagesinitialized() ] ).then( + function () { + // If we come from another post for creating a new one, we have to update translations from the original post. + const fromPost = select( MODULE_KEY ).getFromPost(); + if ( ! isNil( fromPost ) && ! isNil( fromPost.id ) ) { + const lang = select( MODULE_CORE_EDITOR_KEY ).getEditedPostAttribute( 'lang' ); + const translations = select( MODULE_CORE_EDITOR_KEY ).getEditedPostAttribute( 'translations' ); + const translations_table = select( MODULE_CORE_EDITOR_KEY ).getEditedPostAttribute( 'translations_table' ); + const translatedPosts = getTranslatedPosts( translations, translations_table, lang ); + dispatch( MODULE_CORE_EDITOR_KEY ).editPost( { translations: convertMapToObject( translatedPosts ) } ); + } + } + ); +} + +/** + * Wait for the whole site editor context to be initialized: current template loaded and languages list initialized. + */ +const isSiteEditorContextInitialized = () => { + // save url params espacially when a new translation is creating + saveURLParams(); + // call to getCurrentUser to force call to resolvers and initialize state + const currentUser = select( MODULE_KEY ).getCurrentUser(); + + /** + * Set a promise to wait for the current template to be fully loaded before making other processes. + * It allows to see if both Site Editor and Core stores are available (@see getCurrentPostFromDataStore()). + */ + const isTemplatePartLoaded = new Promise( + function ( resolve ) { + let unsubscribe = subscribe( + function () { + const store = select( MODULE_SITE_EDITOR_KEY ); + if ( store ) { + unsubscribe(); + resolve(); + } + } + ); + } + ); + + return Promise.all( [ isTemplatePartLoaded, isLanguagesinitialized() ] ); +} + +/** + * Returns a promise fulfilled when the languages list is correctly initialized before making other processes. + */ +const isLanguagesinitialized = () => new Promise( + function ( resolve ) { + let unsubscribe = subscribe( + function () { + const languages = select( MODULE_KEY )?.getLanguages(); + if ( languages?.size > 0 ) { + unsubscribe(); + resolve(); + } + } + ); + } +); + +/** + * Save query string parameters from URL. They could be needed after + * They could be null if they does not exist + */ +function saveURLParams(){ + // Variable window.location.search isn't use directly + // Function getSearchParams return an URLSearchParams object for manipulating each parameter + // Each of them are sanitized below + const searchParams = getSearchParams(); + if ( null !== searchParams ) { + dispatch( MODULE_KEY ).setFromPost( + { + id: wp.sanitize.stripTagsAndEncodeText( searchParams.get( 'from_post' ) ), + postType: wp.sanitize.stripTagsAndEncodeText( searchParams.get( 'post_type' ) ), + newLanguage: wp.sanitize.stripTagsAndEncodeText( searchParams.get( 'new_lang' ) ) + } + ); + } +} + +const getEditedPostContextWithLegacy = () => { + const siteEditorSelector = (0,external_this_wp_data_.select)( settings_MODULE_SITE_EDITOR_KEY ); + + /** + * Return null when called from our apiFetch middleware without a properly loaded store. + */ + if ( ! siteEditorSelector ) { + return null; + } + + const _context = { + postId: siteEditorSelector.getEditedPostId(), + postType: siteEditorSelector.getEditedPostType() + } + + if ( siteEditorSelector.hasOwnProperty( 'getEditedPostContext' ) ) { + const context = siteEditorSelector.getEditedPostContext(); + + return context?.postType && context?.postId + ? context + : _context; + } + + /** + * Backward compatibility with WordPress < 6.3 where `getEditedPostContext()` doesn't exist yet. + */ + return _context; +} + +/** + * Gets the current post using the Site Editor store and the Core store. + * + * @returns {object|null} The current post object, `null` if none found. + */ +const getCurrentPostFromDataStore = () => { + const editedContext = getEditedPostContextWithLegacy(); + + return null === editedContext + ? null + : (0,external_this_wp_data_.select)( MODULE_CORE_KEY ).getEntityRecord( + 'postType', + editedContext.postType, + editedContext.postId + ); +} + +;// ./modules/block-editor/js/middleware/filter-path-middleware.js +/** + * @package Polylang Pro + */ + +/** + * Filters requests for translatable entities. + * This logic is shared accross all Polylang plugins. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @param {Array} filteredRoutes + * @param {CallableFunction} filter + * @returns {APIFetchOptions} + */ +const filterPathMiddleware = ( options, filteredRoutes, filter ) => { + const cleanPath = options.path.split( '?' )[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'. + + return Object.values( filteredRoutes ).find( ( path ) => cleanPath === path ) ? filter( options ) : options; +} + +/* harmony default export */ const filter_path_middleware = (filterPathMiddleware); + +;// ./modules/block-editor/js/block-editor-plugin.js +/** + * WordPress dependencies + * + * @package Polylang-Pro + */ + + + + +/** + * External dependencies + */ + + +/** + * Internal dependencies + */ + + + + + +/* + * Initializes a block editor apiFetch middleware to be able to filter REST API requests. + */ +external_this_wp_apiFetch_default().use( + ( options, next ) => { + /* + * If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes. + * If `filteredRoutes` is not defined, return early. + */ + if ( 'undefined' !== typeof options.url || 'undefined' === typeof pllFilteredRoutes ) { + return next( options ); + } + + return next( filter_path_middleware( options, pllFilteredRoutes, addParametersToRequest ) ); + } +); + +/** + * Adds parameters according to the context of the request. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @returns {APIFetchOptions} + */ +const addParametersToRequest = ( options ) => { + const currentLangSlug = getCurrentLanguageSlug(); + + // `POST` or `PUT` request. + if ( isSaveRequest( options ) ) { + /** + * Use default language for new template part that doesn't exist in any language, + * otherwise use the current language. + */ + if ( isNewTemplatePartCreationRequest( options ) ) { + addLanguageToRequest( options, getDefaultLanguage()?.slug ); + } + + if ( ! isCurrentPostRequest( options ) && ! isTemplatePartTranslationCreationRequest( options ) ) { + addLanguageToRequest( options, currentLangSlug ); + } + + maybeAddLangSuffixToTemplatePart( options, currentLangSlug ); + + return options; + } + + const currentPostType = getCurrentPostType(); + + // Current language is set to default when editing templates. + if ( 'wp_template' === currentPostType ) { + addLanguageToRequest( options, getDefaultLanguage()?.slug ); + } + + const templatePartListRegex = new RegExp( /^\/wp\/v2\/template-parts\/?(?:\?.*)?$/ ); + + // Template part list request. + if ( templatePartListRegex.test( options.path ) ) { + maybeRequireIncludeUntranslatedTemplate( options ); + } + + // All kinds of requests. + addLanguageToRequest( options, currentLangSlug ); + + return options; +} + +/** + * Gets language from store or a fallback javascript global variable. + * + * @returns {string} + */ +function getCurrentLanguageSlug(){ + if ( (0,external_lodash_.isUndefined)( (0,external_this_wp_data_.select)( settings_MODULE_CORE_EDITOR_KEY ) ) ) { + // Return ASAP to avoid issues later. + return pll_block_editor_plugin_settings.lang.slug; + } + + // Post block editor case. + const postLanguage = (0,external_this_wp_data_.select)( settings_MODULE_CORE_EDITOR_KEY ).getEditedPostAttribute( 'lang' ); + if ( ! (0,external_lodash_.isUndefined)( postLanguage ) && postLanguage ) { + return postLanguage; + } + + // Returns the default lang if the current location is a template part list + // and update pll_block_editor_plugin_settings at the same time. + const params = ( new URL( document.location ) ).searchParams; + const postType = params.get( 'postType' ); + const postId = params.get( 'postId' ); + if ( "wp_template_part" === postType && (0,external_lodash_.isNil)( postId ) ) { + pll_block_editor_plugin_settings.lang = getDefaultLanguage(); + + return pll_block_editor_plugin_settings.lang.slug; + } + + // FSE template editor case. + const template = getCurrentPostFromDataStore(); + const templateLanguage = template?.lang; + if ( ! (0,external_lodash_.isUndefined)( templateLanguage ) && templateLanguage ) { + return templateLanguage; + } + + // For the first requests block editor isn't initialized yet. + // So language is retrieved from a javascript global variable initialized server-side. + return pll_block_editor_plugin_settings.lang.slug; +} + +/** + * Adds the language suffix to a template part only during creation. + * + * @param {object} options Object representing a REST request. + * @param {string} langSlug The Language slug to add. + * @return {void} + */ +function maybeAddLangSuffixToTemplatePart( options, langSlug ){ + const restBaseUrl = getPostsUrl( 'wp_template_part' ); + if ( (0,external_lodash_.isUndefined)( restBaseUrl ) ) { + // The user hasn't the rights to edit template part. + return; + } + const templatePartURLRegExp = new RegExp( (0,external_lodash_.escapeRegExp)( restBaseUrl ) ); + if ( 'POST' == options.method && templatePartURLRegExp.test( options.path ) ) { + const languages = (0,external_this_wp_data_.select)( settings_MODULE_KEY ).getLanguages(); + const language = languages.get( langSlug ); + + if ( ! language.is_default ) { + // No suffix for default language. + const langSuffix = settings_TEMPLATE_PART_SLUG_SEPARATOR + langSlug; + options.data.slug += langSuffix; + } + } +} + +// Duplicate code of PLL_Admin_Base::admin_print_footer_scripts() to add lang parameter in admin ajax requests in FSE. +if ( typeof jQuery != 'undefined' ) { + jQuery( + function ( $ ) { + $.ajaxPrefilter( function ( options, originalOptions, jqXHR ) { + if ( -1 != options.url.indexOf( ajaxurl ) || -1 != ajaxurl.indexOf( options.url ) ) { + + const currentLanguage = getCurrentLanguageSlug(); + const arr = { 'lang' : currentLanguage }; + + function addPolylangParametersAsString() { + const str = 'lang=' + currentLanguage; + if ( 'undefined' === typeof options.data || '' === options.data.trim() ) { + // Only Polylang data need to be send. So it could be as a simple query string. + options.data = str; + } else { + /* + * In some cases data could be a JSON string like in third party plugins. + * So we need not to break their process by adding polylang parameters as valid JSON datas. + */ + try { + options.data = JSON.stringify( Object.assign( JSON.parse( options.data ), arr ) ); + } catch ( exception ) { + // Add Polylang data to the existing query string. + options.data = options.data + '&' + str; + } + } + } + + /* + * options.processData set to true is the default jQuery process where the data is converted in a query string by using jQuery.param(). + * This step is done before applying filters. Thus here the options.data is already a string in this case. + * @See https://github.com/jquery/jquery/blob/3.5.1/src/ajax.js#L563-L569 jQuery ajax function. + * It is the most case WordPress send ajax request this way however third party plugins or themes could be send JSON string. + * Use JSON format is recommended in jQuery.param() documentation to be able to send complex data structures. + * @See https://api.jquery.com/jquery.param/ jQuery param function. + */ + if ( options.processData ) { + addPolylangParametersAsString(); + } else { + /* + * If options.processData is set to false data could be undefined or pass as a string. + * So data as to be processed as if options.processData is set to true. + */ + if ( 'undefined' === typeof options.data || 'string' === typeof options.data ) { + addPolylangParametersAsString(); + } else { + // Otherwise options.data is probably an object. + options.data = Object.assign( options.data || {} , arr ); + } + } + } + }); + } + ); +} + +})(); + +this["polylang-pro"] = __webpack_exports__; +/******/ })() +; \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.min.js b/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.min.js new file mode 100644 index 000000000..e599c732f --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/block-editor-plugin.min.js @@ -0,0 +1 @@ +(()=>{var t={419:t=>{t.exports=function(){return this.lodash}()},631:t=>{t.exports=function(){return this.wp.apiFetch}()},987:t=>{t.exports=function(){return this.wp.data}()},172:t=>{t.exports=function(){return this.wp.url}()}},e={};function n(s){var r=e[s];if(void 0!==r)return r.exports;var a=e[s]={exports:{}};return t[s](a,a.exports,n),a.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var s in e)n.o(e,s)&&!n.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:e[s]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);(()=>{"use strict";var t=n(631),e=n.n(t),s=n(987),r=n(419),a=n(172);const o="pll/metabox",i="core/editor",p="core/edit-site";function l(){const t=(0,s.select)(o).getLanguages();return Array.from(t.values()).find((t=>t.is_default))}function d(t,e){const n=(0,a.hasQueryArg)(t.path,"lang");((0,r.isUndefined)(t.filterLang)||t.filterLang)&&!n&&(t.path=(0,a.addQueryArgs)(t.path,{lang:e}))}function u(t){const e=new URL(document.location).searchParams,n=e.get("postType"),o=e.get("postId"),i=(0,s.select)("core/edit-post")?.isEditingTemplate();("wp_template_part"===n&&!(0,r.isNil)(o)||i)&&function(t){t.path=(0,a.addQueryArgs)(t.path,{include_untranslated:!0})}(t)}function c(){return document.getElementById("site-editor")||document.getElementById("edit-site-editor")?(0,s.select)(p).getEditedPostType():(0,s.select)(i).getCurrentPostType()}const g=()=>{const t=(()=>{const t=(0,s.select)(p);if(!t)return null;const e={postId:t.getEditedPostId(),postType:t.getEditedPostType()};if(t.hasOwnProperty("getEditedPostContext")){const n=t.getEditedPostContext();return n?.postType&&n?.postId?n:e}return e})();return null===t?null:(0,s.select)("core").getEntityRecord("postType",t.postType,t.postId)},f=(t,e,n)=>{const s=t.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(e).find((t=>s===t))?n(t):t};e().use(((t,e)=>void 0!==t.url||"undefined"==typeof pllFilteredRoutes?e(t):e(f(t,pllFilteredRoutes,y))));const y=t=>{const e=_();if(function(t){return!(0,r.isNil)(t.data)}(t))return function(t){return"POST"===t.method&&t.path.match(/^\/wp\/v2\/template-parts(?:\/|\?|$)/)&&(0,r.isNil)(t.data.from_post)&&(0,r.isNil)(t.data.lang)}(t)&&d(t,l()?.slug),function(t){const e=(0,r.map)((0,s.select)("core").getEntitiesByKind("postType"),(0,r.property)("baseURL")),n=(0,s.select)("core/editor").getCurrentPostId(),a=t.data.id;return-1!==e.findIndex((function(e){return new RegExp(`${(0,r.escapeRegExp)(e)}`).test(t.path)}))&&n===a}(t)||function(t){return"POST"===t.method&&t.path.match(/^\/wp\/v2\/template-parts(?:\/|\?|$)/)&&!(0,r.isNil)(t.data.from_post)&&!(0,r.isNil)(t.data.lang)}(t)||d(t,e),function(t,e){const n=function(t){const e=(0,s.select)("core").getEntitiesByKind("postType"),n=(0,r.find)(e,{name:t});return n?.baseURL}("wp_template_part");if((0,r.isUndefined)(n))return;const a=new RegExp((0,r.escapeRegExp)(n));if("POST"==t.method&&a.test(t.path)){if(!(0,s.select)(o).getLanguages().get(e).is_default){const n="___"+e;t.data.slug+=n}}}(t,e),t;"wp_template"===c()&&d(t,l()?.slug);return new RegExp(/^\/wp\/v2\/template-parts\/?(?:\?.*)?$/).test(t.path)&&u(t),d(t,e),t};function _(){if((0,r.isUndefined)((0,s.select)(i)))return pll_block_editor_plugin_settings.lang.slug;const t=(0,s.select)(i).getEditedPostAttribute("lang");if(!(0,r.isUndefined)(t)&&t)return t;const e=new URL(document.location).searchParams,n=e.get("postType"),a=e.get("postId");if("wp_template_part"===n&&(0,r.isNil)(a))return pll_block_editor_plugin_settings.lang=l(),pll_block_editor_plugin_settings.lang.slug;const o=g(),p=o?.lang;return!(0,r.isUndefined)(p)&&p?p:pll_block_editor_plugin_settings.lang.slug}"undefined"!=typeof jQuery&&jQuery((function(t){t.ajaxPrefilter((function(t,e,n){if(-1!=t.url.indexOf(ajaxurl)||-1!=ajaxurl.indexOf(t.url)){const s=_(),r={lang:s};function a(){const e="lang="+s;if(void 0===t.data||""===t.data.trim())t.data=e;else try{t.data=JSON.stringify(Object.assign(JSON.parse(t.data),r))}catch(n){t.data=t.data+"&"+e}}t.processData||void 0===t.data||"string"==typeof t.data?a():t.data=Object.assign(t.data||{},r)}}))}))})(),this["polylang-pro"]={}})(); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/block-editor.js b/wp-content/plugins/polylang-pro/js/build/block-editor.js new file mode 100644 index 000000000..ffbeb84ec --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/block-editor.js @@ -0,0 +1,405 @@ +/******/ "use strict"; + +;// ./vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js +/** + * @package Polylang + */ + +const languagesList = jQuery( '.post_lang_choice' ); + +// Dialog box for alerting the user about a risky changing. +const initializeConfirmationModal = () => { + // We can't use underscore or lodash in this common code because it depends of the context classic or block editor. + // Classic editor underscore is loaded, Block editor lodash is loaded. + const { __ } = wp.i18n; + + // Create dialog container. + const dialogContainer = jQuery( + '
    ', + { + id: 'pll-dialog', + style: 'display:none;' + } + ).text( __( 'Are you sure you want to change the language of the current content?', 'polylang' ) ); + + // Put it after languages list dropdown. + // PHPCS ignore dialogContainer is a new safe HTML code generated above. + languagesList.after( dialogContainer ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + + const dialogResult = new Promise( + ( confirm, cancel ) => { + const confirmDialog = ( what ) => { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + switch ( what ) { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + case 'yes': + // Confirm the new language. + languagesList.data( 'old-value', languagesList.children( ':selected' ).first().val() ); + confirm(); + break; + case 'no': + // Revert to the old language. + languagesList.val( languagesList.data( 'old-value' ) ); + cancel( 'Cancel' ); + break; + } + dialogContainer.dialog( 'close' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + } // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + // Initialize dialog box in the case a language is selected but not added in the list. + const dialogOptions = { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: __( 'Change language', 'polylang' ), + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( jQuery( 'body' ).hasClass( 'rtl' ) ) { + jQuery( this ).parent().css( + { + right: jQuery( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + }, + close: function ( event, ui ) { + // When we're closing the dialog box we need to cancel the language change as we click on Cancel button. + confirmDialog( 'no' ); + }, + buttons: [ + { + text: __( 'OK', 'polylang' ), + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: __( 'Cancel', 'polylang' ), + click: function ( event ) { + confirmDialog( 'no' ); + } + } + ] + }; + + if ( jQuery.ui.version >= '1.12.0' ) { + Object.assign( dialogOptions, { classes: { 'ui-dialog': 'pll-confirmation-modal' } } ); + } else { + Object.assign( dialogOptions, { dialogClass: 'pll-confirmation-modal' } ); // jQuery UI 1.11.4 - WP < 5.6 + } + + dialogContainer.dialog( dialogOptions ); + } + ); + return { dialogContainer, dialogResult }; +} + +const initializeLanguageOldValue = () => { + // Keep the old language value to be able to compare to the new one and revert to it if necessary. + languagesList.attr( 'data-old-value', languagesList.children( ':selected' ).first().val() ); +}; + +;// ./vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js +/** + * @package Polylang + */ + +// Translations autocomplete input box. +function initMetaboxAutoComplete() { + jQuery('.tr_lang').each( + function () { + var tr_lang = jQuery(this).attr('id').substring(8); + var td = jQuery(this).parent().parent().siblings('.pll-edit-column'); + + jQuery(this).autocomplete( + { + minLength: 0, + source: ajaxurl + '?action=pll_posts_not_translated' + + '&post_language=' + jQuery('.post_lang_choice').val() + + '&translation_language=' + tr_lang + + '&post_type=' + jQuery('#post_type').val() + + '&_pll_nonce=' + jQuery('#_pll_nonce').val(), + select: function (event, ui) { + jQuery('#htr_lang_' + tr_lang).val(ui.item.id); + // ui.item.link is built and come from server side and is well escaped when necessary + td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + }, + } + ); + + // when the input box is emptied + jQuery(this).on( + 'blur', + function () { + if ( ! jQuery(this).val() ) { + jQuery('#htr_lang_' + tr_lang).val(0); + // Value is retrieved from HTML already generated server side + td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + } + ); + } + ); +} + +;// ./vendor/wpsyntex/polylang/js/src/lib/filter-path-middleware.js +/** + * @package Polylang + */ + +/** + * Filters requests for translatable entities. + * This logic is shared across all Polylang plugins. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @param {Array} filteredRoutes + * @param {CallableFunction} filter + * @returns {APIFetchOptions} + */ +const filterPathMiddleware = ( options, filteredRoutes, filter ) => { + const cleanPath = options.path.split( '?' )[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'. + + return Object.values( filteredRoutes ).find( ( path ) => cleanPath === path ) ? filter( options ) : options; +} + +/* harmony default export */ const filter_path_middleware = (filterPathMiddleware); + +;// ./vendor/wpsyntex/polylang/js/src/block-editor.js +/** + * @package Polylang + */ + + + + + + + +/** + * Filter REST API requests to add the language in the request + * + * @since 2.5 + */ +wp.apiFetch.use( + function ( options, next ) { + /* + * If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes. + * If `filteredRoutes` is not defined, return early. + */ + if ( 'undefined' !== typeof options.url || 'undefined' === typeof pllFilteredRoutes ) { + return next( options ); + } + + return next( filter_path_middleware( options, pllFilteredRoutes, addLanguageParameter ) ); + } +); + +/** + * Gets the language of the currently edited post, fallback to default language if none is found. + * + * @since 2.5 + * + * @return {Element.value} + */ +function getCurrentLanguage() { + const lang = document.querySelector( '[name=post_lang_choice]' ); + + if ( null === lang ) { + return pllDefaultLanguage; + } + + return lang.value; +} + +/** + * Adds language parameter according to the current one (query string for GET, body for PUT and POST). + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @returns {APIFetchOptions} + */ +function addLanguageParameter( options ) { + if ( 'undefined' === typeof options.data || null === options.data ) { + // GET + options.path += ( ( options.path.indexOf( '?' ) >= 0 ) ? '&lang=' : '?lang=' ) + getCurrentLanguage(); + } else { + // PUT, POST + options.data.lang = getCurrentLanguage(); + } + + return options; +} + +/** + * Handles internals of the metabox: + * Language select, autocomplete input field. + * + * @since 1.5 + * + * Save post after lang choice is done and redirect to the same page for refreshing all the data. + * + * @since 2.5 + * + * Link post saving after refreshing the metabox. + * + * @since 3.0 + */ +jQuery( + function ( $ ) { + // Initialize current language to be able to compare if it changes. + initializeLanguageOldValue(); + + + // Ajax for changing the post's language in the languages metabox + $( '.post_lang_choice' ).on( + 'change', + function ( event ) { + const { select, dispatch, subscribe } = wp.data; + const emptyPost = isEmptyPost(); + const { addQueryArgs } = wp.url; + + // Initialize the confirmation dialog box. + const confirmationModal = initializeConfirmationModal(); + const { dialogContainer : dialog } = confirmationModal; + let { dialogResult } = confirmationModal; + const selectedOption = event.target; // The selected option in the dropdown list. + + // Specific case for empty posts. + // Place at the beginning because window.location change triggers automatically page reloading. + if ( location.pathname.match( /post-new.php/gi ) && emptyPost ) { + reloadPageForEmptyPost( selectedOption.value ); + } + + // Otherwise send an ajax request to refresh the legacy metabox and set the post language with the new language. + // It needs a confirmation of the user before changing the language. + // Need to wait the ajax response before triggering the block editor post save action. + if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! emptyPost ) { + dialog.dialog( 'open' ); + } else { + // Update the old language with the new one to be able to compare it in the next change. + // Because the page isn't reloaded in this case. + initializeLanguageOldValue(); + dialogResult = Promise.resolve(); + } + + dialogResult.then( + () => { + let data = { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + action: 'post_lang_choice', + lang: selectedOption.value, + post_type: $( '#post_type' ).val(), + post_id: $( '#post_ID' ).val(), + _pll_nonce: $( '#_pll_nonce' ).val() + } + + // Update post language in database as soon as possible. + // Because, in addition of the block editor save process, the legacy metabox uses a post.php process to update the language and is too late compared to the page reload. + $.post( + ajaxurl, + data, + function () { + blockEditorSavePostAndReloadPage(); + } + ); + }, + () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button. + ); + + function isEmptyPost() { + const editor = select( 'core/editor' ); + + return ! editor.getEditedPostAttribute( 'title' )?.trim() && ! editor.getEditedPostContent() && ! editor.getEditedPostAttribute( 'excerpt' )?.trim(); + } + + /** + * Reload the block editor page for empty posts. + * + * @param {string} lang The target language code. + */ + function reloadPageForEmptyPost( lang ) { + // Change the new_lang parameter with the new language value for reloading the page + // WPCS location.search is never written in the page, just used to reload page with the right value of new_lang + // new_lang input is controlled server side in PHP. The value come from the dropdown list of language returned and escaped server side. + // Notice that window.location changing triggers automatically page reloading. + if ( -1 != location.search.indexOf( 'new_lang' ) ) { + // use regexp non capturing group to replace new_lang parameter no matter where it is and capture other parameters which can be behind it + window.location.search = window.location.search.replace( /(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + lang + '$1$2' ); // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment + } else { + window.location.search = window.location.search + ( ( -1 != window.location.search.indexOf( '?' ) ) ? '&' : '?' ) + 'new_lang=' + lang; // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment + } + }; + + /** + * Triggers block editor post save and reload the block editor page when everything is ok. + */ + function blockEditorSavePostAndReloadPage() { + + let unsubscribe = null; + const previousPost = select( 'core/editor').getCurrentPost(); + + // Listen if the savePost is completely done by subscribing to its events. + const savePostIsDone = new Promise( + function ( resolve, reject ) { + unsubscribe = subscribe( + function () { + const post = select( 'core/editor').getCurrentPost(); + const { id, status, type } = post; + const error = select( 'core' ) + .getLastEntitySaveError( + 'postType', + type, + id + ); + + if ( error ) { + reject(); + } + + if ( previousPost.modified !== post.modified ) { + + if ( location.pathname.match( /post-new.php/gi ) && status !== 'auto-draft' && id ) { + window.history.replaceState( + { id }, + 'Post ' + id, + addQueryArgs( 'post.php', { post: id, action: 'edit' } ) + ); + } + resolve(); + } + } + ); + } + ); + + // Triggers the post save. + dispatch( 'core/editor' ).savePost(); + + // Process + savePostIsDone.then( + function () { + // If the post is well saved, we can reload the page + window.location.reload(); + }, + function () { + // If the post save failed + unsubscribe(); + } + ).catch( + function () { + // If an exception is thrown + unsubscribe(); + } + ); + }; + } + ); + + initMetaboxAutoComplete(); + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/block-editor.min.js b/wp-content/plugins/polylang-pro/js/build/block-editor.min.js new file mode 100644 index 000000000..6c5480a80 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/block-editor.min.js @@ -0,0 +1 @@ +"use strict";const languagesList=jQuery(".post_lang_choice"),initializeConfirmationModal=()=>{const{__:t}=wp.i18n,e=jQuery("
    ",{id:"pll-dialog",style:"display:none;"}).text(t("Are you sure you want to change the language of the current content?","polylang"));languagesList.after(e);const a=new Promise(((a,n)=>{const i=t=>{switch(t){case"yes":languagesList.data("old-value",languagesList.children(":selected").first().val()),a();break;case"no":languagesList.val(languagesList.data("old-value")),n("Cancel")}e.dialog("close")},l={autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:t("Change language","polylang"),minWidth:600,maxWidth:"100%",open:function(t,e){jQuery("body").hasClass("rtl")&&jQuery(this).parent().css({right:jQuery(this).parent().css("left"),left:"auto"})},close:function(t,e){i("no")},buttons:[{text:t("OK","polylang"),click:function(t){i("yes")}},{text:t("Cancel","polylang"),click:function(t){i("no")}}]};jQuery.ui.version>="1.12.0"?Object.assign(l,{classes:{"ui-dialog":"pll-confirmation-modal"}}):Object.assign(l,{dialogClass:"pll-confirmation-modal"}),e.dialog(l)}));return{dialogContainer:e,dialogResult:a}},initializeLanguageOldValue=()=>{languagesList.attr("data-old-value",languagesList.children(":selected").first().val())};function initMetaboxAutoComplete(){jQuery(".tr_lang").each((function(){var t=jQuery(this).attr("id").substring(8),e=jQuery(this).parent().parent().siblings(".pll-edit-column");jQuery(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+jQuery(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+jQuery("#post_type").val()+"&_pll_nonce="+jQuery("#_pll_nonce").val(),select:function(a,n){jQuery("#htr_lang_"+t).val(n.item.id),e.html(n.item.link)}}),jQuery(this).on("blur",(function(){jQuery(this).val()||(jQuery("#htr_lang_"+t).val(0),e.html(e.siblings(".hidden").children().clone()))}))}))}const filterPathMiddleware=(t,e,a)=>{const n=t.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(e).find((t=>n===t))?a(t):t},filter_path_middleware=filterPathMiddleware;function getCurrentLanguage(){const t=document.querySelector("[name=post_lang_choice]");return null===t?pllDefaultLanguage:t.value}function addLanguageParameter(t){return void 0===t.data||null===t.data?t.path+=(t.path.indexOf("?")>=0?"&lang=":"?lang=")+getCurrentLanguage():t.data.lang=getCurrentLanguage(),t}wp.apiFetch.use((function(t,e){return void 0!==t.url||"undefined"==typeof pllFilteredRoutes?e(t):e(filter_path_middleware(t,pllFilteredRoutes,addLanguageParameter))})),jQuery((function(t){initializeLanguageOldValue(),t(".post_lang_choice").on("change",(function(e){const{select:a,dispatch:n,subscribe:i}=wp.data,l=function(){const t=a("core/editor");return!t.getEditedPostAttribute("title")?.trim()&&!t.getEditedPostContent()&&!t.getEditedPostAttribute("excerpt")?.trim()}(),{addQueryArgs:o}=wp.url,r=initializeConfirmationModal(),{dialogContainer:s}=r;let{dialogResult:u}=r;const c=e.target;var d;location.pathname.match(/post-new.php/gi)&&l&&(d=c.value,-1!=location.search.indexOf("new_lang")?window.location.search=window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/,"new_lang="+d+"$1$2"):window.location.search=window.location.search+(-1!=window.location.search.indexOf("?")?"&":"?")+"new_lang="+d),t(this).data("old-value")===c.value||l?(initializeLanguageOldValue(),u=Promise.resolve()):s.dialog("open"),u.then((()=>{let e={action:"post_lang_choice",lang:c.value,post_type:t("#post_type").val(),post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,e,(function(){!function(){let t=null;const e=a("core/editor").getCurrentPost(),l=new Promise((function(n,l){t=i((function(){const t=a("core/editor").getCurrentPost(),{id:i,status:r,type:s}=t;a("core").getLastEntitySaveError("postType",s,i)&&l(),e.modified!==t.modified&&(location.pathname.match(/post-new.php/gi)&&"auto-draft"!==r&&i&&window.history.replaceState({id:i},"Post "+i,o("post.php",{post:i,action:"edit"})),n())}))}));n("core/editor").savePost(),l.then((function(){window.location.reload()}),(function(){t()})).catch((function(){t()}))}()}))}),(()=>{}))})),initMetaboxAutoComplete()})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/blocks.js b/wp-content/plugins/polylang-pro/js/build/blocks.js new file mode 100644 index 000000000..9b4709c1e --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/blocks.js @@ -0,0 +1,1517 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 20: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +var __webpack_unused_export__; +/** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +var f=__webpack_require__(677),k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0}; +function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return{$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}__webpack_unused_export__=l;exports.jsx=q;exports.jsxs=q; + + +/***/ }), + +/***/ 848: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +if (true) { + module.exports = __webpack_require__(20); +} else {} + + +/***/ }), + +/***/ 677: +/***/ ((module) => { + +module.exports = (function() { return this["React"]; }()); + +/***/ }), + +/***/ 419: +/***/ ((module) => { + +module.exports = (function() { return this["lodash"]; }()); + +/***/ }), + +/***/ 89: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["blockEditor"]; }()); + +/***/ }), + +/***/ 545: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["blocks"]; }()); + +/***/ }), + +/***/ 959: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["components"]; }()); + +/***/ }), + +/***/ 897: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["compose"]; }()); + +/***/ }), + +/***/ 987: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["data"]; }()); + +/***/ }), + +/***/ 601: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["element"]; }()); + +/***/ }), + +/***/ 873: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["hooks"]; }()); + +/***/ }), + +/***/ 75: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["i18n"]; }()); + +/***/ }), + +/***/ 933: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["primitives"]; }()); + +/***/ }), + +/***/ 567: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["serverSideRender"]; }()); + +/***/ }), + +/***/ 172: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["url"]; }()); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; + +// EXTERNAL MODULE: external {"this":["wp","i18n"]} +var external_this_wp_i18n_ = __webpack_require__(75); +// EXTERNAL MODULE: external "lodash" +var external_lodash_ = __webpack_require__(419); +// EXTERNAL MODULE: external {"this":["wp","compose"]} +var external_this_wp_compose_ = __webpack_require__(897); +// EXTERNAL MODULE: external {"this":["wp","hooks"]} +var external_this_wp_hooks_ = __webpack_require__(873); +// EXTERNAL MODULE: external {"this":["wp","data"]} +var external_this_wp_data_ = __webpack_require__(987); +// EXTERNAL MODULE: external {"this":["wp","element"]} +var external_this_wp_element_ = __webpack_require__(601); +// EXTERNAL MODULE: external {"this":["wp","blockEditor"]} +var external_this_wp_blockEditor_ = __webpack_require__(89); +// EXTERNAL MODULE: external {"this":["wp","components"]} +var external_this_wp_components_ = __webpack_require__(959); +// EXTERNAL MODULE: external {"this":["wp","primitives"]} +var external_this_wp_primitives_ = __webpack_require__(933); +// EXTERNAL MODULE: ./node_modules/react/jsx-runtime.js +var jsx_runtime = __webpack_require__(848); +;// ./modules/block-editor/js/icons/library/duplication.js +/** + * Duplication icon - admin-page Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const duplication = isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M6 15v-13h10v13h-10zM5 16h8v2h-10v-13h2v11z" + }) +}) : 'admin-page'; +/* harmony default export */ const library_duplication = ((/* unused pure expression or super */ null && (duplication))); +;// ./modules/block-editor/js/icons/library/pencil.js +/** + * Pencil icon - edit Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const pencil_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const pencil = pencil_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M13.89 3.39l2.71 2.72c0.46 0.46 0.42 1.24 0.030 1.64l-8.010 8.020-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.030c0.39-0.39 1.22-0.39 1.68 0.070zM11.16 6.18l-5.59 5.61 1.11 1.11 5.54-5.65zM8.19 14.41l5.58-5.6-1.070-1.080-5.59 5.6z" + }) +}) : 'edit'; +/* harmony default export */ const library_pencil = ((/* unused pure expression or super */ null && (pencil))); +;// ./modules/block-editor/js/icons/library/plus.js +/** + * Plus icon - plus Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const plus_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const plus = plus_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M17 7v3h-5v5h-3v-5h-5v-3h5v-5h3v5h5z" + }) +}) : 'plus'; +/* harmony default export */ const library_plus = ((/* unused pure expression or super */ null && (plus))); +;// ./modules/block-editor/js/icons/library/synchronization.js +/** + * Synchronization icon - controls-repeat Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const synchronization_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const synchronization = synchronization_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M5 7v3l-2 1.5v-6.5h11v-2l4 3.010-4 2.99v-2h-9zM15 13v-3l2-1.5v6.5h-11v2l-4-3.010 4-2.99v2h9z" + }) +}) : 'controls-repeat'; +/* harmony default export */ const library_synchronization = ((/* unused pure expression or super */ null && (synchronization))); +;// ./modules/block-editor/js/icons/library/translation.js +/** + * Translation icon - translation Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const translation_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const translation = translation_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M11 7H9.49c-.63 0-1.25.3-1.59.7L7 5H4.13l-2.39 7h1.69l.74-2H7v4H2c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h7c1.1 0 2 .9 2 2v2zM6.51 9H4.49l1-2.93zM10 8h7c1.1 0 2 .9 2 2v7c0 1.1-.9 2-2 2h-7c-1.1 0-2-.9-2-2v-7c0-1.1.9-2 2-2zm7.25 5v-1.08h-3.17V9.75h-1.16v2.17H9.75V13h1.28c.11.85.56 1.85 1.28 2.62-.87.36-1.89.62-2.31.62-.01.02.22.97.2 1.46.84 0 2.21-.5 3.28-1.15 1.09.65 2.48 1.15 3.34 1.15-.02-.49.2-1.44.2-1.46-.43 0-1.49-.27-2.38-.63.7-.77 1.14-1.77 1.25-2.61h1.36zm-3.81 1.93c-.5-.46-.85-1.13-1.01-1.93h2.09c-.17.8-.51 1.47-1 1.93l-.04.03s-.03-.02-.04-.03z" + }) +}) : 'translation'; +/* harmony default export */ const library_translation = (translation); +;// ./modules/block-editor/js/icons/library/trash.js +/** + * Trash icon - trash Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const trash_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const trash = trash_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M12 4h3c.6 0 1 .4 1 1v1H3V5c0-.6.5-1 1-1h3c.2-1.1 1.3-2 2.5-2s2.3.9 2.5 2zM8 4h3c-.2-.6-.9-1-1.5-1S8.2 3.4 8 4zM4 7h11l-.9 10.1c0 .5-.5.9-1 .9H5.9c-.5 0-.9-.4-1-.9L4 7z" + }) +}) : 'trash'; +/* harmony default export */ const library_trash = ((/* unused pure expression or super */ null && (trash))); +;// ./modules/block-editor/js/icons/library/star.js +/** + * Star icon - star-filled Dashicon. + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + + + +const star_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const star = star_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + width: "20", + height: "20", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 20 20", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "m10 1 3 6 6 .75-4.12 4.62L16 19l-6-3-6 3 1.13-6.63L1 7.75 7 7z" + }) +}) : 'star-filled'; +/* harmony default export */ const library_star = ((/* unused pure expression or super */ null && (star))); +;// ./modules/block-editor/js/icons/library/submenu.js +/** + * Submenu icon + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies + */ + +/** + * External dependencies + */ + + +const submenu_isPrimitivesComponents = !(0,external_lodash_.isUndefined)(wp.primitives); +const SubmenuIcon = () => submenu_isPrimitivesComponents ? /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.SVG, { + xmlns: "http://www.w3.org/2000/svg", + width: "12", + height: "12", + viewBox: "0 0 12 12", + fill: "none", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_primitives_.Path, { + d: "M1.50002 4L6.00002 8L10.5 4", + strokeWidth: "1.5" + }) +}) : 'submenu'; +/* harmony default export */ const submenu = (SubmenuIcon); +;// ./modules/block-editor/js/icons/index.js +/** + * Icons library + * + * @package Polylang-Pro + */ + + + + + + + + + +;// ./modules/block-editor/js/components/language-flag.js +/** + * @package Polylang-Pro + */ + +/** + * External dependencies. + */ + + +/** + * Internal dependencies. + */ + + +/** + * Display a flag icon for a given language. + * + * @since 3.1 + * @since 3.2 Now its own component. + * + * @param {Object} A language object. + * + * @return {Object} + */ + +function LanguageFlag({ + language +}) { + return !(0,external_lodash_.isNil)(language) ? !(0,external_lodash_.isEmpty)(language.flag_url) ? /*#__PURE__*/(0,jsx_runtime.jsx)("span", { + className: "pll-select-flag", + children: /*#__PURE__*/(0,jsx_runtime.jsx)("img", { + src: language.flag_url, + alt: language.name, + title: language.name, + className: "flag" + }) + }) : /*#__PURE__*/(0,jsx_runtime.jsxs)("abbr", { + children: [language.slug, /*#__PURE__*/(0,jsx_runtime.jsx)("span", { + className: "screen-reader-text", + children: language.name + })] + }) : /*#__PURE__*/(0,jsx_runtime.jsx)("span", { + className: "pll-translation-icon", + children: library_translation + }); +} +/* harmony default export */ const language_flag = (LanguageFlag); +;// ./modules/block-editor/js/components/language-dropdown.js +/** + * @package Polylang-Pro + */ + +// External dependencies + + +/** + * Displays a dropdown to select a language. + * + * @since 3.1 + * + * @param {Function} handleChange Callback to be executed when language changes. + * @param {mixed} children Child components to be used as select options. + * @param {Object} selectedLanguage An object representing a Polylang Language. Default to null. + * @param {string} Default value to be selected if the selected language is not provided. Default to an empty string. + * + * @return {Object} A dropdown selector for languages. + */ + +function LanguageDropdown({ + handleChange, + children, + selectedLanguage = null, + defaultValue = '' +}) { + const selectedLanguageSlug = selectedLanguage?.slug ? selectedLanguage.slug : defaultValue; + return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { + id: "select-post-language", + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(language_flag, { + language: selectedLanguage + }), children && /*#__PURE__*/(0,jsx_runtime.jsx)("select", { + value: selectedLanguageSlug, + onChange: event => handleChange(event), + id: "pll_post_lang_choice", + name: "pll_post_lang_choice", + className: "post_lang_choice", + children: children + })] + }); +} + +/** + * Map languages objects as options for a tag. + */ +function LanguagesOptionsList({ + languages +}) { + return Array.from(languages.values()).map(({ + slug, + name, + w3c + }) => /*#__PURE__*/(0,jsx_runtime.jsx)("option", { + value: slug, + lang: w3c, + children: name + }, slug)); +} + +;// ./modules/block-editor/js/sidebar/settings.js +/** + * Module Constants + * + * @package Polylang-Pro + */ + +const settings_MODULE_KEY = 'pll/metabox'; +const settings_MODULE_CORE_EDITOR_KEY = 'core/editor'; +const settings_MODULE_SITE_EDITOR_KEY = 'core/edit-site'; +const settings_MODULE_POST_EDITOR_KEY = 'core/edit-post'; +const settings_MODULE_CORE_KEY = 'core'; +const DEFAULT_STATE = { + languages: [], + selectedLanguage: {}, + translatedPosts: {}, + fromPost: null, + currentTemplatePart: {} +}; +const UNTRANSLATABLE_POST_TYPE = (/* unused pure expression or super */ null && (['wp_template', 'wp_global_styles'])); +const POST_TYPE_WITH_TRASH = (/* unused pure expression or super */ null && (['page'])); +const settings_TEMPLATE_PART_SLUG_SEPARATOR = '___'; // Its value must be synchronized with its equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR +const settings_TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN = '[a-z_-]+'; // Its value must be synchronized with it equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR + +// EXTERNAL MODULE: external {"this":["wp","url"]} +var external_this_wp_url_ = __webpack_require__(172); +;// ./modules/block-editor/js/sidebar/utils.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + + +/** + * Internal dependencies + */ + + +/** + * Converts array of object to a map. + * + * @param {array} array Array to convert. + * @param {*} key The key in the object used as key to build the map. + * @returns {Map} + */ +function convertArrayToMap(array, key) { + const map = new Map(); + array.reduce(function (accumulator, currentValue) { + accumulator.set(currentValue[key], currentValue); + return accumulator; + }, map); + return map; +} + +/** + * Converts map to an associative array. + * + * @param {Map} map The map to convert. + * @returns {Object} + */ +function utils_convertMapToObject(map) { + const object = {}; + map.forEach(function (value, key, map) { + const obj = this; + this[key] = isBoolean(value) ? value.toString() : value; + }, object); + return object; +} + +/** + * Checks whether the current screen is block-based post type editor. + * + * @returns {boolean} True if block editor for post type; false otherwise. + */ +function isPostTypeBlockEditor() { + return !!document.getElementById('editor'); +} + +/** + * Checks whether the current screen is the block-based widgets editor. + * + * @returns {boolean} True if we are in the widgets block editor; false otherwise. + */ +function isWidgetsBlockEditor() { + return !!document.getElementById('widgets-editor'); +} + +/** + * Checks whether the current screen is the customizer widgets editor. + * + * @returns {boolean} True if we are in the customizer widgets editor; false otherwise. + */ +function isWidgetsCustomizerEditor() { + return !!document.getElementById('customize-controls'); +} + +/** + * Checks whether the current screen is the site editor. + * Takes in account if Gutenberg is activated. + * + * @returns {boolean} True if site editor screen, false otherwise. + */ +function isSiteBlockEditor() { + return !!(document.getElementById('site-editor') || document.getElementById('edit-site-editor')); +} + +/** + * Returns the post type URL for REST API calls or undefined if the user hasn't the rights. + * + * @param {string} name The post type name. + * @returns {string|undefined} + */ +function getPostsUrl(name) { + const postTypes = select('core').getEntitiesByKind('postType'); + const postType = find(postTypes, { + name + }); + return postType?.baseURL; +} + +/** + * Gets all query string parameters and convert them in a URLSearchParams object. + * + * @returns {Object} + */ +function utils_getSearchParams() { + // Variable window.location.search is just read for creating and returning a URLSearchParams object to be able to manipulate it more easily. + if (!isEmpty(window.location.search)) { + // phpcs:ignore WordPressVIPMinimum.JS.Window.location + return new URLSearchParams(window.location.search); // phpcs:ignore WordPressVIPMinimum.JS.Window.location + } else { + return null; + } +} + +/** + * Gets selected language. + * + * @param {string} lang The post language code. + * @returns {Object} The selected language. + */ +function getSelectedLanguage(lang) { + const languages = select(MODULE_KEY).getLanguages(); + // Pick up this language as selected in languages list + return languages.get(lang); +} + +/** + * Gets the default language. + * + * @returns {Object} The default Language. + */ +function getDefaultLanguage() { + const languages = select(MODULE_KEY).getLanguages(); + return Array.from(languages.values()).find(lang => lang.is_default); +} + +/** + * Checks if the given language is the default one. + * + * @param {string} lang The language code to compare with. + * @returns {boolean} True if the given language is the default one. + */ +function isDefaultLanguage(lang) { + return lang === getDefaultLanguage().slug; +} + +/** + * Gets translated posts. + * + * @param {Object} translations The translated posts object with language codes as keys and ids as values. + * @param {Object.} translations_table The translations table data with language codes as keys and data object as values. + * @returns {Map} + */ +function utils_getTranslatedPosts(translations, translations_table, lang) { + const translationsTable = getTranslationsTable(translations_table, lang); + const fromPost = select(MODULE_KEY).getFromPost(); + let translatedPosts = new Map(Object.entries([])); + if (!isUndefined(translations)) { + translatedPosts = new Map(Object.entries(translations)); + } + // If we come from another post for creating a new one, we have to update translated posts from the original post + // to be able to update translations attribute of the post + if (!isNil(fromPost) && !isNil(fromPost.id)) { + translationsTable.forEach((translationData, lang) => { + if (!isNil(translationData.translated_post) && !isNil(translationData.translated_post.id)) { + translatedPosts.set(lang, translationData.translated_post.id); + } + }); + } + return translatedPosts; +} + +/** + * Gets synchronized posts. + * + * @param {Object.} pll_sync_post The synchronized posts object with language codes as keys and boolean values to say if the post is synchronized or not. + * @returns {Map} + */ +function getSynchronizedPosts(pll_sync_post) { + let synchronizedPosts = new Map(Object.entries([])); + if (!isUndefined(pll_sync_post)) { + synchronizedPosts = new Map(Object.entries(pll_sync_post)); + } + return synchronizedPosts; +} + +/** + * Gets translations table. + * + * @param {Object.} translationsTableDatas The translations table data object with language codes as keys and data object as values. + * @returns {Map} + */ +function getTranslationsTable(translationsTableDatas) { + let translationsTable = new Map(Object.entries([])); + // get translations table datas from post + if (!isUndefined(translationsTableDatas)) { + // Build translations table map with language slug as key + translationsTable = new Map(Object.entries(translationsTableDatas)); + } + return translationsTable; +} + +/** + * Checks if the given request is for saving. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request is for saving. + */ +function isSaveRequest(options) { + // If data is defined we are in a PUT or POST request method otherwise a GET request method + // Test options.method property isn't efficient because most of REST request which use fetch API doesn't pass this property. + // So, test options.data is necessary to know if the REST request is to save datas. + // However test if options.data is undefined isn't sufficient because some REST request pass a null value as the ServerSideRender Gutenberg component. + if (!isNil(options.data)) { + return true; + } else { + return false; + } +} + +/** + * Checks if the given request concerns the current post type. + * + * Useful when saving a reusable block contained in another post type. + * Indeed a reusable block is also a post, but its saving request doesn't concern the post currently edited. + * As we don't know the language of the reusable block when the user triggers the reusable block saving action, + * we need to pass the current post language to be sure that the reusable block will have a language. + * + * @see https://github.com/polylang/polylang/issues/437 - Reusable block has no language when it's saved from another post type editing. + * + * @param {Object} options the initial request + * @returns {boolean} True if the request concerns the current post. + */ +function isCurrentPostRequest(options) { + // Saving translation data is needed only for all post types. + // It's done by verifying options.path matches with one of baseURL of all post types + // and compare current post id with this sent in the request. + + // List of post type baseURLs. + const postTypeURLs = map(select('core').getEntitiesByKind('postType'), property('baseURL')); + + // Id from the post currently edited. + const postId = select('core/editor').getCurrentPostId(); + + // Id from the REST request. + // options.data never isNil here because it's already verified before in isSaveRequest() function. + const id = options.data.id; + + // Return true + // if REST request baseURL matches with one of the known post type baseURLs + // and the id from the post currently edited corresponds on the id passed to the REST request + // Return false otherwise + return -1 !== postTypeURLs.findIndex(function (element) { + return new RegExp(`${escapeRegExp(element)}`).test(options.path); + }) && postId === id; +} + +/** + * Checks if the given REST request is for the creation of a new template part translation. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part translation creation. + */ +function isTemplatePartTranslationCreationRequest(options) { + return 'POST' === options.method && options.path.match(/^\/wp\/v2\/template-parts(?:\/|\?|$)/) && !isNil(options.data.from_post) && !isNil(options.data.lang); +} + +/** + * Checks if the given REST request is for the creation of a new template part. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part creation. + */ +function isNewTemplatePartCreationRequest(options) { + return 'POST' === options.method && options.path.match(/^\/wp\/v2\/template-parts(?:\/|\?|$)/) && isNil(options.data.from_post) && isNil(options.data.lang); +} + +/** + * Adds language as query string parameter to the given request. + * + * @param {Object} options The initial request. + * @param {string} currentLanguage The language code to add to the request. + */ +function addLanguageToRequest(options, currentLanguage) { + const hasLangArg = hasQueryArg(options.path, 'lang'); + const filterLang = isUndefined(options.filterLang) || options.filterLang; + if (filterLang && !hasLangArg) { + options.path = addQueryArgs(options.path, { + lang: currentLanguage + }); + } +} + +/** + * Adds `include_untranslated` parameter to the request. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function addIncludeUntranslatedParam(options) { + options.path = addQueryArgs(options.path, { + include_untranslated: true + }); +} + +/** + * Use addIncludeUntranslatedParam if the given page is a template part page. + * Or if the template editing mode is enabled inside post editing. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function maybeRequireIncludeUntranslatedTemplate(options) { + const params = new URL(document.location).searchParams; + const postType = params.get('postType'); + const postId = params.get('postId'); + const isEditingTemplate = select(MODULE_POST_EDITOR_KEY)?.isEditingTemplate(); + if ("wp_template_part" === postType && !isNil(postId) || isEditingTemplate) { + addIncludeUntranslatedParam(options); + } +} + +/** + * Returns true if the given post is a template part, false otherwise. + * + * @param {Object} post A post object. + * @returns {boolean} Whether it is a template part or not. + */ +function isTemplatePart(post) { + return 'wp_template_part' === post.type; +} + +/** + * Returns the current post type considering the Site Editor or Post Editor. + * + * @returns {string} The current post type. + */ +function getCurrentPostType() { + if (isSiteBlockEditor()) { + return select(MODULE_SITE_EDITOR_KEY).getEditedPostType(); + } + return select(MODULE_CORE_EDITOR_KEY).getCurrentPostType(); +} + +/** + * Returns a regular expression ready to use to perform search and replace. + * + * @returns {RegExp} The regular expression. + */ +function getLangSlugRegex() { + let languageCheckPattern = TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN; + const languages = select(MODULE_KEY).getLanguages(); + const languageSlugs = Array.from(languages.keys()); + if (!isEmpty(languageSlugs)) { + languageCheckPattern = languageSlugs.join('|'); + } + return new RegExp(`${TEMPLATE_PART_SLUG_SEPARATOR}(?:${languageCheckPattern})$`); +} +;// ./modules/block-editor/js/sidebar/store/utils.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + +/** + * Internal dependencies + */ + + + +/** + * Wait for the whole post block editor context has been initialized: current post loaded and languages list initialized. + */ +const isBlockPostEditorContextInitialized = () => { + if (isNil(select(MODULE_CORE_EDITOR_KEY))) { + return Promise.reject("Polylang languages panel can't be initialized because block editor isn't fully initialized."); + } + + // save url params espacially when a new translation is creating + saveURLParams(); + // call to getCurrentUser to force call to resolvers and initialize state + const currentUser = select(MODULE_KEY).getCurrentUser(); + + /** + * Set a promise for waiting for the current post has been fully loaded before making other processes. + */ + const isCurrentPostLoaded = new Promise(function (resolve) { + let unsubscribe = subscribe(function () { + const currentPost = select(MODULE_CORE_EDITOR_KEY).getCurrentPost(); + if (!isEmpty(currentPost)) { + unsubscribe(); + resolve(); + } + }); + }); + + // Wait for current post has been loaded and languages list initialized. + return Promise.all([isCurrentPostLoaded, isLanguagesinitialized()]).then(function () { + // If we come from another post for creating a new one, we have to update translations from the original post. + const fromPost = select(MODULE_KEY).getFromPost(); + if (!isNil(fromPost) && !isNil(fromPost.id)) { + const lang = select(MODULE_CORE_EDITOR_KEY).getEditedPostAttribute('lang'); + const translations = select(MODULE_CORE_EDITOR_KEY).getEditedPostAttribute('translations'); + const translations_table = select(MODULE_CORE_EDITOR_KEY).getEditedPostAttribute('translations_table'); + const translatedPosts = getTranslatedPosts(translations, translations_table, lang); + dispatch(MODULE_CORE_EDITOR_KEY).editPost({ + translations: convertMapToObject(translatedPosts) + }); + } + }); +}; + +/** + * Wait for the whole site editor context to be initialized: current template loaded and languages list initialized. + */ +const isSiteEditorContextInitialized = () => { + // save url params espacially when a new translation is creating + saveURLParams(); + // call to getCurrentUser to force call to resolvers and initialize state + const currentUser = select(MODULE_KEY).getCurrentUser(); + + /** + * Set a promise to wait for the current template to be fully loaded before making other processes. + * It allows to see if both Site Editor and Core stores are available (@see getCurrentPostFromDataStore()). + */ + const isTemplatePartLoaded = new Promise(function (resolve) { + let unsubscribe = subscribe(function () { + const store = select(MODULE_SITE_EDITOR_KEY); + if (store) { + unsubscribe(); + resolve(); + } + }); + }); + return Promise.all([isTemplatePartLoaded, isLanguagesinitialized()]); +}; + +/** + * Returns a promise fulfilled when the languages list is correctly initialized before making other processes. + */ +const isLanguagesinitialized = () => new Promise(function (resolve) { + let unsubscribe = (0,external_this_wp_data_.subscribe)(function () { + const languages = (0,external_this_wp_data_.select)(settings_MODULE_KEY)?.getLanguages(); + if (languages?.size > 0) { + unsubscribe(); + resolve(); + } + }); +}); + +/** + * Save query string parameters from URL. They could be needed after + * They could be null if they does not exist + */ +function saveURLParams() { + // Variable window.location.search isn't use directly + // Function getSearchParams return an URLSearchParams object for manipulating each parameter + // Each of them are sanitized below + const searchParams = getSearchParams(); + if (null !== searchParams) { + dispatch(MODULE_KEY).setFromPost({ + id: wp.sanitize.stripTagsAndEncodeText(searchParams.get('from_post')), + postType: wp.sanitize.stripTagsAndEncodeText(searchParams.get('post_type')), + newLanguage: wp.sanitize.stripTagsAndEncodeText(searchParams.get('new_lang')) + }); + } +} +const getEditedPostContextWithLegacy = () => { + const siteEditorSelector = select(MODULE_SITE_EDITOR_KEY); + + /** + * Return null when called from our apiFetch middleware without a properly loaded store. + */ + if (!siteEditorSelector) { + return null; + } + const _context = { + postId: siteEditorSelector.getEditedPostId(), + postType: siteEditorSelector.getEditedPostType() + }; + if (siteEditorSelector.hasOwnProperty('getEditedPostContext')) { + const context = siteEditorSelector.getEditedPostContext(); + return context?.postType && context?.postId ? context : _context; + } + + /** + * Backward compatibility with WordPress < 6.3 where `getEditedPostContext()` doesn't exist yet. + */ + return _context; +}; + +/** + * Gets the current post using the Site Editor store and the Core store. + * + * @returns {object|null} The current post object, `null` if none found. + */ +const getCurrentPostFromDataStore = () => { + const editedContext = getEditedPostContextWithLegacy(); + return null === editedContext ? null : select(MODULE_CORE_KEY).getEntityRecord('postType', editedContext.postType, editedContext.postId); +}; +;// ./modules/block-editor/js/blocks/attributes.js +/** + * Add blocks attributes + * + * @package Polylang-Pro + */ + +/** + * WordPress Dependencies + */ + + + + + + + + + +/** + * Internal dependencies + */ + + + + + +if (isWidgetsBlockEditor() || isWidgetsCustomizerEditor()) { + const LanguageAttribute = { + type: 'string', + default: 'every' + }; + const addLangChoiceAttribute = function (settings, name) { + const unallowedBlockNames = ['core/widget-area', 'core/legacy-widget']; + if (unallowedBlockNames.find(element => element === name)) { + return settings; + } + settings.attributes = (0,external_lodash_.assign)(settings.attributes, { + pll_lang: LanguageAttribute + }); + return settings; + }; + (0,external_this_wp_hooks_.addFilter)('blocks.registerBlockType', 'pll/lang-choice', addLangChoiceAttribute); + const withInspectorControls = (0,external_this_wp_compose_.createHigherOrderComponent)(BlockEdit => { + return props => { + const languages = (0,external_this_wp_data_.select)(settings_MODULE_KEY).getLanguages(); + const { + pll_lang + } = props.attributes; + const isLanguageFilterable = !(0,external_lodash_.isNil)(pll_lang); + const selectedLanguage = languages.get(pll_lang); + return /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_element_.Fragment, { + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(BlockEdit, { + ...props + }), isLanguageFilterable && /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_blockEditor_.InspectorControls, { + children: /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_components_.PanelBody, { + title: (0,external_this_wp_i18n_.__)('Languages', 'polylang-pro'), + children: [/*#__PURE__*/(0,jsx_runtime.jsx)("label", { + children: (0,external_this_wp_i18n_.__)('The block is displayed for:', 'polylang-pro') + }), /*#__PURE__*/(0,jsx_runtime.jsxs)(LanguageDropdown, { + selectedLanguage: selectedLanguage, + handleChange: langChoiceEvent => { + const langChoice = langChoiceEvent.currentTarget.value; + props.setAttributes({ + pll_lang: langChoice + }); + }, + defaultValue: LanguageAttribute.default, + children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("option", { + value: LanguageAttribute.default, + children: [(0,external_this_wp_i18n_.__)('All languages', 'polylang-pro'), " "] + }), /*#__PURE__*/(0,jsx_runtime.jsx)(LanguagesOptionsList, { + languages: languages + })] + })] + }) + })] + }); + }; + }, "withInspectorControl"); + isLanguagesinitialized().then(function () { + (0,external_this_wp_hooks_.addFilter)('editor.BlockEdit', 'pll/lang-choice-with-inspector-controls', withInspectorControls); + }); +} +// EXTERNAL MODULE: external {"this":["wp","blocks"]} +var external_this_wp_blocks_ = __webpack_require__(545); +// EXTERNAL MODULE: external {"this":["wp","serverSideRender"]} +var external_this_wp_serverSideRender_ = __webpack_require__(567); +var external_this_wp_serverSideRender_default = /*#__PURE__*/__webpack_require__.n(external_this_wp_serverSideRender_); +;// ./modules/block-editor/js/blocks/language-switcher-edit.js +/** + * @package Polylang-Pro + */ + +/** + * External dependencies + */ + + +/** + * WordPress dependencies + */ + + +/** + * Call initialization of pll/metabox store for getting ready some datas + */ + +const i18nAttributeStrings = pll_block_editor_blocks_settings; +function createLanguageSwitcherEdit(props) { + const createToggleAttribute = function (propName) { + return () => { + const value = props.attributes[propName]; + const { + setAttributes + } = props; + let updatedAttributes = { + [propName]: !value + }; + let forcedAttributeName; + let forcedAttributeUnchecked; + + // Both show_names and show_flags attributes can't be unchecked together. + switch (propName) { + case 'show_names': + forcedAttributeName = 'show_flags'; + forcedAttributeUnchecked = !props.attributes[forcedAttributeName]; + break; + case 'show_flags': + forcedAttributeName = 'show_names'; + forcedAttributeUnchecked = !props.attributes[forcedAttributeName]; + break; + } + if ('show_names' === propName || 'show_flags' === propName) { + if (value && forcedAttributeUnchecked) { + updatedAttributes = (0,external_lodash_.assign)(updatedAttributes, { + [forcedAttributeName]: forcedAttributeUnchecked + }); + } + } + setAttributes(updatedAttributes); + }; + }; + const toggleDropdown = createToggleAttribute('dropdown'); + const toggleShowNames = createToggleAttribute('show_names'); + const toggleShowFlags = createToggleAttribute('show_flags'); + const toggleForceHome = createToggleAttribute('force_home'); + const toggleHideCurrent = createToggleAttribute('hide_current'); + const toggleHideIfNoTranslation = createToggleAttribute('hide_if_no_translation'); + const { + dropdown, + show_names, + show_flags, + force_home, + hide_current, + hide_if_no_translation + } = props.attributes; + function ToggleControlDropdown() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.dropdown, + checked: dropdown, + onChange: toggleDropdown + }); + } + function ToggleControlShowNames() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.show_names, + checked: show_names, + onChange: toggleShowNames + }); + } + function ToggleControlShowFlags() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.show_flags, + checked: show_flags, + onChange: toggleShowFlags + }); + } + function ToggleControlForceHome() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.force_home, + checked: force_home, + onChange: toggleForceHome + }); + } + function ToggleControlHideCurrent() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.hide_current, + checked: hide_current, + onChange: toggleHideCurrent + }); + } + function ToggleControlHideIfNoTranslations() { + return /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.ToggleControl, { + label: i18nAttributeStrings.hide_if_no_translation, + checked: hide_if_no_translation, + onChange: toggleHideIfNoTranslation + }); + } + return { + ToggleControlDropdown, + ToggleControlShowNames, + ToggleControlShowFlags, + ToggleControlForceHome, + ToggleControlHideCurrent, + ToggleControlHideIfNoTranslations + }; +} +;// ./modules/block-editor/js/blocks/block.js +/** + * Register language switcher block. + * + * @package Polylang-Pro + */ + +/** + * WordPress Dependencies + */ + + + + + + + + +/** + * External dependencies + */ + + +/** + * Internal dependencies + */ + + + +const blocktitle = (0,external_this_wp_i18n_.__)('Language switcher', 'polylang-pro'); +const descriptionTitle = (0,external_this_wp_i18n_.__)('Add a language switcher to allow your visitors to select their preferred language.', 'polylang-pro'); +const panelTitle = (0,external_this_wp_i18n_.__)('Language switcher settings', 'polylang-pro'); + +// Register the Language Switcher block as first level block in Block Editor. +(0,external_this_wp_blocks_.registerBlockType)('polylang/language-switcher', { + title: blocktitle, + description: descriptionTitle, + icon: library_translation, + category: 'widgets', + example: {}, + edit: props => { + const { + dropdown + } = props.attributes; + const { + ToggleControlDropdown, + ToggleControlShowNames, + ToggleControlShowFlags, + ToggleControlForceHome, + ToggleControlHideCurrent, + ToggleControlHideIfNoTranslations + } = createLanguageSwitcherEdit(props); + return /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_element_.Fragment, { + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_blockEditor_.InspectorControls, { + children: /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_components_.PanelBody, { + title: panelTitle, + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlDropdown, {}), !dropdown && /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlShowNames, {}), !dropdown && /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlShowFlags, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlForceHome, {}), !dropdown && /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlHideCurrent, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlHideIfNoTranslations, {})] + }) + }), /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.Disabled, { + children: /*#__PURE__*/(0,jsx_runtime.jsx)((external_this_wp_serverSideRender_default()), { + block: "polylang/language-switcher", + attributes: props.attributes + }) + })] + }); + } +}); + +// Register the Language Switcher block as child block of core/navigation block. +const navigationLanguageSwitcherName = 'polylang/navigation-language-switcher'; +(0,external_this_wp_blocks_.registerBlockType)(navigationLanguageSwitcherName, { + title: blocktitle, + description: descriptionTitle, + icon: library_translation, + category: 'widgets', + parent: ['core/navigation'], + attributes: { + dropdown: { + type: 'boolean', + default: false + }, + show_names: { + type: 'boolean', + default: true + }, + show_flags: { + type: 'boolean', + default: false + }, + force_home: { + type: 'boolean', + default: false + }, + hide_current: { + type: 'boolean', + default: false + }, + hide_if_no_translation: { + type: 'boolean', + default: false + } + }, + transforms: { + from: [{ + type: 'block', + blocks: ['core/navigation-link'], + transform: () => (0,external_this_wp_blocks_.createBlock)(navigationLanguageSwitcherName) + }] + }, + usesContext: ['textColor', 'customTextColor', 'backgroundColor', 'customBackgroundColor', 'overlayTextColor', 'customOverlayTextColor', 'overlayBackgroundColor', 'customOverlayBackgroundColor', 'fontSize', 'customFontSize', 'showSubmenuIcon', 'openSubmenusOnClick', 'style'], + example: {}, + edit: props => { + const { + dropdown + } = props.attributes; + const { + showSubmenuIcon, + openSubmenusOnClick + } = props.context; + const { + ToggleControlDropdown, + ToggleControlShowNames, + ToggleControlShowFlags, + ToggleControlForceHome, + ToggleControlHideCurrent, + ToggleControlHideIfNoTranslations + } = createLanguageSwitcherEdit(props); + return /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_element_.Fragment, { + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_blockEditor_.InspectorControls, { + children: /*#__PURE__*/(0,jsx_runtime.jsxs)(external_this_wp_components_.PanelBody, { + title: panelTitle, + children: [/*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlDropdown, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlShowNames, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlShowFlags, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlForceHome, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlHideCurrent, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ToggleControlHideIfNoTranslations, {})] + }) + }), /*#__PURE__*/(0,jsx_runtime.jsx)(external_this_wp_components_.Disabled, { + children: /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { + className: "wp-block-navigation-item", + children: [/*#__PURE__*/(0,jsx_runtime.jsx)((external_this_wp_serverSideRender_default()), { + block: navigationLanguageSwitcherName, + attributes: props.attributes, + className: 'wp-block-navigation__container block-editor-block-list__layout' + }), submenuIcon(showSubmenuIcon, openSubmenusOnClick, dropdown)] + }) + })] + }); + } +}); + +/** + * Apply a callback function on each block of the blocks list. + * + * @param {Array} blocks The list of blocks to process. + * @param {Array} menuItems The initial menu items from where the blocks are converted to. + * @param {Object} blocksMapping The mapping between the menu items and their corresponding blocks. + * @param {mapper} mapper A callback to change the converted block by another one if necessary + * @returns {Array} Array of blocks updated. + */ +function mapBlockTree(blocks, menuItems, blocksMapping, mapper) { + /** + * A function to apply to each block to convert it if necessary by applying the `mapper` filter. + * + * @param {Object} block The block to replace or not. + * @returns {Object} The new block potentially replaced by the `mapper`. + */ + const convertBlock = block => ({ + ...mapper(block, menuItems, blocksMapping), + innerBlocks: mapBlockTree(block.innerBlocks, menuItems, blocksMapping, mapper) + }); + return blocks.map(convertBlock); +} + +/** + * A filter to detect the `core/navigation-link` block not correctly converted from the langauge switcher menu item + * and convert it to its corresponding `polylang/navigation-language-switcher` block. + * + * @callback mapper + * @param {Object} block The block converted from the menu item. + * @param {Array} menuItems The initial menu items from where the blocks are converted to. + * @param {Object} blocksMapping The mapping between the menu items and their corresponding blocks. + * @returns {Object} The block correctly converted. + */ +const blocksFilter = (block, menuItems, blocksMapping) => { + if (block.name === "core/navigation-link" && block.attributes?.url === "#pll_switcher") { + const menuItem = (0,external_lodash_.find)(menuItems, { + url: '#pll_switcher' + }); // Get the corresponding menu item. + const attributes = menuItem.meta._pll_menu_item; // Get its options. + const newBlock = (0,external_this_wp_blocks_.createBlock)(navigationLanguageSwitcherName, attributes); + blocksMapping[menuItem.id] = newBlock.clientId; // Update the blocks mapping. + return newBlock; + } + return block; +}; + +/** + * A filter callback hooked to `blocks.navigation.__unstableMenuItemsToBlocks`. + * + * @param {Array} blocks The list of blocks to process. + * @param {Array} menuItems The initial menu items from where the blocks are converted to. + * @returns {Array} Array of blocks updated. + */ +const menuItemsToBlocksFilter = (blocks, menuItems) => ({ + ...blocks, + innerBlocks: mapBlockTree(blocks.innerBlocks, menuItems, blocks.mapping, blocksFilter) +}); + +/** + * Returns the submenu icon if block parameters allow it. + * + * @param {bool} showSubmenuIcon Whether to show submenu icon or not. + * @param {bool} openSubmenusOnClick Whether the submenu can be open on click or not. + * @param {bool} dropdown Whether the language switcher is in dropdown mode or not. + * @returns The submenu icon or null. + */ +const submenuIcon = (showSubmenuIcon, openSubmenusOnClick, dropdown) => { + if ((showSubmenuIcon || openSubmenusOnClick) && dropdown) { + return /*#__PURE__*/(0,jsx_runtime.jsx)("span", { + className: "wp-block-navigation__submenu-icon", + children: /*#__PURE__*/(0,jsx_runtime.jsx)(submenu, {}) + }); + } + return null; +}; + +/** + * Hooks to the classic menu conversion to core/navigation block to be able to convert + * the language switcher menu item to its corresponding block. + */ +(0,external_this_wp_hooks_.addFilter)('blocks.navigation.__unstableMenuItemsToBlocks', 'polylang/include-language-switcher', menuItemsToBlocksFilter); +;// ./modules/block-editor/js/blocks/index.js +/** + * Handles language switcher block and attributes. + * + * @package Polylang-Pro + */ + +/** + * Internal dependencies + */ + + +})(); + +this["polylang-pro"] = __webpack_exports__; +/******/ })() +; \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/blocks.min.js b/wp-content/plugins/polylang-pro/js/build/blocks.min.js new file mode 100644 index 000000000..341c4f9e2 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/blocks.min.js @@ -0,0 +1 @@ +(()=>{var e={20:(e,t,o)=>{"use strict";var n=o(677),r=Symbol.for("react.element"),s=Symbol.for("react.fragment"),l=Object.prototype.hasOwnProperty,i=n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,a={key:!0,ref:!0,__self:!0,__source:!0};function c(e,t,o){var n,s={},c=null,u=null;for(n in void 0!==o&&(c=""+o),void 0!==t.key&&(c=""+t.key),void 0!==t.ref&&(u=t.ref),t)l.call(t,n)&&!a.hasOwnProperty(n)&&(s[n]=t[n]);if(e&&e.defaultProps)for(n in t=e.defaultProps)void 0===s[n]&&(s[n]=t[n]);return{$$typeof:r,type:e,key:c,ref:u,props:s,_owner:i.current}}t.jsx=c,t.jsxs=c},848:(e,t,o)=>{"use strict";e.exports=o(20)},677:e=>{e.exports=function(){return this.React}()},419:e=>{e.exports=function(){return this.lodash}()},89:e=>{e.exports=function(){return this.wp.blockEditor}()},545:e=>{e.exports=function(){return this.wp.blocks}()},959:e=>{e.exports=function(){return this.wp.components}()},897:e=>{e.exports=function(){return this.wp.compose}()},987:e=>{e.exports=function(){return this.wp.data}()},601:e=>{e.exports=function(){return this.wp.element}()},873:e=>{e.exports=function(){return this.wp.hooks}()},75:e=>{e.exports=function(){return this.wp.i18n}()},933:e=>{e.exports=function(){return this.wp.primitives}()},567:e=>{e.exports=function(){return this.wp.serverSideRender}()},172:e=>{e.exports=function(){return this.wp.url}()}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,o),s.exports}o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);(()=>{"use strict";var e=o(75),t=o(419),n=o(897),r=o(873),s=o(987),l=o(601),i=o(89),a=o(959),c=o(933),u=o(848);!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path),!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path),!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path),!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path);const g=!(0,t.isUndefined)(wp.primitives)?(0,u.jsx)(c.SVG,{width:"20",height:"20",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",children:(0,u.jsx)(c.Path,{d:"M11 7H9.49c-.63 0-1.25.3-1.59.7L7 5H4.13l-2.39 7h1.69l.74-2H7v4H2c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h7c1.1 0 2 .9 2 2v2zM6.51 9H4.49l1-2.93zM10 8h7c1.1 0 2 .9 2 2v7c0 1.1-.9 2-2 2h-7c-1.1 0-2-.9-2-2v-7c0-1.1.9-2 2-2zm7.25 5v-1.08h-3.17V9.75h-1.16v2.17H9.75V13h1.28c.11.85.56 1.85 1.28 2.62-.87.36-1.89.62-2.31.62-.01.02.22.97.2 1.46.84 0 2.21-.5 3.28-1.15 1.09.65 2.48 1.15 3.34 1.15-.02-.49.2-1.44.2-1.46-.43 0-1.49-.27-2.38-.63.7-.77 1.14-1.77 1.25-2.61h1.36zm-3.81 1.93c-.5-.46-.85-1.13-1.01-1.93h2.09c-.17.8-.51 1.47-1 1.93l-.04.03s-.03-.02-.04-.03z"})}):"translation",d=(!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path),!(0,t.isUndefined)(wp.primitives)&&(c.SVG,c.Path),!(0,t.isUndefined)(wp.primitives)),p=()=>d?(0,u.jsx)(c.SVG,{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",children:(0,u.jsx)(c.Path,{d:"M1.50002 4L6.00002 8L10.5 4",strokeWidth:"1.5"})}):"submenu";const h=function({language:e}){return(0,t.isNil)(e)?(0,u.jsx)("span",{className:"pll-translation-icon",children:g}):(0,t.isEmpty)(e.flag_url)?(0,u.jsxs)("abbr",{children:[e.slug,(0,u.jsx)("span",{className:"screen-reader-text",children:e.name})]}):(0,u.jsx)("span",{className:"pll-select-flag",children:(0,u.jsx)("img",{src:e.flag_url,alt:e.name,title:e.name,className:"flag"})})};function f({handleChange:e,children:t,selectedLanguage:o=null,defaultValue:n=""}){const r=o?.slug?o.slug:n;return(0,u.jsxs)("div",{id:"select-post-language",children:[(0,u.jsx)(h,{language:o}),t&&(0,u.jsx)("select",{value:r,onChange:t=>e(t),id:"pll_post_lang_choice",name:"pll_post_lang_choice",className:"post_lang_choice",children:t})]})}function _({languages:e}){return Array.from(e.values()).map((({slug:e,name:t,w3c:o})=>(0,u.jsx)("option",{value:e,lang:o,children:t},e)))}const m="pll/metabox";o(172);const w=()=>new Promise((function(e){let t=(0,s.subscribe)((function(){const o=(0,s.select)(m)?.getLanguages();o?.size>0&&(t(),e())}))}));if(document.getElementById("widgets-editor")||document.getElementById("customize-controls")){const o={type:"string",default:"every"},c=function(e,n){return["core/widget-area","core/legacy-widget"].find((e=>e===n))||(e.attributes=(0,t.assign)(e.attributes,{pll_lang:o})),e};(0,r.addFilter)("blocks.registerBlockType","pll/lang-choice",c);const g=(0,n.createHigherOrderComponent)((n=>r=>{const c=(0,s.select)(m).getLanguages(),{pll_lang:g}=r.attributes,d=!(0,t.isNil)(g),p=c.get(g);return(0,u.jsxs)(l.Fragment,{children:[(0,u.jsx)(n,{...r}),d&&(0,u.jsx)(i.InspectorControls,{children:(0,u.jsxs)(a.PanelBody,{title:(0,e.__)("Languages","polylang-pro"),children:[(0,u.jsx)("label",{children:(0,e.__)("The block is displayed for:","polylang-pro")}),(0,u.jsxs)(f,{selectedLanguage:p,handleChange:e=>{const t=e.currentTarget.value;r.setAttributes({pll_lang:t})},defaultValue:o.default,children:[(0,u.jsxs)("option",{value:o.default,children:[(0,e.__)("All languages","polylang-pro")," "]}),(0,u.jsx)(_,{languages:c})]})]})})]})}),"withInspectorControl");w().then((function(){(0,r.addFilter)("editor.BlockEdit","pll/lang-choice-with-inspector-controls",g)}))}var x=o(545),b=o(567),j=o.n(b);const v=pll_block_editor_blocks_settings;function y(e){const o=function(o){return()=>{const n=e.attributes[o],{setAttributes:r}=e;let s,l,i={[o]:!n};switch(o){case"show_names":s="show_flags",l=!e.attributes[s];break;case"show_flags":s="show_names",l=!e.attributes[s]}"show_names"!==o&&"show_flags"!==o||n&&l&&(i=(0,t.assign)(i,{[s]:l})),r(i)}},n=o("dropdown"),r=o("show_names"),s=o("show_flags"),l=o("force_home"),i=o("hide_current"),c=o("hide_if_no_translation"),{dropdown:g,show_names:d,show_flags:p,force_home:h,hide_current:f,hide_if_no_translation:_}=e.attributes;return{ToggleControlDropdown:function(){return(0,u.jsx)(a.ToggleControl,{label:v.dropdown,checked:g,onChange:n})},ToggleControlShowNames:function(){return(0,u.jsx)(a.ToggleControl,{label:v.show_names,checked:d,onChange:r})},ToggleControlShowFlags:function(){return(0,u.jsx)(a.ToggleControl,{label:v.show_flags,checked:p,onChange:s})},ToggleControlForceHome:function(){return(0,u.jsx)(a.ToggleControl,{label:v.force_home,checked:h,onChange:l})},ToggleControlHideCurrent:function(){return(0,u.jsx)(a.ToggleControl,{label:v.hide_current,checked:f,onChange:i})},ToggleControlHideIfNoTranslations:function(){return(0,u.jsx)(a.ToggleControl,{label:v.hide_if_no_translation,checked:_,onChange:c})}}}const C=(0,e.__)("Language switcher","polylang-pro"),k=(0,e.__)("Add a language switcher to allow your visitors to select their preferred language.","polylang-pro"),T=(0,e.__)("Language switcher settings","polylang-pro");(0,x.registerBlockType)("polylang/language-switcher",{title:C,description:k,icon:g,category:"widgets",example:{},edit:e=>{const{dropdown:t}=e.attributes,{ToggleControlDropdown:o,ToggleControlShowNames:n,ToggleControlShowFlags:r,ToggleControlForceHome:s,ToggleControlHideCurrent:c,ToggleControlHideIfNoTranslations:g}=y(e);return(0,u.jsxs)(l.Fragment,{children:[(0,u.jsx)(i.InspectorControls,{children:(0,u.jsxs)(a.PanelBody,{title:T,children:[(0,u.jsx)(o,{}),!t&&(0,u.jsx)(n,{}),!t&&(0,u.jsx)(r,{}),(0,u.jsx)(s,{}),!t&&(0,u.jsx)(c,{}),(0,u.jsx)(g,{})]})}),(0,u.jsx)(a.Disabled,{children:(0,u.jsx)(j(),{block:"polylang/language-switcher",attributes:e.attributes})})]})}});const S="polylang/navigation-language-switcher";function B(e,t,o,n){return e.map((e=>({...n(e,t,o),innerBlocks:B(e.innerBlocks,t,o,n)})))}(0,x.registerBlockType)(S,{title:C,description:k,icon:g,category:"widgets",parent:["core/navigation"],attributes:{dropdown:{type:"boolean",default:!1},show_names:{type:"boolean",default:!0},show_flags:{type:"boolean",default:!1},force_home:{type:"boolean",default:!1},hide_current:{type:"boolean",default:!1},hide_if_no_translation:{type:"boolean",default:!1}},transforms:{from:[{type:"block",blocks:["core/navigation-link"],transform:()=>(0,x.createBlock)(S)}]},usesContext:["textColor","customTextColor","backgroundColor","customBackgroundColor","overlayTextColor","customOverlayTextColor","overlayBackgroundColor","customOverlayBackgroundColor","fontSize","customFontSize","showSubmenuIcon","openSubmenusOnClick","style"],example:{},edit:e=>{const{dropdown:t}=e.attributes,{showSubmenuIcon:o,openSubmenusOnClick:n}=e.context,{ToggleControlDropdown:r,ToggleControlShowNames:s,ToggleControlShowFlags:c,ToggleControlForceHome:g,ToggleControlHideCurrent:d,ToggleControlHideIfNoTranslations:p}=y(e);return(0,u.jsxs)(l.Fragment,{children:[(0,u.jsx)(i.InspectorControls,{children:(0,u.jsxs)(a.PanelBody,{title:T,children:[(0,u.jsx)(r,{}),(0,u.jsx)(s,{}),(0,u.jsx)(c,{}),(0,u.jsx)(g,{}),(0,u.jsx)(d,{}),(0,u.jsx)(p,{})]})}),(0,u.jsx)(a.Disabled,{children:(0,u.jsxs)("div",{className:"wp-block-navigation-item",children:[(0,u.jsx)(j(),{block:S,attributes:e.attributes,className:"wp-block-navigation__container block-editor-block-list__layout"}),P(o,n,t)]})})]})}});const N=(e,o,n)=>{if("core/navigation-link"===e.name&&"#pll_switcher"===e.attributes?.url){const e=(0,t.find)(o,{url:"#pll_switcher"}),r=e.meta._pll_menu_item,s=(0,x.createBlock)(S,r);return n[e.id]=s.clientId,s}return e},P=(e,t,o)=>(e||t)&&o?(0,u.jsx)("span",{className:"wp-block-navigation__submenu-icon",children:(0,u.jsx)(p,{})}):null;(0,r.addFilter)("blocks.navigation.__unstableMenuItemsToBlocks","polylang/include-language-switcher",((e,t)=>({...e,innerBlocks:B(e.innerBlocks,t,e.mapping,N)})))})(),this["polylang-pro"]={}})(); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/bulk-translate.js b/wp-content/plugins/polylang-pro/js/build/bulk-translate.js new file mode 100644 index 000000000..8052ef24c --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/bulk-translate.js @@ -0,0 +1,87 @@ +/** + * Bulk translate + * + * @package Polylang-Pro + */ + +jQuery( + function ( $ ) { + var t = this; + + $( '.editinline' ).on( + 'click', + function () { + $( '#pll-translate' ).find( '.cancel' ).trigger( 'click' ); // Close the form on quick edit + } + ); + + $( '#doaction, #doaction2' ).on( + 'click', + function ( e ) { + t.whichBulkButtonId = $( this ).attr( 'id' ); + var n = t.whichBulkButtonId.substr( 2 ); + + if ( 'pll_translate' === $( 'select[name="' + n + '"]' ).val() ) { + e.preventDefault(); + + if ( typeof inlineEditPost !== 'undefined' ) { // Not available for media. + inlineEditPost.revert(); // Close Bulk edit and Quick edit if open. + } + + $( '#pll-translate td' ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length ); + // The hidden tr allows to keep the background color. + // HTML prepended is hardcoded. So prepend is safe and as no need to be escaped. + $( 'table.widefat tbody' ).prepend( $( '#pll-translate' ) ).prepend( '' ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + } else { + $( '#pll-translate' ).find( '.cancel' ).trigger( 'click' ); + } + } + ); + + // Cancel + $( '#pll-translate' ).on( + 'click', + '.cancel', + function () { + // Close the form on any other bulk action + $( '#pll-translate' ).siblings( '.hidden' ).remove(); + // #pll-translate is built and come from server side and is well escaped when necessary + $( '#pll-bulk-translate' ).append( $( '#pll-translate' ) ); //phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + // Move focus back to the Bulk Action button that was activated. + $( '#' + t.whichBulkButtonId ).trigger( 'focus' ); + } + ); + + // Act when pressing enter or esc + $( '#pll-translate' ).on( + 'keydown', + function ( event ) { + if ( 'Enter' === event.key && ! $( event.target ).hasClass( 'cancel' ) ) { + event.preventDefault(); + $( this ).find( 'input[type=submit]' ).trigger( 'click' ); + } + if ( 'Escape' === event.key ) { + event.preventDefault(); + $( this ).find( '.cancel' ).trigger( 'click' ); + } + } + ); + + // Clean DOM in case of file download + $( '#posts-filter' ).on( + 'submit', + function () { + $( '.settings-error' ).remove(); + setTimeout( + function () { + $( 'input[type=checkbox]:checked' ).attr( 'checked', false ); + $( '#pll-translate' ).find( '.cancel' ).trigger( 'click' ); + }, + 500 + ); + } + ); + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/bulk-translate.min.js b/wp-content/plugins/polylang-pro/js/build/bulk-translate.min.js new file mode 100644 index 000000000..e0b34d9f0 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/bulk-translate.min.js @@ -0,0 +1 @@ +jQuery((function(t){var e=this;t(".editinline").on("click",(function(){t("#pll-translate").find(".cancel").trigger("click")})),t("#doaction, #doaction2").on("click",(function(n){e.whichBulkButtonId=t(this).attr("id");var l=e.whichBulkButtonId.substr(2);"pll_translate"===t('select[name="'+l+'"]').val()?(n.preventDefault(),"undefined"!=typeof inlineEditPost&&inlineEditPost.revert(),t("#pll-translate td").attr("colspan",t("th:visible, td:visible",".widefat:first thead").length),t("table.widefat tbody").prepend(t("#pll-translate")).prepend('')):t("#pll-translate").find(".cancel").trigger("click")})),t("#pll-translate").on("click",".cancel",(function(){t("#pll-translate").siblings(".hidden").remove(),t("#pll-bulk-translate").append(t("#pll-translate")),t("#"+e.whichBulkButtonId).trigger("focus")})),t("#pll-translate").on("keydown",(function(e){"Enter"!==e.key||t(e.target).hasClass("cancel")||(e.preventDefault(),t(this).find("input[type=submit]").trigger("click")),"Escape"===e.key&&(e.preventDefault(),t(this).find(".cancel").trigger("click"))})),t("#posts-filter").on("submit",(function(){t(".settings-error").remove(),setTimeout((function(){t("input[type=checkbox]:checked").attr("checked",!1),t("#pll-translate").find(".cancel").trigger("click")}),500)}))})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/classic-editor.js b/wp-content/plugins/polylang-pro/js/build/classic-editor.js new file mode 100644 index 000000000..def396974 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/classic-editor.js @@ -0,0 +1,451 @@ +/******/ "use strict"; + +;// ./vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js +/** + * @package Polylang + */ + +const languagesList = jQuery( '.post_lang_choice' ); + +// Dialog box for alerting the user about a risky changing. +const initializeConfirmationModal = () => { + // We can't use underscore or lodash in this common code because it depends of the context classic or block editor. + // Classic editor underscore is loaded, Block editor lodash is loaded. + const { __ } = wp.i18n; + + // Create dialog container. + const dialogContainer = jQuery( + '
    ', + { + id: 'pll-dialog', + style: 'display:none;' + } + ).text( __( 'Are you sure you want to change the language of the current content?', 'polylang' ) ); + + // Put it after languages list dropdown. + // PHPCS ignore dialogContainer is a new safe HTML code generated above. + languagesList.after( dialogContainer ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + + const dialogResult = new Promise( + ( confirm, cancel ) => { + const confirmDialog = ( what ) => { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + switch ( what ) { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + case 'yes': + // Confirm the new language. + languagesList.data( 'old-value', languagesList.children( ':selected' ).first().val() ); + confirm(); + break; + case 'no': + // Revert to the old language. + languagesList.val( languagesList.data( 'old-value' ) ); + cancel( 'Cancel' ); + break; + } + dialogContainer.dialog( 'close' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + } // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + // Initialize dialog box in the case a language is selected but not added in the list. + const dialogOptions = { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: __( 'Change language', 'polylang' ), + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( jQuery( 'body' ).hasClass( 'rtl' ) ) { + jQuery( this ).parent().css( + { + right: jQuery( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + }, + close: function ( event, ui ) { + // When we're closing the dialog box we need to cancel the language change as we click on Cancel button. + confirmDialog( 'no' ); + }, + buttons: [ + { + text: __( 'OK', 'polylang' ), + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: __( 'Cancel', 'polylang' ), + click: function ( event ) { + confirmDialog( 'no' ); + } + } + ] + }; + + if ( jQuery.ui.version >= '1.12.0' ) { + Object.assign( dialogOptions, { classes: { 'ui-dialog': 'pll-confirmation-modal' } } ); + } else { + Object.assign( dialogOptions, { dialogClass: 'pll-confirmation-modal' } ); // jQuery UI 1.11.4 - WP < 5.6 + } + + dialogContainer.dialog( dialogOptions ); + } + ); + return { dialogContainer, dialogResult }; +} + +const initializeLanguageOldValue = () => { + // Keep the old language value to be able to compare to the new one and revert to it if necessary. + languagesList.attr( 'data-old-value', languagesList.children( ':selected' ).first().val() ); +}; + +;// ./vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js +/** + * @package Polylang + */ + +// Translations autocomplete input box. +function initMetaboxAutoComplete() { + jQuery('.tr_lang').each( + function () { + var tr_lang = jQuery(this).attr('id').substring(8); + var td = jQuery(this).parent().parent().siblings('.pll-edit-column'); + + jQuery(this).autocomplete( + { + minLength: 0, + source: ajaxurl + '?action=pll_posts_not_translated' + + '&post_language=' + jQuery('.post_lang_choice').val() + + '&translation_language=' + tr_lang + + '&post_type=' + jQuery('#post_type').val() + + '&_pll_nonce=' + jQuery('#_pll_nonce').val(), + select: function (event, ui) { + jQuery('#htr_lang_' + tr_lang).val(ui.item.id); + // ui.item.link is built and come from server side and is well escaped when necessary + td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + }, + } + ); + + // when the input box is emptied + jQuery(this).on( + 'blur', + function () { + if ( ! jQuery(this).val() ) { + jQuery('#htr_lang_' + tr_lang).val(0); + // Value is retrieved from HTML already generated server side + td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + } + ); + } + ); +} + +;// ./vendor/wpsyntex/polylang/js/src/classic-editor.js +/** + * @package Polylang + */ + + + + + +// tag suggest in metabox +jQuery( + function ( $ ) { + $.ajaxPrefilter( + function ( options, originalOptions, jqXHR ) { + var lang = $( '.post_lang_choice' ).val(); + if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && lang ) { + options.data = 'lang=' + lang + '&' + options.data; + } + } + ); + } +); + +// overrides tagBox.get +jQuery( + function ( $ ) { + // overrides function to add the language + tagBox.get = function ( id ) { + var tax = id.substr( id.indexOf( '-' ) + 1 ); + + // add the language in the $_POST variable + var data = { + action: 'get-tagcloud', + lang: $( '.post_lang_choice' ).val(), + tax: tax + } + + $.post( + ajaxurl, + data, + function ( r, stat ) { + if ( 0 == r || 'success' != stat ) { + r = wpAjax.broken; + } + + // @see code from WordPress core https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/js/tags-box.js#L291 + // @see wp_generate_tag_cloud function which generate the escaped HTML https://github.com/WordPress/WordPress/blob/a02b5cc2a8eecb8e076fbb7cf4de7bd2ec8a8eb1/wp-includes/category-template.php#L966-L975 + r = $( '
    ' ).addClass( 'the-tagcloud' ).attr( 'id', 'tagcloud-' + tax ).html( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + $( 'a', r ).on( + 'click', + function () { + tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this ); + return false; + } + ); + + var tagCloud = $( '#tagcloud-' + tax ); + // add an if else condition to allow modifying the tags outputted when switching the language + var v = tagCloud.css( 'display' ); + if ( v ) { + // See the comment above when r variable is created. + $( '#tagcloud-' + tax ).replaceWith( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith + $( '#tagcloud-' + tax ).css( 'display', v ); + } + else { + // See the comment above when r variable is created. + $( '#' + id ).after( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + } + } + ); + } + } +); + +jQuery( + function ( $ ) { + // collect taxonomies - code partly copied from WordPress + var taxonomies = new Array(); + $( '.categorydiv' ).each( + function () { + var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy; + + taxonomyParts = this_id.split( '-' ); + taxonomyParts.shift(); + taxonomy = taxonomyParts.join( '-' ); + taxonomies.push( taxonomy ); // store the taxonomy for future use + + // add our hidden field in the new category form - for each hierarchical taxonomy + // to set the language when creating a new category + // html code inserted come from html code itself. + $( '#' + taxonomy + '-add-submit' ).before( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.before + $( '' ).attr( 'type', 'hidden' ) + .attr( 'id', taxonomy + '-lang' ) + .attr( 'name', 'term_lang_choice' ) + .attr( 'value', $( '.post_lang_choice' ).val() ) + ); + } + ); + + // Initialize current language to be able to compare if it changes. + initializeLanguageOldValue(); + + // ajax for changing the post's language in the languages metabox + $( '.post_lang_choice' ).on( + 'change', + function ( event ) { + // Initialize the confirmation dialog box. + const confirmationModal = initializeConfirmationModal(); + const { dialogContainer: dialog } = confirmationModal; + let { dialogResult } = confirmationModal; + // The selected option in the dropdown list. + const selectedOption = event.target; + + if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! isEmptyPost() ) { + dialog.dialog( 'open' ); + } else { + dialogResult = Promise.resolve(); + } + + // phpcs:disable PEAR.Functions.FunctionCallSignature.EmptyLine + dialogResult.then( + () => { + var lang = selectedOption.options[selectedOption.options.selectedIndex].lang; // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + var data = { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + action: 'post_lang_choice', + lang: selectedOption.value, + post_type: $( '#post_type' ).val(), + taxonomies: taxonomies, + post_id: $( '#post_ID' ).val(), + _pll_nonce: $( '#_pll_nonce' ).val() + } + + $.post( + ajaxurl, + data, + function ( response ) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function () { + switch ( this.what ) { + case 'translations': // translations fields + // Data is built and come from server side and is well escaped when necessary + $( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + initMetaboxAutoComplete(); + break; + case 'taxonomy': // categories metabox for posts + var tax = this.data; + // @see wp_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L175 + // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/class-walker-category-checklist.php#L89-L111 + $( '#' + tax + 'checklist' ).html( this.supplemental.all ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // @see wp_popular_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L236 + $( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // @see wp_dropdown_categories https://github.com/WordPress/WordPress/blob/5.5.1/wp-includes/category-template.php#L336 + // which is called by PLL_Admin_Classic_Editor::post_lang_choice to generate supplemental.dropdown + $( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith + $( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field + break; + case 'pages': // parent dropdown list for pages + // @see wp_dropdown_pages https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/post-template.php#L1186-L1208 + // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/class-walker-page-dropdown.php#L88 + $( '#parent_id' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + break; + case 'flag': // flag in front of the select dropdown + // Data is built and come from server side and is well escaped when necessary + $( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + break; + case 'permalink': // Sample permalink + var div = $( '#edit-slug-box' ); + if ( '-1' != this.data && div.children().length ) { + // @see get_sample_permalink_html https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/post.php#L1425-L1454 + div.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + break; + } + } + ); + + // Update the old language with the new one to be able to compare it in the next changing. + initializeLanguageOldValue(); + // modifies the language in the tag cloud + $( '.tagcloud-link' ).each( + function () { + var id = $( this ).attr( 'id' ); + tagBox.get( id ); + } + ); + + // Modifies the text direction + $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir ); + $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir ); + $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir ); + + pll.media.resetAllAttachmentsCollections(); + } + ) + }, + () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button. + ); + // phpcs:enable PEAR.Functions.FunctionCallSignature.EmptyLine + + function isEmptyPost() { + const title = $( 'input#title' ).val(); + const content = $( 'textarea#content' ).val(); + const excerpt = $( 'textarea#excerpt' ).val(); + + return ! title && ! content && ! excerpt; + } + } + ); + + initMetaboxAutoComplete(); + } +); + +/** + * @since 3.0 + * + * @namespace pll + */ +var pll = window.pll || {}; + +/** + * @since 3.0 + * + * @namespace pll.media + */ +_.extend( pll, { media: {} } ); + +/** + * @since 3.0 + * + * @alias pll.media + * @memberOf pll + * @namespace + */ +var media = _.extend( + pll.media, /** @lends pll.media.prototype */ + { + /** + * TODO: Find a way to delete references to Attachments collections that are not used anywhere else. + * + * @type {wp.media.model.Attachments} + */ + attachmentsCollections : [], + + /** + * Imitates { @see wp.media.query } but log all Attachments collections created. + * + * @param {Object} [props] + * @return {wp.media.model.Attachments} + */ + query: function ( props ) { + var attachments = pll.media.query.delegate( props ); + + pll.media.attachmentsCollections.push( attachments ); + + return attachments; + }, + + resetAllAttachmentsCollections: function () { + this.attachmentsCollections.forEach( + function ( attachmentsCollection ) { + /** + * First reset the { @see wp.media.model.Attachments } collection. + * Then, if it is mirroring a { @see wp.media.model.Query } collection, + * refresh this one too, so it will fetch new data from the server, + * and then the wp.media.model.Attachments collection will synchronize with the new data. + */ + attachmentsCollection.reset(); + if (attachmentsCollection.mirroring) { + attachmentsCollection.mirroring._hasMore = true; + attachmentsCollection.mirroring.reset(); + } + } + ); + } + } +); + +if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.media ) { + + /** + * @since 3.0 + * + * @memberOf pll.media + */ + media.query = _.extend( + media.query, /** @lends pll.media.query prototype */ + { + /** + * @type Function References WordPress { @see wp.media.query } constructor + */ + delegate: wp.media.query + } + ) + + // Substitute WordPress media query shortcut with our decorated function. + wp.media.query = media.query + +} + diff --git a/wp-content/plugins/polylang-pro/js/build/classic-editor.min.js b/wp-content/plugins/polylang-pro/js/build/classic-editor.min.js new file mode 100644 index 000000000..e2ce48749 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/classic-editor.min.js @@ -0,0 +1 @@ +"use strict";const languagesList=jQuery(".post_lang_choice"),initializeConfirmationModal=()=>{const{__:t}=wp.i18n,a=jQuery("
    ",{id:"pll-dialog",style:"display:none;"}).text(t("Are you sure you want to change the language of the current content?","polylang"));languagesList.after(a);const e=new Promise(((e,l)=>{const n=t=>{switch(t){case"yes":languagesList.data("old-value",languagesList.children(":selected").first().val()),e();break;case"no":languagesList.val(languagesList.data("old-value")),l("Cancel")}a.dialog("close")},i={autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:t("Change language","polylang"),minWidth:600,maxWidth:"100%",open:function(t,a){jQuery("body").hasClass("rtl")&&jQuery(this).parent().css({right:jQuery(this).parent().css("left"),left:"auto"})},close:function(t,a){n("no")},buttons:[{text:t("OK","polylang"),click:function(t){n("yes")}},{text:t("Cancel","polylang"),click:function(t){n("no")}}]};jQuery.ui.version>="1.12.0"?Object.assign(i,{classes:{"ui-dialog":"pll-confirmation-modal"}}):Object.assign(i,{dialogClass:"pll-confirmation-modal"}),a.dialog(i)}));return{dialogContainer:a,dialogResult:e}},initializeLanguageOldValue=()=>{languagesList.attr("data-old-value",languagesList.children(":selected").first().val())};function initMetaboxAutoComplete(){jQuery(".tr_lang").each((function(){var t=jQuery(this).attr("id").substring(8),a=jQuery(this).parent().parent().siblings(".pll-edit-column");jQuery(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+jQuery(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+jQuery("#post_type").val()+"&_pll_nonce="+jQuery("#_pll_nonce").val(),select:function(e,l){jQuery("#htr_lang_"+t).val(l.item.id),a.html(l.item.link)}}),jQuery(this).on("blur",(function(){jQuery(this).val()||(jQuery("#htr_lang_"+t).val(0),a.html(a.siblings(".hidden").children().clone()))}))}))}jQuery((function(t){t.ajaxPrefilter((function(a,e,l){var n=t(".post_lang_choice").val();"string"==typeof a.data&&-1!==a.url.indexOf("action=ajax-tag-search")&&n&&(a.data="lang="+n+"&"+a.data)}))})),jQuery((function(t){tagBox.get=function(a){var e=a.substr(a.indexOf("-")+1),l={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:e};t.post(ajaxurl,l,(function(l,n){0!=l&&"success"==n||(l=wpAjax.broken),l=t("
    ").addClass("the-tagcloud").attr("id","tagcloud-"+e).html(l),t("a",l).on("click",(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}));var i=t("#tagcloud-"+e).css("display");i?(t("#tagcloud-"+e).replaceWith(l),t("#tagcloud-"+e).css("display",i)):t("#"+a).after(l)}))}})),jQuery((function(t){var a=new Array;t(".categorydiv").each((function(){var e,l;(e=t(this).attr("id").split("-")).shift(),l=e.join("-"),a.push(l),t("#"+l+"-add-submit").before(t("").attr("type","hidden").attr("id",l+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))})),initializeLanguageOldValue(),t(".post_lang_choice").on("change",(function(e){const l=initializeConfirmationModal(),{dialogContainer:n}=l;let{dialogResult:i}=l;const o=e.target;t(this).data("old-value")===o.value||function(){const a=t("input#title").val(),e=t("textarea#content").val(),l=t("textarea#excerpt").val();return!a&&!e&&!l}()?i=Promise.resolve():n.dialog("open"),i.then((()=>{var e=o.options[o.options.selectedIndex].lang,l=t('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),n={action:"post_lang_choice",lang:o.value,post_type:t("#post_type").val(),taxonomies:a,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,n,(function(a){var n=wpAjax.parseAjaxResponse(a,"pll-ajax-response");t.each(n.responses,(function(){switch(this.what){case"translations":t(".translations").html(this.data),initMetaboxAutoComplete();break;case"taxonomy":var a=this.data;t("#"+a+"checklist").html(this.supplemental.all),t("#"+a+"checklist-pop").html(this.supplemental.populars),t("#new"+a+"_parent").replaceWith(this.supplemental.dropdown),t("#"+a+"-lang").val(t(".post_lang_choice").val());break;case"pages":t("#parent_id").html(this.data);break;case"flag":t(".pll-select-flag").html(this.data);break;case"permalink":var e=t("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.html(this.data)}})),initializeLanguageOldValue(),t(".tagcloud-link").each((function(){var a=t(this).attr("id");tagBox.get(a)})),t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+l),t("#content_ifr").contents().find("html").attr("lang",e).attr("dir",l),t("#content_ifr").contents().find("body").attr("dir",l),pll.media.resetAllAttachmentsCollections()}))}),(()=>{}))})),initMetaboxAutoComplete()}));var pll=window.pll||{};_.extend(pll,{media:{}});var media=_.extend(pll.media,{attachmentsCollections:[],query:function(t){var a=pll.media.query.delegate(t);return pll.media.attachmentsCollections.push(a),a},resetAllAttachmentsCollections:function(){this.attachmentsCollections.forEach((function(t){t.reset(),t.mirroring&&(t.mirroring._hasMore=!0,t.mirroring.reset())}))}});"undefined"!=typeof wp&&void 0!==wp.media&&(media.query=_.extend(media.query,{delegate:wp.media.query}),wp.media.query=media.query); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/confirmation-modal.js b/wp-content/plugins/polylang-pro/js/build/confirmation-modal.js new file mode 100644 index 000000000..c49fae07e --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/confirmation-modal.js @@ -0,0 +1,125 @@ +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +/* unused harmony exports initializeConfirmationModal, initializeLanguageOldValue */ +/** + * @package Polylang + */ + +const languagesList = jQuery( '.post_lang_choice' ); + +// Dialog box for alerting the user about a risky changing. +const initializeConfirmationModal = () => { + // We can't use underscore or lodash in this common code because it depends of the context classic or block editor. + // Classic editor underscore is loaded, Block editor lodash is loaded. + const { __ } = wp.i18n; + + // Create dialog container. + const dialogContainer = jQuery( + '
    ', + { + id: 'pll-dialog', + style: 'display:none;' + } + ).text( __( 'Are you sure you want to change the language of the current content?', 'polylang' ) ); + + // Put it after languages list dropdown. + // PHPCS ignore dialogContainer is a new safe HTML code generated above. + languagesList.after( dialogContainer ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + + const dialogResult = new Promise( + ( confirm, cancel ) => { + const confirmDialog = ( what ) => { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + switch ( what ) { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + case 'yes': + // Confirm the new language. + languagesList.data( 'old-value', languagesList.children( ':selected' ).first().val() ); + confirm(); + break; + case 'no': + // Revert to the old language. + languagesList.val( languagesList.data( 'old-value' ) ); + cancel( 'Cancel' ); + break; + } + dialogContainer.dialog( 'close' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + } // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + // Initialize dialog box in the case a language is selected but not added in the list. + const dialogOptions = { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: __( 'Change language', 'polylang' ), + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( jQuery( 'body' ).hasClass( 'rtl' ) ) { + jQuery( this ).parent().css( + { + right: jQuery( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + }, + close: function ( event, ui ) { + // When we're closing the dialog box we need to cancel the language change as we click on Cancel button. + confirmDialog( 'no' ); + }, + buttons: [ + { + text: __( 'OK', 'polylang' ), + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: __( 'Cancel', 'polylang' ), + click: function ( event ) { + confirmDialog( 'no' ); + } + } + ] + }; + + if ( jQuery.ui.version >= '1.12.0' ) { + Object.assign( dialogOptions, { classes: { 'ui-dialog': 'pll-confirmation-modal' } } ); + } else { + Object.assign( dialogOptions, { dialogClass: 'pll-confirmation-modal' } ); // jQuery UI 1.11.4 - WP < 5.6 + } + + dialogContainer.dialog( dialogOptions ); + } + ); + return { dialogContainer, dialogResult }; +} + +const initializeLanguageOldValue = () => { + // Keep the old language value to be able to compare to the new one and revert to it if necessary. + languagesList.attr( 'data-old-value', languagesList.children( ':selected' ).first().val() ); +}; + diff --git a/wp-content/plugins/polylang-pro/js/build/confirmation-modal.min.js b/wp-content/plugins/polylang-pro/js/build/confirmation-modal.min.js new file mode 100644 index 000000000..4cc957b50 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/confirmation-modal.min.js @@ -0,0 +1 @@ +"use strict";var __webpack_require__={d:(e,a)=>{for(var t in a)__webpack_require__.o(a,t)&&!__webpack_require__.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},o:(e,a)=>Object.prototype.hasOwnProperty.call(e,a)},__webpack_exports__={};const languagesList=jQuery(".post_lang_choice"),initializeConfirmationModal=()=>{const{__:e}=wp.i18n,a=jQuery("
    ",{id:"pll-dialog",style:"display:none;"}).text(e("Are you sure you want to change the language of the current content?","polylang"));languagesList.after(a);const t=new Promise(((t,l)=>{const n=e=>{switch(e){case"yes":languagesList.data("old-value",languagesList.children(":selected").first().val()),t();break;case"no":languagesList.val(languagesList.data("old-value")),l("Cancel")}a.dialog("close")},i={autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:e("Change language","polylang"),minWidth:600,maxWidth:"100%",open:function(e,a){jQuery("body").hasClass("rtl")&&jQuery(this).parent().css({right:jQuery(this).parent().css("left"),left:"auto"})},close:function(e,a){n("no")},buttons:[{text:e("OK","polylang"),click:function(e){n("yes")}},{text:e("Cancel","polylang"),click:function(e){n("no")}}]};jQuery.ui.version>="1.12.0"?Object.assign(i,{classes:{"ui-dialog":"pll-confirmation-modal"}}):Object.assign(i,{dialogClass:"pll-confirmation-modal"}),a.dialog(i)}));return{dialogContainer:a,dialogResult:t}},initializeLanguageOldValue=()=>{languagesList.attr("data-old-value",languagesList.children(":selected").first().val())}; \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.js b/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.js new file mode 100644 index 000000000..854d2cdac --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.js @@ -0,0 +1,24 @@ +/******/ "use strict"; +/** + * @package Polylang + */ + +/** + * Filters requests for translatable entities. + * This logic is shared across all Polylang plugins. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @param {Array} filteredRoutes + * @param {CallableFunction} filter + * @returns {APIFetchOptions} + */ +const filterPathMiddleware = ( options, filteredRoutes, filter ) => { + const cleanPath = options.path.split( '?' )[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'. + + return Object.values( filteredRoutes ).find( ( path ) => cleanPath === path ) ? filter( options ) : options; +} + +/* unused harmony default export */ var __WEBPACK_DEFAULT_EXPORT__ = ((/* unused pure expression or super */ null && (filterPathMiddleware))); + diff --git a/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.min.js b/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.min.js new file mode 100644 index 000000000..43cd05a33 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/filter-path-middleware.min.js @@ -0,0 +1 @@ +"use strict";const filterPathMiddleware=(t,e,l)=>{const r=t.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(e).find((t=>r===t))?l(t):t};var __WEBPACK_DEFAULT_EXPORT__=null; \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/languages-step.js b/wp-content/plugins/polylang-pro/js/build/languages-step.js new file mode 100644 index 000000000..8077fa908 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/languages-step.js @@ -0,0 +1,303 @@ +/** + * @package Polylang + */ + +jQuery( + function ( $ ) { + var addLanguageForm = $( '.languages-step' ); // Form element. + var languageFields = $( '#language-fields' ); // Element where to append hidden fields for creating language. + var languagesTable = $( '#languages' ); // Table element contains languages list to create. + var languagesListTable = $( '#languages tbody' ); // Table rows with languages list to create. + var definedLanguagesListTable = $( '#defined-languages tbody' ); // Table rows with already defined languages list. + var languagesList = $( '#lang_list' ); // Select form element with predefined languages without already created languages. + var nextStepButton = $( '[name="save_step"]' ); // The button for continuing to the next step. + var messagesContainer = $( '#messages' ); // Element where to display error messages. + var languagesMap = new Map(); // Languages map object for managing the languages to create. + var dialog = $( '#dialog' ); // Dialog box for alerting the language selected has not been added to the list. + + /** + * Add a language in the list to create it in Polylang settings + * + * @param {object} language The language object + */ + function addLanguage( language ) { + // language properties come from the select dropdown which is built server side and well escaped. + // see template view-wizard-step-languages.php. + var languageValueHtml = $( '' ).text( language.text ).prepend( language.flagUrl ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + var languageTrashIconHtml = $( '' ) + .append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + $( '' ) + .addClass( 'dashicons dashicons-trash' ) + .attr( 'data-language', language.locale ) + .append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + $( '' ) + .addClass( 'screen-reader-text' ) + .text( pll_wizard_params.i18n_remove_language_icon ) + ) + ); + // see the comment and the hardcoded code above. languageTrashIconHtml and languageValueHtml are safe. + var languageLineHtml = $( '' ).prepend( languageTrashIconHtml ).prepend( languageValueHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + var languageFieldHtml = $( '' ).attr( + { + type: 'hidden', + name: 'languages[]' + } + ).val( language.locale ); + + languagesList.val( '' ); + languagesList.selectmenu( 'refresh' ); // Refresh jQuery selectmenu widget after changing the value. + + languagesMap.set( language.locale, language ); + + // see above how languageLineHtml is built. + languagesListTable.append( languageLineHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + // Bind click event on trash icon. + languagesListTable.on( + 'click', + 'span[data-language=' + language.locale + ']', + function ( event ) { + event.preventDefault(); + // Remove line in languages table. + $( this ).parents( 'tr' ).remove(); + // Remove input field. + var languageField = languageFields.children( 'input[value=' + $( this ).data( 'language' ) + ']' ).remove(); + // If there is no more languages hide languages table. + if ( languagesListTable.children().length <= 0 ) { + languagesTable.hide(); + } + // Remove language from the Map. + languagesMap.delete( $( this ).data( 'language' ) ); + // Hide error message. + hideError(); + } + ); + // see above how languageFieldHtml is built. + // Add hidden input field for posting the form. + languageFields.append( languageFieldHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + } + + /** + * Display an error message + * + * @param {string} message The message to display + */ + function showError( message ) { + messagesContainer.empty(); + // html is hardcoded and use of jQuery text method which is safe to add message value. + // In addition message is i18n value which is initialized server side in PLL_Wizard::add_step_languages and correctly escaped. + messagesContainer.prepend( $( '

    ' ).addClass( 'error' ).text( message ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + } + + /** + * Hide all error messages and fields in error + */ + function hideError() { + messagesContainer.empty(); + addLanguageForm.find( '.error' ).removeClass( 'error field-in-error' ); + } + + /** + * Style the field to indicate where the error is + * + * @param {object} field The jQuery element which is in error + */ + function showFieldInError( field ) { + field.addClass( 'error field-in-error' ); + } + + /** + * Focus on a specific element + * + * @param {object} field The jQuery element which will be focused + */ + function focusOnField( field ) { + field.trigger( 'focus' ); + } + + /** + * Disable a specific button + * + * @param {object} button + */ + function disableButton( button ){ + button.prop( 'disabled', true ); + // Because the button is disabled we need to add the value of the button to ensure it will pass in the request. + addLanguageForm.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + $( '' ).prop( + { + type: 'hidden', + name: button.prop( 'name' ), + value: button.prop( 'value' ) + } + ) + ); + } + + /** + * Remove error when a new selection is done in languages list. + */ + languagesList.on( + 'selectmenuchange', + function () { + hideError();; + } + ); + /** + * Bind click event on "Add language" button + */ + $( '#add-language' ).on( + 'click', + function ( event ) { + hideError(); + var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex]; + if ( '' !== selectedOption.value && ! languagesMap.has( selectedOption.value ) ) { + addLanguage( + { + locale: selectedOption.value, + text: selectedOption.innerText, + name: $( selectedOption ).data( 'language-name' ), + flagUrl: $( selectedOption ).data( 'flag-html' ) + } + ); + // Show table of languages. + languagesTable.show(); + // Put back the focus on the select language field after clicking on "Add language button". + focusOnField( $( '#lang_list-button' ) ); + } else { + var message = pll_wizard_params.i18n_no_language_selected; + if ( languagesMap.has( selectedOption.value ) ) { + message = pll_wizard_params.i18n_language_already_added; + } + showError( message ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + + } + } + ); + + /** + * Bind submit event on "add_lang" form + */ + addLanguageForm.on( + 'submit', + function ( event ) { + // Verify if there is at least one language. + var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0; + var selectedLanguage = $( '#lang_list' ).val(); + if ( languagesMap.size <= 0 && ! isLanguagesAlreadyDefined ) { + if ( '' === selectedLanguage ) { + showError( pll_wizard_params.i18n_no_language_added ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + } else { + showError( pll_wizard_params.i18n_add_language_needed ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#add-language' ) ); // Put the focus on the "Add language" button. + } + return false; + } + // Verify if the language has been added in the list otherwise display a dialog box to confirm what to do. + if ( '' !== selectedLanguage ) { + // Verify we don't add a duplicate language before opening the dialog box otherwise display an error message. + if ( ! languagesMap.has( selectedLanguage ) ) { + dialog.dialog( 'open' ); + } else { + showError( pll_wizard_params.i18n_language_already_added ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + } + return false; + } + disableButton( nextStepButton ); + } + ); + + // Is there an error return by PHP ? + var searchParams = new URLSearchParams( document.location.search ); + if ( searchParams.has( 'activate_error' ) ) { + // If the error code exists, display it. + if ( undefined !== pll_wizard_params[ searchParams.get( 'activate_error' ) ] ) { + showError( pll_wizard_params[ searchParams.get( 'activate_error' ) ] ); + } + } + + function confirmDialog( what ) { + switch ( what ) { + case 'yes': + var selectedOption = $( '#lang_list' ).children( ':selected' ); + addLanguage( + { + locale: selectedOption[0].value, + text: selectedOption[0].innerText, + name: $( selectedOption ).data( 'language-name' ), + flagUrl: $( selectedOption ).data( 'flag-html' ) + } + ); + break; + case 'no': + // Empty select form field and submit again the form. + languagesList.val( '' ); + break; + case 'ignore': + } + dialog.dialog( 'close' ); + if ( 'ignore' === what ) { + focusOnField( $( '#lang_list-button' ) ); + } else { + addLanguageForm.submit(); + } + } + + // Initialize dialog box in the case a language is selected but not added in the list. + dialog.dialog( + { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: pll_wizard_params.i18n_dialog_title, + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( $( 'body' ).hasClass( 'rtl' ) ) { + $( this ).parent().css( + { + right: $( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + // Display language name and flag information in dialog box. + $( this ).find( '#dialog-language' ).text( $( '#lang_list' ).children( ':selected' ).first().text() ); + // language properties come from the select dropdown #lang_list which is built server side and well escaped. + // see template view-wizard-step-languages.php. + $( this ).find( '#dialog-language-flag' ).empty().prepend( $( '#lang_list' ).children( ':selected' ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + }, + buttons: [ + { + text: pll_wizard_params.i18n_dialog_yes_button, + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: pll_wizard_params.i18n_dialog_no_button, + click: function ( event ) { + confirmDialog( 'no' ); + } + }, + { + text: pll_wizard_params.i18n_dialog_ignore_button, + click: function ( event ) { + confirmDialog( 'ignore' ); + } + } + ] + } + ) + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/languages-step.min.js b/wp-content/plugins/polylang-pro/js/build/languages-step.min.js new file mode 100644 index 000000000..64ce94e2b --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/languages-step.min.js @@ -0,0 +1 @@ +jQuery((function(a){var e=a(".languages-step"),n=a("#language-fields"),t=a("#languages"),l=a("#languages tbody"),i=a("#defined-languages tbody"),r=a("#lang_list"),d=a('[name="save_step"]'),s=a("#messages"),o=new Map,g=a("#dialog");function u(e){var i=a("").text(e.text).prepend(e.flagUrl),d=a("").append(a("").addClass("dashicons dashicons-trash").attr("data-language",e.locale).append(a("").addClass("screen-reader-text").text(pll_wizard_params.i18n_remove_language_icon))),s=a("").prepend(d).prepend(i),g=a("").attr({type:"hidden",name:"languages[]"}).val(e.locale);r.val(""),r.selectmenu("refresh"),o.set(e.locale,e),l.append(s),l.on("click","span[data-language="+e.locale+"]",(function(e){e.preventDefault(),a(this).parents("tr").remove();n.children("input[value="+a(this).data("language")+"]").remove();l.children().length<=0&&t.hide(),o.delete(a(this).data("language")),c()})),n.append(g)}function p(e){s.empty(),s.prepend(a("

    ").addClass("error").text(e))}function c(){s.empty(),e.find(".error").removeClass("error field-in-error")}function _(a){a.addClass("error field-in-error")}function m(a){a.trigger("focus")}r.on("selectmenuchange",(function(){c()})),a("#add-language").on("click",(function(e){c();var n=e.currentTarget.form.lang_list.options[e.currentTarget.form.lang_list.selectedIndex];if(""===n.value||o.has(n.value)){var l=pll_wizard_params.i18n_no_language_selected;o.has(n.value)&&(l=pll_wizard_params.i18n_language_already_added),p(l),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))}else u({locale:n.value,text:n.innerText,name:a(n).data("language-name"),flagUrl:a(n).data("flag-html")}),t.show(),m(a("#lang_list-button"))})),e.on("submit",(function(n){var t,l=i.children().length>0,s=a("#lang_list").val();return o.size<=0&&!l?(""===s?(p(pll_wizard_params.i18n_no_language_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):(p(pll_wizard_params.i18n_add_language_needed),_(r.next("span.ui-selectmenu-button")),m(a("#add-language"))),!1):""!==s?(o.has(s)?(p(pll_wizard_params.i18n_language_already_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):g.dialog("open"),!1):((t=d).prop("disabled",!0),void e.append(a("").prop({type:"hidden",name:t.prop("name"),value:t.prop("value")})))}));var f=new URLSearchParams(document.location.search);function h(n){switch(n){case"yes":var t=a("#lang_list").children(":selected");u({locale:t[0].value,text:t[0].innerText,name:a(t).data("language-name"),flagUrl:a(t).data("flag-html")});break;case"no":r.val("")}g.dialog("close"),"ignore"===n?m(a("#lang_list-button")):e.submit()}f.has("activate_error")&&void 0!==pll_wizard_params[f.get("activate_error")]&&p(pll_wizard_params[f.get("activate_error")]),g.dialog({autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:pll_wizard_params.i18n_dialog_title,minWidth:600,maxWidth:"100%",open:function(e,n){a("body").hasClass("rtl")&&a(this).parent().css({right:a(this).parent().css("left"),left:"auto"}),a(this).find("#dialog-language").text(a("#lang_list").children(":selected").first().text()),a(this).find("#dialog-language-flag").empty().prepend(a("#lang_list").children(":selected").data("flag-html"))},buttons:[{text:pll_wizard_params.i18n_dialog_yes_button,click:function(a){h("yes")}},{text:pll_wizard_params.i18n_dialog_no_button,click:function(a){h("no")}},{text:pll_wizard_params.i18n_dialog_ignore_button,click:function(a){h("ignore")}}]})})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.js b/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.js new file mode 100644 index 000000000..75ad1a50c --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.js @@ -0,0 +1,220 @@ +/** + * @package Polylang-Pro + */ + +const { addAction } = wp.hooks; + +const pllMachineTranslation = { + /** + * Init. + */ + init: () => { + if ( document.readyState !== 'loading' ) { + pllMachineTranslation.ajaxButton.attachEvent(); + pllMachineTranslation.dataUsage.fetchData(); + } else { + document.addEventListener( 'DOMContentLoaded', pllMachineTranslation.ajaxButton.attachEvent ); + document.addEventListener( 'DOMContentLoaded', pllMachineTranslation.dataUsage.fetchData ); + } + addAction( 'pll_settings_saved', 'polylang-pro', pllMachineTranslation.saveSettings.highlightRow ); + }, + + /** + * Resets a field's row. + * + * @param {HTMLElement} fieldRow Field's row. + */ + resetFieldRow: ( fieldRow ) => { + fieldRow.querySelectorAll( '.pll-message-shown' ).forEach( ( el ) => { + el.classList.remove( 'pll-message-shown' ); + } ); + fieldRow.classList.remove( 'notice-success', 'notice-warning', 'notice-error', 'notice-alt' ); + fieldRow.querySelectorAll( '.pll-error-message-text' ).forEach( ( el ) => { + el.textContent = ''; + } ); + }, + + /** + * Displays an error message under the field by adding HTML classes. + * + * @param {HTMLElement} fieldRow Field's row. + * @param {String} messageClass HTML class of the error message to display. + * @param {String} type Type of the error: `'error'` or `'warning'`. + */ + displayErrorMessage: ( fieldRow, messageClass, type = 'error' ) => { + if ( messageClass ) { + fieldRow.querySelectorAll( '.' + messageClass ).forEach( ( el ) => { + el.classList.add( 'pll-message-shown' ); + } ); + } + fieldRow.classList.add( 'notice-' + type, 'notice-alt' ); + }, + + ajaxButton: { + /** + * Attaches an event to `.pll-ajax-button` buttons to trigger AJAX requests. + */ + attachEvent: () => { + document.querySelectorAll( '.pll-ajax-button' ).forEach( ( el ) => { + el.addEventListener( 'click', ( event ) => { + const button = event.target; + const action = button.getAttribute( 'data-action' ); + const nonce = button.getAttribute( 'data-nonce' ); + const fieldRow = button.closest( 'tr' ); + const errorElms = fieldRow.querySelectorAll( '.pll-error-message-text' ); + + if ( ! action || ! nonce || ! fieldRow || ! errorElms.length || button.getAttribute( 'disabled' ) ) { + return; + } + + const urlParams = { 'action': action, '_pll_nonce': nonce, 'pll_ajax_settings': 1 }; + fieldRow.querySelectorAll( '[data-name]' ).forEach( ( el ) => { + urlParams[ el.getAttribute( 'data-name' ) ] = el.value; + } ); + const url = wp.url.addQueryArgs( ajaxurl, urlParams ); + + button.setAttribute( 'disabled', 'disabled' ); + pllMachineTranslation.resetFieldRow( fieldRow ); + + fetch( url ).then( ( response ) => { + return response.json(); + } ).then( ( json ) => { + button.removeAttribute( 'disabled' ); + + if ( json.success ) { + fieldRow.classList.add( 'notice-success', 'notice-alt' ); + } else { + errorElms[0].textContent = json.data && json.data.message ? json.data.message : ''; + pllMachineTranslation.displayErrorMessage( fieldRow, json.data ? json.data.message_class : '' ); + } + } ).catch( () => { + button.removeAttribute( 'disabled' ); + fieldRow.classList.add( 'notice-error', 'notice-alt' ); + } ); + } ); + } ); + } + }, + + saveSettings: { + /** + * Highlights a settings row in case of error when the settings are saved. + * Hooked to `'pll_settings_saved'`. + * + * @param {Object} response The response from the AJAX call. + * @param {HTMLElement} tr The HTML element containing the module's fields. + */ + highlightRow: ( response, tr ) => { + switch ( response.what ) { + case 'success': + tr.querySelectorAll( '.notice-alt, .pll-message-shown' ).forEach( ( el ) => { + el.classList.remove( 'notice-success', 'notice-warning', 'notice-error', 'notice-alt', 'pll-message-shown' ); + } ); + break; + + case 'error': + const noticeData = pllMachineTranslation.saveSettings.getNoticeData( response.data ); + + if ( ! noticeData.fieldId ) { + break; + } + + const field = document.getElementById( noticeData.fieldId ); + + if ( ! field ) { + break; + } + + const fieldRow = field.closest( 'tr' ); + + if ( ! fieldRow ) { + break; + } + + pllMachineTranslation.resetFieldRow( fieldRow ); + pllMachineTranslation.displayErrorMessage( fieldRow, noticeData.messageClass, noticeData.type ); + break; + } + }, + + /** + * Returns the data contained in the HTML classes of the given element. + * + * @param {String} htmlString HTML string. + * @returns {Object} + */ + getNoticeData: ( htmlString ) => { + const div = document.createElement( 'div' ); + div.innerHTML = htmlString.trim(); // phpcs:ignore WordPressVIPMinimum.JS.InnerHTML.Found + return { + type: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'notice-(success|warning|error)', 'error' ), + fieldId: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'pll-field-id-([^\\s]+)', '' ), // See `Settings\Deepl::is_api_key_valid()` and `Module_Settings::update()`. + messageClass: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'pll-message-class-([^\\s]+)', '' ) // See `Settings\Deepl::is_api_key_valid()` and `Module_Settings::update()`. + }; + }, + + /** + * Returns the part of the given string matching the given pattern. + * + * @param {String} string A string. + * @param {String} pattern A regex pattern. + * @param {String} def String to return if nothing is found. + * @returns {String} + */ + find: ( string, pattern, def ) => { + const matches = ( ' ' + string + ' ' ).match( new RegExp( '\\s' + pattern + '\\s' ) ); + return matches && matches[1] ? matches[1] : def; + } + }, + + dataUsage: { + fetchData: () => { + document.querySelectorAll( '.pll-progress-bar-wrapper' ).forEach( ( el ) => { + const action = el.getAttribute( 'data-action' ); + const nonce = el.getAttribute( 'data-nonce' ); + const spinner = el.querySelectorAll( '.spinner' ).item( 0 ); + const progress = el.querySelectorAll( 'div' ).item( 0 ); + + if ( ! action || ! nonce || ! spinner || ! progress || ! el.parentElement ) { + return; + } + + const description = el.parentElement.querySelectorAll( '.description' ).item( 0 ); + + if ( ! description ) { + return; + } + + const urlParams = { 'action': action, '_pll_nonce': nonce, 'pll_ajax_settings': 1 }; + const url = wp.url.addQueryArgs( ajaxurl, urlParams ); + + fetch( url ).then( ( response ) => { + return response.json(); + } ).then( ( json ) => { + if ( ! json.success || ! json.data.percent ) { + /* + * 2 cases: + * - Error while retrieving the data: display the error message. + * - The character limit is 0: display only the character count. + */ + el.remove(); + description.textContent = json.data.message; + return; + } + + // Display a graphic. + el.replaceChild( document.createTextNode( json.data.percent_formatted ), spinner ); + progress.textContent = json.data.percent_formatted; + progress.style.width = json.data.percent; + description.textContent = json.data.message; + } ).catch( () => { + el.closest( 'tr' ).remove(); + } ); + } ); + } + } +}; + +pllMachineTranslation.init(); + + diff --git a/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.min.js b/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.min.js new file mode 100644 index 000000000..dded68da7 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/machine-translation-settings.min.js @@ -0,0 +1 @@ +const{addAction}=wp.hooks,pllMachineTranslation={init:()=>{"loading"!==document.readyState?(pllMachineTranslation.ajaxButton.attachEvent(),pllMachineTranslation.dataUsage.fetchData()):(document.addEventListener("DOMContentLoaded",pllMachineTranslation.ajaxButton.attachEvent),document.addEventListener("DOMContentLoaded",pllMachineTranslation.dataUsage.fetchData)),addAction("pll_settings_saved","polylang-pro",pllMachineTranslation.saveSettings.highlightRow)},resetFieldRow:e=>{e.querySelectorAll(".pll-message-shown").forEach((e=>{e.classList.remove("pll-message-shown")})),e.classList.remove("notice-success","notice-warning","notice-error","notice-alt"),e.querySelectorAll(".pll-error-message-text").forEach((e=>{e.textContent=""}))},displayErrorMessage:(e,t,a="error")=>{t&&e.querySelectorAll("."+t).forEach((e=>{e.classList.add("pll-message-shown")})),e.classList.add("notice-"+a,"notice-alt")},ajaxButton:{attachEvent:()=>{document.querySelectorAll(".pll-ajax-button").forEach((e=>{e.addEventListener("click",(e=>{const t=e.target,a=t.getAttribute("data-action"),s=t.getAttribute("data-nonce"),n=t.closest("tr"),l=n.querySelectorAll(".pll-error-message-text");if(!a||!s||!n||!l.length||t.getAttribute("disabled"))return;const r={action:a,_pll_nonce:s,pll_ajax_settings:1};n.querySelectorAll("[data-name]").forEach((e=>{r[e.getAttribute("data-name")]=e.value}));const i=wp.url.addQueryArgs(ajaxurl,r);t.setAttribute("disabled","disabled"),pllMachineTranslation.resetFieldRow(n),fetch(i).then((e=>e.json())).then((e=>{t.removeAttribute("disabled"),e.success?n.classList.add("notice-success","notice-alt"):(l[0].textContent=e.data&&e.data.message?e.data.message:"",pllMachineTranslation.displayErrorMessage(n,e.data?e.data.message_class:""))})).catch((()=>{t.removeAttribute("disabled"),n.classList.add("notice-error","notice-alt")}))}))}))}},saveSettings:{highlightRow:(e,t)=>{switch(e.what){case"success":t.querySelectorAll(".notice-alt, .pll-message-shown").forEach((e=>{e.classList.remove("notice-success","notice-warning","notice-error","notice-alt","pll-message-shown")}));break;case"error":const a=pllMachineTranslation.saveSettings.getNoticeData(e.data);if(!a.fieldId)break;const s=document.getElementById(a.fieldId);if(!s)break;const n=s.closest("tr");if(!n)break;pllMachineTranslation.resetFieldRow(n),pllMachineTranslation.displayErrorMessage(n,a.messageClass,a.type)}},getNoticeData:e=>{const t=document.createElement("div");return t.innerHTML=e.trim(),{type:pllMachineTranslation.saveSettings.find(t.firstChild.className,"notice-(success|warning|error)","error"),fieldId:pllMachineTranslation.saveSettings.find(t.firstChild.className,"pll-field-id-([^\\s]+)",""),messageClass:pllMachineTranslation.saveSettings.find(t.firstChild.className,"pll-message-class-([^\\s]+)","")}},find:(e,t,a)=>{const s=(" "+e+" ").match(new RegExp("\\s"+t+"\\s"));return s&&s[1]?s[1]:a}},dataUsage:{fetchData:()=>{document.querySelectorAll(".pll-progress-bar-wrapper").forEach((e=>{const t=e.getAttribute("data-action"),a=e.getAttribute("data-nonce"),s=e.querySelectorAll(".spinner").item(0),n=e.querySelectorAll("div").item(0);if(!(t&&a&&s&&n&&e.parentElement))return;const l=e.parentElement.querySelectorAll(".description").item(0);if(!l)return;const r={action:t,_pll_nonce:a,pll_ajax_settings:1},i=wp.url.addQueryArgs(ajaxurl,r);fetch(i).then((e=>e.json())).then((t=>{if(!t.success||!t.data.percent)return e.remove(),void(l.textContent=t.data.message);e.replaceChild(document.createTextNode(t.data.percent_formatted),s),n.textContent=t.data.percent_formatted,n.style.width=t.data.percent,l.textContent=t.data.message})).catch((()=>{e.closest("tr").remove()}))}))}}};pllMachineTranslation.init(); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.js b/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.js new file mode 100644 index 000000000..b6e9af4dd --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.js @@ -0,0 +1,67 @@ +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +/* unused harmony export initMetaboxAutoComplete */ +/** + * @package Polylang + */ + +// Translations autocomplete input box. +function initMetaboxAutoComplete() { + jQuery('.tr_lang').each( + function () { + var tr_lang = jQuery(this).attr('id').substring(8); + var td = jQuery(this).parent().parent().siblings('.pll-edit-column'); + + jQuery(this).autocomplete( + { + minLength: 0, + source: ajaxurl + '?action=pll_posts_not_translated' + + '&post_language=' + jQuery('.post_lang_choice').val() + + '&translation_language=' + tr_lang + + '&post_type=' + jQuery('#post_type').val() + + '&_pll_nonce=' + jQuery('#_pll_nonce').val(), + select: function (event, ui) { + jQuery('#htr_lang_' + tr_lang).val(ui.item.id); + // ui.item.link is built and come from server side and is well escaped when necessary + td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + }, + } + ); + + // when the input box is emptied + jQuery(this).on( + 'blur', + function () { + if ( ! jQuery(this).val() ) { + jQuery('#htr_lang_' + tr_lang).val(0); + // Value is retrieved from HTML already generated server side + td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + } + ); + } + ); +} + diff --git a/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.min.js b/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.min.js new file mode 100644 index 000000000..076ec8e49 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/metabox-autocomplete.min.js @@ -0,0 +1 @@ +"use strict";var __webpack_require__={d:(e,t)=>{for(var r in t)__webpack_require__.o(t,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},__webpack_exports__={};function initMetaboxAutoComplete(){jQuery(".tr_lang").each((function(){var e=jQuery(this).attr("id").substring(8),t=jQuery(this).parent().parent().siblings(".pll-edit-column");jQuery(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+jQuery(".post_lang_choice").val()+"&translation_language="+e+"&post_type="+jQuery("#post_type").val()+"&_pll_nonce="+jQuery("#_pll_nonce").val(),select:function(r,n){jQuery("#htr_lang_"+e).val(n.item.id),t.html(n.item.link)}}),jQuery(this).on("blur",(function(){jQuery(this).val()||(jQuery("#htr_lang_"+e).val(0),t.html(t.siblings(".hidden").children().clone()))}))}))} \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/metabox-button.js b/wp-content/plugins/polylang-pro/js/build/metabox-button.js new file mode 100644 index 000000000..c5d501d11 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/metabox-button.js @@ -0,0 +1,46 @@ +/** + * Handle the response to a click on a Languages metabox button. + * + * @package Polylang-Pro + */ + +jQuery( + function ( $ ) { + $( '#ml_box' ).on( + 'click', + '.pll-button', + function () { + var value = $( this ).hasClass( 'wp-ui-text-highlight' ); + var id = $( this ).attr( 'id' ); + var post_id = $( '#htr_lang_' + id.replace( 'pll_sync_post[', '' ).replace( ']', '' ) ).val(); + + if ( 'undefined' == typeof( post_id ) || 0 == post_id || value || confirm( pll_sync_post.confirm_text ) ) { + var data = { + action: 'toggle_' + id, + value: value, + post_type: $( '#post_type' ).val(), + _pll_nonce: $( '#_pll_nonce' ).val() + } + + $.post( + ajaxurl, + data, + function ( response ) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function () { + id = id.replace( '[', '\\[' ).replace( ']', '\\]' ); + $( '#' + id ).toggleClass( 'wp-ui-text-highlight' ).attr( 'title', this.data ).children( 'span' ).text( this.data ); + $( 'input[name="' + id + '"]' ).val( ! data['value'] ); + } + ); + } + ); + } + } + ); + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/metabox-button.min.js b/wp-content/plugins/polylang-pro/js/build/metabox-button.min.js new file mode 100644 index 000000000..225be5150 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/metabox-button.min.js @@ -0,0 +1 @@ +jQuery((function(t){t("#ml_box").on("click",".pll-button",(function(){var a=t(this).hasClass("wp-ui-text-highlight"),l=t(this).attr("id"),e=t("#htr_lang_"+l.replace("pll_sync_post[","").replace("]","")).val();if(void 0===e||0==e||a||confirm(pll_sync_post.confirm_text)){var n={action:"toggle_"+l,value:a,post_type:t("#post_type").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,n,(function(a){var e=wpAjax.parseAjaxResponse(a,"pll-ajax-response");t.each(e.responses,(function(){l=l.replace("[","\\[").replace("]","\\]"),t("#"+l).toggleClass("wp-ui-text-highlight").attr("title",this.data).children("span").text(this.data),t('input[name="'+l+'"]').val(!n.value)}))}))}}))})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/nav-menu.js b/wp-content/plugins/polylang-pro/js/build/nav-menu.js new file mode 100644 index 000000000..723ebe01e --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/nav-menu.js @@ -0,0 +1,105 @@ +/** + * Handles the options in the language switcher nav menu metabox. + * + * @package Polylang + */ + +jQuery( + function ( $ ) { + $( '#update-nav-menu' ).on( + 'click', + function ( e ) { + if ( e.target && e.target.className && -1 != e.target.className.indexOf( 'item-edit' ) ) { + $( "input[value='#pll_switcher'][type=text]" ).parent().parent().parent().each( + function () { + var item = $( this ).attr( 'id' ).substring( 19 ); + $( this ).children( 'p:not( .field-move )' ).remove(); // remove default fields we don't need + + // item is a number part of id of parent menu item built by WordPress + // pll_data is built server side with i18n strings without HTML and data retrieved from post meta + // the usage of attr method is safe before append call. + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-title-' + item, + name: 'menu-item-title[' + item + ']', + value: pll_data.title + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-url-' + item, + name: 'menu-item-url[' + item + ']', + value: '#pll_switcher' + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + // a hidden field which exits only if our jQuery code has been executed + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-pll-detect-' + item, + name: 'menu-item-pll-detect[' + item + ']', + value: 1 + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // reverse order + + // add the fields + for ( var i = 0, idsLength = ids.length; i < idsLength; i++ ) { + p = $( '

    ' ).attr( 'class', 'description' ); + // p is hardcoded just above by using attr method which is safe. + $( this ).prepend( p ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + // item is a number part of id of parent menu item built by WordPress + // pll_data is built server side with i18n strings without HTML + label = $( '

    ' ).text( lang[1] ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + td.append( desc ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + } + ); + + td.append( '
    ' ); + // Whitelist because description come from html code generated by WordPress + td.append( span ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/user.min.js b/wp-content/plugins/polylang-pro/js/build/user.min.js new file mode 100644 index 000000000..5ffd380a5 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/user.min.js @@ -0,0 +1 @@ +jQuery((function(e){var n=e("#description").parent(),i=e("#description").clone(),t=n.children(".description").clone();n.children().remove(),e(".biography").each((function(){lang=e(this).attr("name").split("___"),desc=i.clone(),desc.attr("name","description_"+lang[0]),desc.attr("id","description_"+lang[0]),desc.html(e(this).val()),n.append(e("
    ").text(lang[1])),n.append(desc)})),n.append("
    "),n.append(t)})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.js b/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.js new file mode 100644 index 000000000..df565fb34 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.js @@ -0,0 +1,722 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 419: +/***/ ((module) => { + +module.exports = (function() { return this["lodash"]; }()); + +/***/ }), + +/***/ 631: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["apiFetch"]; }()); + +/***/ }), + +/***/ 987: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["data"]; }()); + +/***/ }), + +/***/ 172: +/***/ ((module) => { + +module.exports = (function() { return this["wp"]["url"]; }()); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; + +// EXTERNAL MODULE: external {"this":["wp","apiFetch"]} +var external_this_wp_apiFetch_ = __webpack_require__(631); +var external_this_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_this_wp_apiFetch_); +// EXTERNAL MODULE: external {"this":["wp","data"]} +var external_this_wp_data_ = __webpack_require__(987); +// EXTERNAL MODULE: external {"this":["wp","url"]} +var external_this_wp_url_ = __webpack_require__(172); +// EXTERNAL MODULE: external "lodash" +var external_lodash_ = __webpack_require__(419); +;// ./modules/block-editor/js/sidebar/settings.js +/** + * Module Constants + * + * @package Polylang-Pro + */ + +const settings_MODULE_KEY = 'pll/metabox'; +const settings_MODULE_CORE_EDITOR_KEY = 'core/editor'; +const settings_MODULE_SITE_EDITOR_KEY = 'core/edit-site'; +const settings_MODULE_POST_EDITOR_KEY = 'core/edit-post'; +const MODULE_CORE_KEY = 'core'; +const DEFAULT_STATE = { + languages: [], + selectedLanguage: {}, + translatedPosts: {}, + fromPost: null, + currentTemplatePart: {} +}; +const UNTRANSLATABLE_POST_TYPE = (/* unused pure expression or super */ null && (['wp_template', 'wp_global_styles'])); +const POST_TYPE_WITH_TRASH = (/* unused pure expression or super */ null && (['page'])); +const settings_TEMPLATE_PART_SLUG_SEPARATOR = '___'; // Its value must be synchronized with its equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR +const settings_TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN = '[a-z_-]+'; // Its value must be synchronized with it equivalent in PHP @see PLL_FSE_Template_Slug::SEPARATOR + + +;// ./modules/block-editor/js/sidebar/utils.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + + +/** + * Internal dependencies + */ + + +/** + * Converts array of object to a map. + * + * @param {array} array Array to convert. + * @param {*} key The key in the object used as key to build the map. + * @returns {Map} + */ +function convertArrayToMap( array, key ){ + const map = new Map(); + array.reduce( + function (accumulator, currentValue) { + accumulator.set( currentValue[key], currentValue ); + return accumulator; + }, + map + ); + return map; +} + +/** + * Converts map to an associative array. + * + * @param {Map} map The map to convert. + * @returns {Object} + */ +function convertMapToObject( map ){ + const object = {}; + map.forEach( + function ( value, key, map ) { + const obj = this; + this[key] = isBoolean( value ) ? value.toString() : value; + }, + object + ); + return object; +} + +/** + * Checks whether the current screen is block-based post type editor. + * + * @returns {boolean} True if block editor for post type; false otherwise. + */ +function isPostTypeBlockEditor() { + return !! document.getElementById( 'editor' ); +} + +/** + * Checks whether the current screen is the block-based widgets editor. + * + * @returns {boolean} True if we are in the widgets block editor; false otherwise. + */ +function isWidgetsBlockEditor() { + return !! document.getElementById( 'widgets-editor' ); +} + +/** + * Checks whether the current screen is the customizer widgets editor. + * + * @returns {boolean} True if we are in the customizer widgets editor; false otherwise. + */ +function isWidgetsCustomizerEditor() { + return !! document.getElementById( 'customize-controls' ); +} + + +/** + * Checks whether the current screen is the site editor. + * Takes in account if Gutenberg is activated. + * + * @returns {boolean} True if site editor screen, false otherwise. + */ +function isSiteBlockEditor() { + return !! ( document.getElementById( 'site-editor' ) || document.getElementById( 'edit-site-editor' ) ); +} + +/** + * Returns the post type URL for REST API calls or undefined if the user hasn't the rights. + * + * @param {string} name The post type name. + * @returns {string|undefined} + */ +function getPostsUrl( name ) { + const postTypes = select( 'core' ).getEntitiesByKind( 'postType' ); + const postType = find( postTypes, { name } ); + return postType?.baseURL; +} + +/** + * Gets all query string parameters and convert them in a URLSearchParams object. + * + * @returns {Object} + */ +function getSearchParams() { + // Variable window.location.search is just read for creating and returning a URLSearchParams object to be able to manipulate it more easily. + if ( ! isEmpty( window.location.search ) ) { // phpcs:ignore WordPressVIPMinimum.JS.Window.location + return new URLSearchParams( window.location.search ); // phpcs:ignore WordPressVIPMinimum.JS.Window.location + } else { + return null; + } +} + +/** + * Gets selected language. + * + * @param {string} lang The post language code. + * @returns {Object} The selected language. + */ +function getSelectedLanguage( lang ) { + const languages = select( MODULE_KEY ).getLanguages(); + // Pick up this language as selected in languages list + return languages.get( lang ); +} + +/** + * Gets the default language. + * + * @returns {Object} The default Language. + */ +function getDefaultLanguage() { + const languages = select( MODULE_KEY ).getLanguages(); + return Array.from( languages.values() ).find( lang => lang.is_default ); +} + +/** + * Checks if the given language is the default one. + * + * @param {string} lang The language code to compare with. + * @returns {boolean} True if the given language is the default one. + */ +function isDefaultLanguage( lang ) { + return lang === getDefaultLanguage().slug; +} + +/** + * Gets translated posts. + * + * @param {Object} translations The translated posts object with language codes as keys and ids as values. + * @param {Object.} translations_table The translations table data with language codes as keys and data object as values. + * @returns {Map} + */ +function getTranslatedPosts( translations, translations_table, lang ) { + const translationsTable = getTranslationsTable( translations_table, lang ); + const fromPost = select( MODULE_KEY ).getFromPost(); + let translatedPosts = new Map( Object.entries( [] ) ); + if ( ! isUndefined( translations ) ) { + translatedPosts = new Map( Object.entries( translations ) ); + } + // If we come from another post for creating a new one, we have to update translated posts from the original post + // to be able to update translations attribute of the post + if ( ! isNil( fromPost ) && ! isNil( fromPost.id ) ) { + translationsTable.forEach( + ( translationData, lang ) => { + if ( ! isNil( translationData.translated_post ) && ! isNil( translationData.translated_post.id ) ) { + translatedPosts.set( lang, translationData.translated_post.id ); + } + } + ); + } + return translatedPosts; +} + +/** + * Gets synchronized posts. + * + * @param {Object.} pll_sync_post The synchronized posts object with language codes as keys and boolean values to say if the post is synchronized or not. + * @returns {Map} + */ +function getSynchronizedPosts( pll_sync_post ){ + let synchronizedPosts = new Map( Object.entries( [] ) ); + if ( ! isUndefined( pll_sync_post ) ) { + synchronizedPosts = new Map( Object.entries( pll_sync_post ) ); + } + return synchronizedPosts; +} + +/** + * Gets translations table. + * + * @param {Object.} translationsTableDatas The translations table data object with language codes as keys and data object as values. + * @returns {Map} + */ +function getTranslationsTable( translationsTableDatas ){ + let translationsTable = new Map( Object.entries( [] ) ); + // get translations table datas from post + if ( ! isUndefined( translationsTableDatas ) ) { + // Build translations table map with language slug as key + translationsTable = new Map( Object.entries( translationsTableDatas ) ); + } + return translationsTable; +} + +/** + * Checks if the given request is for saving. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request is for saving. + */ +function isSaveRequest( options ){ + // If data is defined we are in a PUT or POST request method otherwise a GET request method + // Test options.method property isn't efficient because most of REST request which use fetch API doesn't pass this property. + // So, test options.data is necessary to know if the REST request is to save datas. + // However test if options.data is undefined isn't sufficient because some REST request pass a null value as the ServerSideRender Gutenberg component. + if ( ! isNil( options.data ) ) { + return true; + } else { + return false; + } +} + +/** + * Checks if the given request concerns the current post type. + * + * Useful when saving a reusable block contained in another post type. + * Indeed a reusable block is also a post, but its saving request doesn't concern the post currently edited. + * As we don't know the language of the reusable block when the user triggers the reusable block saving action, + * we need to pass the current post language to be sure that the reusable block will have a language. + * + * @see https://github.com/polylang/polylang/issues/437 - Reusable block has no language when it's saved from another post type editing. + * + * @param {Object} options the initial request + * @returns {boolean} True if the request concerns the current post. + */ +function isCurrentPostRequest( options ){ + // Saving translation data is needed only for all post types. + // It's done by verifying options.path matches with one of baseURL of all post types + // and compare current post id with this sent in the request. + + // List of post type baseURLs. + const postTypeURLs = map( select( 'core' ).getEntitiesByKind( 'postType' ), property( 'baseURL' ) ); + + // Id from the post currently edited. + const postId = select( 'core/editor' ).getCurrentPostId(); + + // Id from the REST request. + // options.data never isNil here because it's already verified before in isSaveRequest() function. + const id = options.data.id; + + // Return true + // if REST request baseURL matches with one of the known post type baseURLs + // and the id from the post currently edited corresponds on the id passed to the REST request + // Return false otherwise + return -1 !== postTypeURLs.findIndex( + function ( element ) { + return new RegExp( `${ escapeRegExp( element ) }` ).test( options.path ); + } + ) && postId === id; +} + +/** + * Checks if the given REST request is for the creation of a new template part translation. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part translation creation. + */ +function isTemplatePartTranslationCreationRequest( options ) { + return 'POST' === options.method + && options.path.match( /^\/wp\/v2\/template-parts(?:\/|\?|$)/ ) + && ! isNil( options.data.from_post ) + && ! isNil( options.data.lang ); +} + +/** + * Checks if the given REST request is for the creation of a new template part. + * + * @param {Object} options The initial request. + * @returns {Boolean} True if the request concerns a template part creation. + */ +function isNewTemplatePartCreationRequest( options ) { + return 'POST' === options.method + && options.path.match( /^\/wp\/v2\/template-parts(?:\/|\?|$)/ ) + && isNil( options.data.from_post ) + && isNil( options.data.lang ); +} + +/** + * Adds language as query string parameter to the given request. + * + * @param {Object} options The initial request. + * @param {string} currentLanguage The language code to add to the request. + */ +function addLanguageToRequest( options, currentLanguage ){ + const hasLangArg= (0,external_this_wp_url_.hasQueryArg)( options.path, 'lang' ); + const filterLang = (0,external_lodash_.isUndefined)( options.filterLang ) || options.filterLang; + if ( filterLang && ! hasLangArg ) { + options.path = (0,external_this_wp_url_.addQueryArgs)( + options.path, + { + lang: currentLanguage + } + ); + } +} + +/** + * Adds `include_untranslated` parameter to the request. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function addIncludeUntranslatedParam( options ) { + options.path = addQueryArgs( + options.path, + { + include_untranslated: true + } + ); +} + +/** + * Use addIncludeUntranslatedParam if the given page is a template part page. + * Or if the template editing mode is enabled inside post editing. + * + * @param {Object} options The initial request. + * @returns {void} + */ +function maybeRequireIncludeUntranslatedTemplate( options ) { + const params = ( new URL( document.location ) ).searchParams; + const postType = params.get( 'postType' ); + const postId = params.get( 'postId' ); + const isEditingTemplate = select( MODULE_POST_EDITOR_KEY )?.isEditingTemplate(); + if ( ( "wp_template_part" === postType && ! isNil( postId ) ) || isEditingTemplate ) { + addIncludeUntranslatedParam( options ); + } +} + +/** + * Returns true if the given post is a template part, false otherwise. + * + * @param {Object} post A post object. + * @returns {boolean} Whether it is a template part or not. + */ +function isTemplatePart( post ) { + return 'wp_template_part' === post.type; +} + +/** + * Returns the current post type considering the Site Editor or Post Editor. + * + * @returns {string} The current post type. + */ +function getCurrentPostType() { + if ( isSiteBlockEditor() ) { + return select( MODULE_SITE_EDITOR_KEY ).getEditedPostType(); + } + + return select( MODULE_CORE_EDITOR_KEY ).getCurrentPostType(); +} + +/** + * Returns a regular expression ready to use to perform search and replace. + * + * @returns {RegExp} The regular expression. + */ +function getLangSlugRegex() { + let languageCheckPattern = TEMPLATE_PART_SLUG_CHECK_LANGUAGE_PATTERN; + const languages = select( MODULE_KEY ).getLanguages(); + const languageSlugs = Array.from( languages.keys() ); + if ( ! isEmpty( languageSlugs ) ) { + languageCheckPattern = languageSlugs.join( '|' ); + } + + return new RegExp( `${TEMPLATE_PART_SLUG_SEPARATOR}(?:${languageCheckPattern})$` ); +} + +;// ./modules/block-editor/js/sidebar/store/index.js +/** + * WordPress Dependencies + * + * @package Polylang-Pro + */ + + + + +/** + * Internal dependencies + */ + + + +const actions = { + setLanguages( languages ) { + return { + type: 'SET_LANGUAGES', + languages + }; + }, + setCurrentUser( currentUser, save = false ) { + return { + type: 'SET_CURRENT_USER', + currentUser, + save + }; + }, + setFromPost( fromPost ) { + return { + type: 'SET_FROM_POST', + fromPost, + }; + }, + fetchFromAPI( options ) { + return { + type: 'FETCH_FROM_API', + options, + }; + } +}; + +const store = (0,external_this_wp_data_.createReduxStore)( + settings_MODULE_KEY, + { + reducer( state = DEFAULT_STATE, action ) { + switch ( action.type ) { + case 'SET_LANGUAGES': + return { + ...state, + languages: action.languages + }; + case 'SET_CURRENT_USER': + if ( action.save ) { + updateCurrentUser( action.currentUser ).then( + currentUser => { + action.currentUser = currentUser; + return { + ...state, + currentUser: action.currentUser + }; + } ); + } else { + return { + ...state, + currentUser: action.currentUser + } + }; + case 'SET_FROM_POST': + return { + ...state, + fromPost: action.fromPost + }; + case 'SET_CURRENT_TEMPLATE_PART': + return { + ...state, + currentTemplatePart: action.currentTemplatePart + }; + default: + return state; + } + }, + selectors: { + getLanguages( state ){ + return state.languages; + }, + getCurrentUser( state ){ + return state.currentUser; + }, + getFromPost( state ){ + return state.fromPost; + } + }, + actions, + controls: { + FETCH_FROM_API( action ) { + return external_this_wp_apiFetch_default()( { ...action.options } ); + }, + }, + resolvers: { + * getLanguages(){ + const path = '/pll/v1/languages'; + const languages = yield actions.fetchFromAPI( { path, filterLang: false } ); + return actions.setLanguages( convertArrayToMap( languages, 'slug' ) ); + }, + * getCurrentUser() { + const path = '/wp/v2/users/me'; + const currentUser = yield actions.fetchFromAPI( { path, filterLang: true } ); + return actions.setCurrentUser( currentUser ); + } + } + } +); + +(0,external_this_wp_data_.register)( store ); + +/** + * Save current user when it is wondered. + * + * @param {object} currentUser + * @returns {object} The current user updated. + */ +function updateCurrentUser( currentUser ) { + return Promise.resolve( + external_this_wp_apiFetch_default()( + { + path: '/wp/v2/users/me', + data: currentUser, + method: 'POST' + } + ) + ); +} + +;// ./modules/block-editor/js/middleware/filter-path-middleware.js +/** + * @package Polylang Pro + */ + +/** + * Filters requests for translatable entities. + * This logic is shared accross all Polylang plugins. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @param {Array} filteredRoutes + * @param {CallableFunction} filter + * @returns {APIFetchOptions} + */ +const filterPathMiddleware = ( options, filteredRoutes, filter ) => { + const cleanPath = options.path.split( '?' )[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'. + + return Object.values( filteredRoutes ).find( ( path ) => cleanPath === path ) ? filter( options ) : options; +} + +/* harmony default export */ const filter_path_middleware = (filterPathMiddleware); + +;// ./modules/block-editor/js/widget-editor-plugin.js +/** + * WordPress dependencies + * + * @package Polylang-Pro + */ + +/** + * WordPress dependencies. + */ + + +/** + * Internal dependencies. + */ + // Store used for Polylang block attribute. + + + +/* + * Specific scripts with block editor + */ +external_this_wp_apiFetch_default().use( + ( options, next ) => { + /* + * If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes. + * If `filteredRoutes` is not defined, return early. + */ + if ( 'undefined' !== typeof options.url || 'undefined' === typeof pllFilteredRoutes ) { + return next( options ); + } + + return next( filter_path_middleware( options, pllFilteredRoutes, addParametersToRequest ) ); + } +); + +/** + * Adds parameters according to the context of the request. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @returns {APIFetchOptions} + */ +const addParametersToRequest = ( options ) => { + addLanguageToRequest( options, pllDefaultLanguage ); + + return options; +} + +})(); + +this["polylang-pro"] = __webpack_exports__; +/******/ })() +; \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.min.js b/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.min.js new file mode 100644 index 000000000..f0ae0e302 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/widget-editor-plugin.min.js @@ -0,0 +1 @@ +(()=>{var e={419:e=>{e.exports=function(){return this.lodash}()},631:e=>{e.exports=function(){return this.wp.apiFetch}()},987:e=>{e.exports=function(){return this.wp.data}()},172:e=>{e.exports=function(){return this.wp.url}()}},t={};function r(s){var n=t[s];if(void 0!==n)return n.exports;var a=t[s]={exports:{}};return e[s](a,a.exports,r),a.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var s in t)r.o(t,s)&&!r.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);(()=>{"use strict";var e=r(631),t=r.n(e),s=r(987),n=r(172),a=r(419);const o={languages:[],selectedLanguage:{},translatedPosts:{},fromPost:null,currentTemplatePart:{}};const u={setLanguages:e=>({type:"SET_LANGUAGES",languages:e}),setCurrentUser:(e,t=!1)=>({type:"SET_CURRENT_USER",currentUser:e,save:t}),setFromPost:e=>({type:"SET_FROM_POST",fromPost:e}),fetchFromAPI:e=>({type:"FETCH_FROM_API",options:e})},l=(0,s.createReduxStore)("pll/metabox",{reducer(e=o,r){switch(r.type){case"SET_LANGUAGES":return{...e,languages:r.languages};case"SET_CURRENT_USER":if(!r.save)return{...e,currentUser:r.currentUser};(s=r.currentUser,Promise.resolve(t()({path:"/wp/v2/users/me",data:s,method:"POST"}))).then((t=>(r.currentUser=t,{...e,currentUser:r.currentUser})));case"SET_FROM_POST":return{...e,fromPost:r.fromPost};case"SET_CURRENT_TEMPLATE_PART":return{...e,currentTemplatePart:r.currentTemplatePart};default:return e}var s},selectors:{getLanguages:e=>e.languages,getCurrentUser:e=>e.currentUser,getFromPost:e=>e.fromPost},actions:u,controls:{FETCH_FROM_API:e=>t()({...e.options})},resolvers:{*getLanguages(){const e=yield u.fetchFromAPI({path:"/pll/v1/languages",filterLang:!1});return u.setLanguages(function(e,t){const r=new Map;return e.reduce((function(e,r){return e.set(r[t],r),e}),r),r}(e,"slug"))},*getCurrentUser(){const e=yield u.fetchFromAPI({path:"/wp/v2/users/me",filterLang:!0});return u.setCurrentUser(e)}}});(0,s.register)(l);const c=(e,t,r)=>{const s=e.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(t).find((e=>s===e))?r(e):e};t().use(((e,t)=>void 0!==e.url||"undefined"==typeof pllFilteredRoutes?t(e):t(c(e,pllFilteredRoutes,p))));const p=e=>(function(e,t){const r=(0,n.hasQueryArg)(e.path,"lang");((0,a.isUndefined)(e.filterLang)||e.filterLang)&&!r&&(e.path=(0,n.addQueryArgs)(e.path,{lang:t}))}(e,pllDefaultLanguage),e)})(),this["polylang-pro"]={}})(); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/js/build/widgets.js b/wp-content/plugins/polylang-pro/js/build/widgets.js new file mode 100644 index 000000000..3d2ec2c1b --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/widgets.js @@ -0,0 +1,152 @@ +/** + * Adds a flag to the widgets filtered by a language. + * + * @package Polylang + */ + +jQuery( + function ( $ ) { + var widgets_container, + widgets_selector, + flags, + isBlockEditor = 'undefined' !== typeof wp.blockEditor; + + if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) { + flags = pll_widgets.flags; + } + + /** + * Prepend widget titles with a flag once a language is selected. + * + * @param {object} widget The widget element. + * @return {void} Nothing. + */ + function add_flag( widget ) { + if ( ! flags ) { + return; + } + widget = $( widget ); + var title = isBlockEditor ? widget.prev('h3') : $( '.widget-top .widget-title h3', widget ), + locale = $( '.pll-lang-choice option:selected', widget ).val(), + // Icon is HTML built and come from server side and is well escaped when necessary + icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null; + + if ( icon ) { + icon += '   '; + var current = $( '.pll-lang', title ); + if ( current.length ) { + current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } else { + flag = $( '' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // See the comment above about the icon which is safe. So it is also safe to prepend flag which uses icon. + title.prepend( flag ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + } + } else { + $( '.pll-lang', title ).remove(); + } + } + + if ( isBlockEditor ) { + + widgets_container = $( '.edit-widgets-main-block-list' ); + widgets_selector = '.widget'; + + // Update flags when we click on the legacy widget to display its form. + widgets_container.on( + 'click', + '.wp-block-legacy-widget', + function () { + add_flag( $( this ).find( '.widget' ) ); + } + ); + + } else { + if ( 'undefined' !== typeof wp.customize ) { + + widgets_container = $( '#customize-controls' ); + widgets_selector = '.customize-control .widget'; + + /** + * WP Customizer add control listener. + * + * @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading + * + * @param {object} control The control type. + * @return {void} Nothing. + */ + function customize_add_flag( control ) { + if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) { + return; + } + + /* + * Make sure the widget's contents are embedded; normally this is done + * when the control is expanded, for DOM performance reasons. + */ + control.embedWidgetContent(); + + // Now we know for sure the widget is fully embedded. + add_flag( control.container.find( '.widget' ) ); + } + wp.customize.control.each( customize_add_flag ); + wp.customize.control.bind( 'add', customize_add_flag ); + + } else { + + widgets_container = $( '#widgets-right' ); + widgets_selector = '.widget'; + + } + + // Add flags on load. + $( widgets_selector, widgets_container ).each( + function () { + add_flag( this ); + } + ); + } + + // Update flags. + widgets_container.on( + 'change', + '.pll-lang-choice', + function () { + add_flag( $( this ).parents( '.widget' ) ); + } + ); + + function pll_toggle( a, test ) { + test ? a.show() : a.hide(); + } + + // Remove all options if dropdown is checked. + $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on( + 'change', + '.pll-dropdown', + function () { + var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' ); + pll_toggle( $( '.no-dropdown-' + this_id ), true != $( this ).prop( 'checked' ) ); + } + ); + + // Disallow unchecking both show names and show flags. + var options = ['-show_flags', '-show_names']; + $.each( + options, + function ( i, v ) { + $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on( + 'change', + '.pll' + v, + function () { + var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' ); + if ( true != $( this ).prop( 'checked' ) ) { + $( '#widget-' + this_id + options[ 1 - i ] ).prop( 'checked', true ); + } + } + ); + } + ); + + } +); + diff --git a/wp-content/plugins/polylang-pro/js/build/widgets.min.js b/wp-content/plugins/polylang-pro/js/build/widgets.min.js new file mode 100644 index 000000000..50d281224 --- /dev/null +++ b/wp-content/plugins/polylang-pro/js/build/widgets.min.js @@ -0,0 +1 @@ +jQuery((function(e){var t,i,n,o=void 0!==wp.blockEditor;function l(t){if(n){t=e(t);var i=o?t.prev("h3"):e(".widget-top .widget-title h3",t),l=e(".pll-lang-choice option:selected",t).val(),d=l&&n.hasOwnProperty(l)?n[l]:null;if(d){d+="   ";var s=e(".pll-lang",i);s.length?s.html(d):(flag=e("").addClass("pll-lang").html(d),i.prepend(flag))}else e(".pll-lang",i).remove()}}if("undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(n=pll_widgets.flags),o)i=".widget",(t=e(".edit-widgets-main-block-list")).on("click",".wp-block-legacy-widget",(function(){l(e(this).find(".widget"))}));else{if(void 0!==wp.customize){function d(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),l(e.container.find(".widget")))}t=e("#customize-controls"),i=".customize-control .widget",wp.customize.control.each(d),wp.customize.control.bind("add",d)}else t=e("#widgets-right"),i=".widget";e(i,t).each((function(){l(this)}))}t.on("change",".pll-lang-choice",(function(){l(e(this).parents(".widget"))})),e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll-dropdown",(function(){var t,i=e(this).parent().parent().parent().children(".widget-id").attr("value");t=e(".no-dropdown-"+i),1!=e(this).prop("checked")?t.show():t.hide()}));var s=["-show_flags","-show_names"];e.each(s,(function(t,i){e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll"+i,(function(){var i=e(this).parent().parent().parent().children(".widget-id").attr("value");1!=e(this).prop("checked")&&e("#widget-"+i+s[1-t]).prop("checked",!0)}))}))})); \ No newline at end of file diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Action.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Action.php new file mode 100644 index 000000000..6e6360cfa --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Action.php @@ -0,0 +1,205 @@ +model = $polylang->model; + $this->service = $service; + $this->curlang = &$polylang->curlang; + $this->sync = $polylang->sync; + $this->processor = new Processor( $polylang, $this->service->get_client() ); + $this->user_meta = new PLL_Toggle_User_Meta( sprintf( 'pll_machine_translation_%s', $this->service->get_slug() ) ); + + /* + * Before `PLL_Duplicate::new_post_translation()`. + */ + add_filter( 'use_block_editor_for_post', array( $this, 'new_post_translation' ), 1900 ); + } + + /** + * Fires the content translation. + * + * @since 3.6 + * + * @param bool $is_block_editor Whether the post can be edited or not. + * @return bool + */ + public function new_post_translation( $is_block_editor ) { + global $post, $pagenow; // `$post` is the autosave of the new post. + + if ( $this->done || empty( $post ) || 'post-new.php' !== $pagenow || empty( $_GET['from_post'] ) || empty( $_GET['new_lang'] ) ) { + return $is_block_editor; + } + + // Capability check already done in post-new.php. + check_admin_referer( 'new-post-translation' ); + + if ( ! $this->user_meta->is_active() ) { + return $is_block_editor; + } + + // Prevent a second translation in the block editor. + $this->done = true; + + if ( ! is_string( $_GET['new_lang'] ) || ! is_numeric( $_GET['from_post'] ) ) { + // Invalid data. + return $is_block_editor; + } + + $from_post = get_post( (int) $_GET['from_post'] ); + + if ( ! $from_post instanceof WP_Post ) { + // Invalid post. + return $is_block_editor; + } + + $target_language = $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); + + if ( empty( $target_language ) ) { + // Invalid target language. + return $is_block_editor; + } + + // No current language during machine translation process (to avoid filtering queries). + $current_lang_backup = $this->curlang; + $this->curlang = null; + $container = new PLL_Export_Container( Data::class ); + $export_objects = new PLL_Export_Data_From_Posts( $this->model ); + + $export_objects->send_to_export( $container, array( $from_post ), $target_language ); + + // Save translated data. + $result = $this->processor->translate( $container ); + + // All done, set back current language. + $this->curlang = $current_lang_backup; + + if ( $result->has_errors() ) { + pll_add_notice( $result ); + return $is_block_editor; + } + + $result = $this->processor->save( $container ); + + if ( $result->has_errors() ) { + pll_add_notice( $result ); + return $is_block_editor; + } + + // Ensure global post object is updated. + $to_post = get_post( (int) $this->model->post->get_translation( $from_post->ID, $target_language ) ); + + if ( empty( $to_post ) ) { + // The translated post doesn't exist anymore for some reason. + pll_add_notice( + new WP_Error( + 'pll_machine_translation_no_translation', + __( 'Unable to retrieve the translation.', 'polylang-pro' ) + ) + ); + return $is_block_editor; + } + + $post = $to_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + + // Disable duplication. + remove_filter( 'use_block_editor_for_post', array( $this->sync, 'new_post_translation' ), 5000 ); + add_filter( 'get_user_metadata', array( $this, 'disable_post_duplication' ), 10, 3 ); + + return $is_block_editor; + } + + /** + * Filters the user metas to disable post duplication. + * + * @since 3.6 + * + * @param mixed $value The value to return. + * @param int $object_id ID of the object metadata is for. + * @param string $meta_key Metadata key. + * @return mixed False for the post duplication meta, the original value otherwize. + */ + public function disable_post_duplication( $value, $object_id, $meta_key ) { + return 'pll_duplicate_content' === $meta_key ? false : $value; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button.php new file mode 100644 index 000000000..aa8bc14be --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button.php @@ -0,0 +1,72 @@ +service = $service; + $this->user_meta = new PLL_Toggle_User_Meta( sprintf( 'pll_machine_translation_%s', $this->service->get_slug() ) ); + + $args = array( + 'position' => 'before_post_translations', + 'activate' => sprintf( + /* translators: %s is the name of the machine translation service. */ + __( 'Activate %s machine translation', 'polylang-pro' ), + $this->service->get_name() + ), + 'deactivate' => sprintf( + /* translators: %s is the name of the machine translation service. */ + __( 'Deactivate %s machine translation', 'polylang-pro' ), + $this->service->get_name() + ), + 'icon' => $this->service->get_icon(), + 'priority' => 20, + ); + + parent::__construct( 'pll-machine-translation', $args ); + + add_action( 'admin_notices', array( $this, 'display_errors' ) ); + } + + /** + * Prints translation errors into the page. + * + * @since 3.6 + * + * @return void + */ + public function display_errors() { + settings_errors( 'polylang' ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button_REST.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button_REST.php new file mode 100644 index 000000000..c0794f71a --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Button_REST.php @@ -0,0 +1,98 @@ +service = $service; + $this->user_meta = new PLL_Toggle_User_Meta( sprintf( 'pll_machine_translation_%s', $this->service->get_slug() ) ); + + register_rest_field( + 'user', + $this->user_meta->get_meta_name(), + array( + 'get_callback' => array( $this->user_meta, 'get' ), + 'update_callback' => array( $this->user_meta, 'update' ), + ) + ); + + add_filter( 'pll_block_editor_plugin_settings', array( $this, 'get_service_settings' ) ); + add_filter( 'pll_block_editor_plugin_settings', array( $this, 'get_settings_errors' ) ); + } + + /** + * Adds service properties in UI settings. + * + * @since 3.6 + * + * @param array $settings UI settings. + * @return array Updated UI settings. + */ + public function get_service_settings( $settings ) { + $settings['machine_translation'] = array( + 'slug' => $this->service::get_slug(), + 'name' => $this->service->get_name(), + 'icon' => $this->service->get_icon_properties(), + 'isActive' => $this->service->is_active(), + ); + return $settings; + } + + /** + * Adds machine translation errors in UI settings. + * + * @since 3.6 + * + * @param array $settings UI settings. + * @return array Updated UI settings. + */ + public function get_settings_errors( $settings ) { + $settings_errors = get_settings_errors( 'polylang' ); + + if ( empty( $settings_errors ) ) { + return $settings; + } + + $settings['machine_translation']['errors'] = $settings_errors; + + return $settings; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Clients/Client_Interface.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Clients/Client_Interface.php new file mode 100644 index 000000000..61574254a --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Clients/Client_Interface.php @@ -0,0 +1,45 @@ +api_key = $options['api_key']; + $this->formality = $options['formality']; + } + + /** + * Performs a request to machine translation service. + * + * @since 3.6 + * + * @param Translations $translations Translations object. + * @param PLL_Language $target_language Target language. + * @param PLL_Language|null $source_language Source language, leave empty for automatic detection. + * @return Translations|WP_Error + */ + public function translate( Translations $translations, PLL_Language $target_language, $source_language = null ) { + $tr_strings = array(); + foreach ( $this->split( $translations ) as $batch ) { + $result = $this->translate_batch( $batch, $target_language, $source_language ); + + if ( is_wp_error( $result ) ) { + // Abort early. + return $result; + } + + if ( count( $result ) !== count( $batch ) ) { + return new WP_Error( 'pll_deepl_incomplete_response', __( 'The DeepL response is incomplete.', 'polylang-pro' ) ); + } + + array_push( $tr_strings, ...$result ); + } + + + foreach ( $translations->entries as &$entry ) { + $entry->translations = (array) array_shift( $tr_strings ); + } + + return $translations; + } + + /** + * Splits an array of strings into several batches managable by DeepL API. + * + * @since 3.6 + * + * @param Translations $translations Translations object with entries to split. + * @return string[][] Array of arrays of strings, each ones suitable for DeepL. + */ + private function split( Translations $translations ): array { + $count = 0; + $size = 0; + $chunk = array(); + $chunks = array(); + + foreach ( $translations->entries as $entry ) { + $length = strlen( $entry->singular ); + + ++$count; + $size += $length; + + /* + * A DeepL translation request body must not exceed 128 * 1024 bytes according to the documentation. + * {@see https://www.deepl.com/docs-api/translate-text}. We decrease this limit to 120 * 1024 bytes + * to accound for extra bytes added by the request params (100 bytes) + the JSON encoding of the array. + */ + if ( $count > 50 || $size > 120 * \KB_IN_BYTES ) { + $chunks[] = $chunk; + + $count = 0; + $size = $length; + $chunk = array(); + } + + $chunk[] = $entry->singular; + } + + $chunks[] = $chunk; // Don't forget the last chunk. + + return $chunks; + } + + /** + * Sends a batch of strings to DeepL and returns their translations in the same order. + * + * @since 3.6 + * + * @param string[] $batch Strings to translate. + * @param PLL_Language $target_language Target language. + * @param PLL_Language $source_language Source language, `null` for auto-detection. + * @return string[]|WP_Error + */ + private function translate_batch( $batch, PLL_Language $target_language, $source_language = null ) { + $target_code = Service::get_target_code( $target_language ); + if ( empty( $target_code ) ) { + return new WP_Error( + 'pll_deepl_target_language_unavailable', + sprintf( + /* translators: %1$s is a language name, %2$s is a language locale. */ + __( '%1$s (%2$s) is not available as target language with DeepL.', 'polylang-pro' ), + $target_language->name, + sprintf( + '%s', + $target_language->locale + ) + ), + 'warning' + ); + } + + $body = array( + 'target_lang' => $target_code, + 'tag_handling' => 'html', + 'split_sentences' => '1', + 'formality' => $this->get_formality( $target_language ), + 'text' => $batch, + ); + + if ( ! empty( $source_language ) ) { + $source_code = Service::get_source_code( $source_language ); + if ( empty( $source_code ) ) { + return new WP_Error( + 'pll_deepl_source_language_unavailable', + sprintf( + /* translators: %1$s is a language name, %2$s is a language locale. */ + __( '%1$s (%2$s) is not available as source language with DeepL.', 'polylang-pro' ), + $source_language->name, + sprintf( + '%s', + $source_language->locale + ) + ), + 'warning' + ); + } + $body['source_lang'] = $source_code; + } + + $headers = array( + 'Content-Type' => 'application/json', + ); + + $response = $this->request( + 'POST', + 'translate', + array( + 'headers' => $headers, + 'body' => wp_json_encode( $body ), + ) + ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + $body = json_decode( $response['body'], true ); + + if ( ! is_array( $body ) || empty( $body['translations'] ) ) { + return new WP_Error( 'pll_deepl_no_translations', __( 'No translations have been returned by DeepL.', 'polylang-pro' ) ); + } + + $tr_strings = array(); + foreach ( $body['translations'] as $translation ) { + if ( isset( $translation['text'] ) ) { + $tr_strings[] = $translation['text']; + } + } + + return $tr_strings; + } + + /** + * Sends the request to the client, and returns a response or a `WP_Error` in case of failure. + * + * @since 3.6 + * + * @param string $method The HTTP method to use. + * @param string $endpoint The API endpoint. + * @param array $args The request arguments. + * @return array|WP_Error + */ + private function request( string $method, string $endpoint, array $args = array() ) { + if ( empty( $this->api_key ) ) { + // No need to contact DeepL if the API key is empty. + return $this->check_status_code( 403 ); + } + + $args = array_merge_recursive( + array( + 'headers' => array( + 'Authorization' => 'DeepL-Auth-Key ' . $this->api_key, + ), + 'method' => $method, + ), + $args + ); + + $response = wp_remote_request( + $this->get_route( $endpoint ), + $args + ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + $status_code_error = $this->check_status_code( $response['response']['code'] ); + if ( $status_code_error->has_errors() ) { + return $status_code_error; + } + + if ( empty( $response['body'] ) ) { + return new WP_Error( 'pll_deepl_empty_response_body', __( 'No translations have been returned by DeepL.', 'polylang-pro' ) ); + } + + return $response; + } + + /** + * Checks the HTTP status code. + * + * @see https://github.com/DeepLcom/deepl-php/blob/v1.6.0/src/Translator.php#L691 + * + * @since 3.6 + * + * @param int $code The HTTP response code. + * @return WP_Error + */ + protected function check_status_code( int $code ): WP_Error { + if ( 200 === $code ) { + return new WP_Error(); + } + + switch ( $code ) { + case 403: + return new WP_Error( 'pll_deepl_authentication_failure', __( 'Authentication failure. Please check your DeepL authentication key.', 'polylang-pro' ) ); + case 456: + return new WP_Error( 'pll_deepl_quota_exceeded', __( 'The DeepL quota for this billing period has been exceeded.', 'polylang-pro' ) ); + case 404: + return new WP_Error( 'pll_deepl_not_found', __( 'The DeepL server cannot be reached.', 'polylang-pro' ) ); + case 400: + return new WP_Error( 'pll_deepl_bad_request', __( 'Bad request.', 'polylang-pro' ) ); + case 429: + return new WP_Error( 'pll_deepl_too_many_request', __( 'Too many requests, DeepL servers are currently experiencing high load.', 'polylang-pro' ) ); + case 500: + case 502: + case 503: + return new WP_Error( 'pll_deepl_service_unavailable', __( 'DeepL service unavailable.', 'polylang-pro' ) ); + default: + /* translators: %s is an HTTP status code */ + return new WP_Error( 'pll_deepl_unexpected_status_code', sprintf( __( 'The DeepL server sent an unexpected status code %d.', 'polylang-pro' ), $code ) ); + } + } + + /** + * Tells whether API key is valid. + * + * @since 3.6 + * + * @return WP_Error An empty WP_Error if valid, a filled WP_Error otherwise. + */ + public function is_api_key_valid(): WP_Error { + $response = $this->request( 'GET', 'usage' ); + if ( is_wp_error( $response ) ) { + return $response; + } + + if ( 200 === $response['response']['code'] ) { + return new WP_Error(); + } + + return $this->check_status_code( 403 ); + } + + /** + * Returns current machine translation usage. + * + * @since 3.6 + * + * @return array|WP_Error { + * A `WP_Error` on error, or an array on success with the following keys. + * + * @type int $character_count Character count. + * @type int $character_limit Character limiter. + * } + * + * @phpstan-return array{ + * character_count: int<0, max>, + * character_limit: int<0, max> + * }|WP_Error + */ + public function get_usage() { + $response = $this->request( 'GET', 'usage' ); + if ( is_wp_error( $response ) ) { + return $response; + } + + /** @var array{ + * character_count: int<0, max>, + * character_limit: int<0, max> + * } + */ + $usage = array_merge( + array( + 'character_count' => 0, + 'character_limit' => 0, + ), + (array) json_decode( $response['body'], true ) + ); + + if ( $usage['character_limit'] >= pow( 10, 12 ) ) { + // Usage limit for the "unlimited" plan returns 10^12. + $usage['character_limit'] = 0; + } + + return array( + 'character_count' => max( 0, (int) $usage['character_count'] ), + 'character_limit' => max( 0, (int) $usage['character_limit'] ), + ); + } + + /** + * Returns the route to be used according to the DeepL plan. + * + * @since 3.6 + * + * @param string $endpoint The API endpoint. + * + * @return string + */ + public function get_route( string $endpoint ): string { + return ( $this->is_free_plan() ? self::ROUTE_FREE : self::ROUTE ) . $endpoint; + } + + /** + * Tells if the key comes from a free plan or not. + * + * @See https://www.deepl.com/fr/docs-api/api-access/authentication + * + * @since 3.6 + * + * @return bool True if the key is associated to a free plan, false otherwise. + */ + private function is_free_plan(): bool { + return substr( $this->api_key, -3 ) === ':fx'; + } + + /** + * Gets the formality according to the formality of the locale in priority. + * + * @since 3.6 + * + * @param PLL_Language $language The language object. + * @return string + */ + private function get_formality( PLL_Language $language ): string { + if ( str_ends_with( $language->locale, '_formal' ) ) { + return 'prefer_more'; + } + + if ( str_ends_with( $language->locale, '_informal' ) ) { + return 'prefer_less'; + } + + return $this->formality; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Data.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Data.php new file mode 100644 index 000000000..680f900c3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Data.php @@ -0,0 +1,93 @@ +> + */ + private $translations = array(); + + /** + * Adds a source string to exported data and optionally a pre-existing translated one. + * New types or objects are prepended to data arrays, assuming they are linked to previously added ones. + * Once translated, this allows to import linked objects before the objects they are linked to. + * For example, a category is imported before the post it is linked to. + * + * @since 3.6 + * + * @param array $ref { + * Array containing the content type and optionally the corresponding object ID. + * + * @type string $object_type Object type to be exported (e.g. `post` or `term`). + * @type string $field_type Field type to be exported (e.g. `post_content`, `post_title`...). + * @type int $object_id A unique identifier to retrieve the corresponding object from the database. + * @type string $field_id Optional, a unique identifier to retrieve the corresponding field from the database. + * @type string $encoding Optional, encoding format for the field group. + * } + * @param string $source The source to be translated. + * @param string $target Optional, a preexisting translation, if any. + * @return void + * + * @phpstan-param translationEntryRef $ref + * @phpstan-param non-empty-string $source + */ + public function add_translation_entry( array $ref, string $source, string $target = '' ) { + if ( ! $this->are_entry_parameters_valid( $ref, $source ) ) { + return; + } + + if ( ! isset( $this->translations[ $ref['object_type'] ] ) ) { + $this->translations = array( $ref['object_type'] => array() ) + $this->translations; + } + + if ( ! isset( $this->translations[ $ref['object_type'] ][ $ref['object_id'] ] ) ) { + $this->translations[ $ref['object_type'] ] = array( $ref['object_id'] => new Translations() ) + $this->translations[ $ref['object_type'] ]; + } + + $context = Context::to_string( + array( + Context::FIELD => $ref['field_type'], + Context::ID => isset( $ref['field_id'] ) ? $ref['field_id'] : '', + Context::ENCODING => isset( $ref['encoding'] ) ? $ref['encoding'] : '', + ) + ); + $this->translations[ $ref['object_type'] ][ $ref['object_id'] ]->add_entry( + array( + 'singular' => $source, + 'translations' => array( $target ), + 'context' => $context, + ) + ); + } + + /** + * Returns translated data. + * + * @since 3.6 + * + * @return array + * + * @phpstan-return array> + */ + public function get(): array { + return $this->translations; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Factory.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Factory.php new file mode 100644 index 000000000..b12a15b9b --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Factory.php @@ -0,0 +1,138 @@ +> + */ + const SERVICES = array( + Deepl::class, + ); + + /** + * List of the service instances. + * + * @var Service_Interface[] + * + * @phpstan-var array + */ + private $services = array(); + + /** + * Stores the plugin options. + * + * @var array + */ + private $options; + + /** + * Polylang's model. + * + * @var PLL_Model + */ + private $model; + + /** + * Constructor. + * + * @since 3.6 + * + * @param PLL_Model $model Polylang's model. + */ + public function __construct( PLL_Model $model ) { + $this->options = $model->options; + $this->model = $model; + + $this->options['machine_translation_enabled'] = ! empty( $this->options['machine_translation_enabled'] ); + + if ( ! isset( $this->options['machine_translation_services'] ) || ! is_array( $this->options['machine_translation_services'] ) ) { + $this->options['machine_translation_services'] = array(); + } + } + + /** + * Tells if the machine translation feature is enabled. + * + * @since 3.6 + * + * @return bool + */ + public function is_enabled(): bool { + return $this->options['machine_translation_enabled']; + } + + /** + * Returns the active service. + * + * @since 3.6 + * + * @return Service_Interface|null + */ + public function get_active_service() { + foreach ( self::SERVICES as $service ) { + $service = $this->build_service( $service ); + + if ( $service->is_active() ) { + return $service; + } + } + + return null; + } + + /** + * Returns all services. + * + * @since 3.6 + * @return Service_Interface[] + */ + public function get_all(): array { + foreach ( self::SERVICES as $service ) { + $this->build_service( $service ); + } + + return $this->services; + } + + /** + * Builds a service instance. + * + * @since 3.6 + * + * @param string $class_name Service's slug. + * @return Service_Interface + * + * @phpstan-param class-string $class_name + */ + private function build_service( string $class_name ): Service_Interface { + $slug = $class_name::get_slug(); + if ( ! empty( $this->services[ $slug ] ) ) { + return $this->services[ $slug ]; + } + + if ( ! isset( $this->options['machine_translation_services'][ $slug ] ) || ! is_array( $this->options['machine_translation_services'][ $slug ] ) ) { + $this->options['machine_translation_services'][ $slug ] = array(); + } + + $this->services[ $slug ] = new $class_name( $this->options['machine_translation_services'][ $slug ], $this->model ); + + return $this->services[ $slug ]; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Module_Settings.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Module_Settings.php new file mode 100644 index 000000000..4bf704ea8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Module_Settings.php @@ -0,0 +1,151 @@ + 'machine_translation_enabled' ) ); + + $factory = new Factory( $polylang->model ); + + foreach ( $factory->get_all() as $slug => $service ) { + $this->settings[ $slug ] = $service->get_settings( 'machine_translation_services[{slug}]' ); + } + + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); + } + + /** + * Enqueues scripts and styles. + * + * @since 3.6 + * + * @return void + */ + public function admin_enqueue_scripts() { + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + wp_enqueue_style( + 'pll_machine_translation_settings', + plugins_url( '/css/build/machine-translation-settings' . $suffix . '.css', POLYLANG_ROOT_FILE ), + array(), + POLYLANG_VERSION + ); + + wp_enqueue_script( + 'pll_machine_translation_settings', + plugins_url( '/js/build/machine-translation-settings' . $suffix . '.js', POLYLANG_ROOT_FILE ), + array( 'wp-url', 'wp-hooks' ), + POLYLANG_VERSION, + true + ); + + wp_set_script_translations( 'pll_machine_translation_settings', 'polylang-pro' ); + } + + /** + * Displays the settings form. + * + * @since 3.6 + * + * @return void + */ + protected function form() { + foreach ( $this->settings as $service_settings ) { + $service_settings->print_notices(); + + echo ''; + + $service_settings->print_settings_fields(); + + echo '
    '; + } + } + + /** + * Sanitizes the settings before saving. + * + * @since 3.6 + * + * @param array $options Raw options to save. + * @return array Sanitized options. + */ + protected function update( $options ) { + $new_options = array( + 'machine_translation_services' => array(), + ); + + foreach ( $this->settings as $slug => $service_settings ) { + $service_options = $options['machine_translation_services'][ $slug ] ?? array(); + + // Is the API key provided? + $has_api_key = $service_settings->has_api_key( $service_options ); + + // Sanitize options. + $new_options['machine_translation_services'][ $slug ] = $service_settings->sanitize_options( $service_options ); + + if ( ! $has_api_key ) { + // The API key field was empty before sanitization: don't display any error messages. + continue; + } + + // Check the API key validity. + $error = $service_settings->is_api_key_valid( $new_options['machine_translation_services'][ $slug ] ); + + if ( ! $error->has_errors() ) { + // Valid. + continue; + } + + /** @phpstan-var array{type: 'error'|'warning', message_class: string, field_id: non-falsy-string} */ + $data = array_merge( + array( + 'type' => 'error', // Type of admin notice. + 'message_class' => '', // HTML class of the error message to display (only for types error and warning). + 'field_id' => '', // HTML id of the field. + ), + (array) $error->get_error_data() + ); + + /* + * Overwrites error extra data because `pll_add_notice()` expects a string instead of an array. + * The `pll-field-id-` prefix is used to determine which field to highlight. + * The `pll-message-class-` prefix is used to determine which error message to show. + */ + $error->add_data( "notice-{$data['type']} pll-field-id-{$data['field_id']} pll-message-class-{$data['message_class']}" ); + pll_add_notice( $error ); + } + + // Take care to return only sanitized options. + return $new_options; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Processor.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Processor.php new file mode 100644 index 000000000..0b08964fb --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Processor.php @@ -0,0 +1,136 @@ +translation_models[ PLL_Import_Export::TYPE_POST ] = new PLL_Translation_Post_Model( $polylang ); + $this->translation_models[ PLL_Import_Export::TYPE_TERM ] = new PLL_Translation_Term_Model( $polylang ); + $this->client = $client; + } + + /** + * Translates all data from the given container. + * + * @since 3.6 + * + * @param PLL_Export_Container $container Container with data to translate. + * @return WP_Error Error object. + */ + public function translate( PLL_Export_Container $container ): WP_Error { + $error = new WP_Error(); + + foreach ( $container as &$data ) { + if ( ! $data instanceof Data ) { + continue; + } + + foreach ( $data->get() as $entities ) { + foreach ( $entities as &$translations ) { + $result = $this->client->translate( $translations, $data->get_target_language(), $data->get_source_language() ); + + if ( \is_wp_error( $result ) ) { + // Abort if an error occured. + return $result; + } + + $translations = $result; + } + } + } + + return $error; + } + + /** + * Saves all translated data from the given container into corresponding entities. + * + * @since 3.6 + * + * @param PLL_Export_Container $container Container with data to save. + * @return WP_Error Error object. + */ + public function save( PLL_Export_Container $container ): WP_Error { + $error = new WP_Error(); + + foreach ( $container as $translations ) { + if ( ! $translations instanceof Data ) { + continue; + } + + foreach ( $translations->get() as $type => $entities ) { + if ( ! isset( $this->translation_models[ $type ] ) ) { + continue; + } + + foreach ( $entities as $id => $data ) { + $entry = array( + 'id' => $id, + 'data' => $data, + 'fields' => array( + 'post_status' => 'draft', + ), + ); + + $tr_id = $this->translation_models[ $type ]->translate( $entry, $translations->get_target_language() ); + + if ( 0 === $tr_id ) { + $error->add( + 'pll_machine_translation_no_translate', + sprintf( + /* translators: %1$s is a type of content, post or term, %2$s is a numeric ID. */ + __( '%1$s with ID %2$d could not be translated.', 'polylang-pro' ), + $type, + $id + ) + ); + } + } + } + } + + return $error; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Deepl.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Deepl.php new file mode 100644 index 000000000..7bf6327d5 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Deepl.php @@ -0,0 +1,217 @@ +service_options = array_merge( + array( + 'api_key' => '', + 'formality' => 'default', + ), + $options + ); + $this->model = $model; + } + + /** + * Tells if the service is active. + * + * @since 3.6 + * + * @return bool + */ + public function is_active(): bool { + return ! empty( $this->service_options['api_key'] ); + } + + /** + * Returns a unique identifier of the service. + * + * @since 3.6 + * + * @return string + * + * @phpstan-return non-falsy-string + */ + public static function get_slug(): string { + return 'deepl'; + } + + /** + * Returns the name of the service. + * + * @since 3.6 + * + * @return string + * + * @phpstan-return non-empty-string + */ + public function get_name(): string { + return 'DeepL'; + } + + /** + * Returns the svg properties of the service's logo. + * + * @since 3.6 + * + * @return string[] { + * An array containing the SVG icon properties. + * + * @type string $width The icon width. + * @type string $height The icon height. + * @type string $xmlns The SVG namespace URL. + * @type string $viewBox The position and dimension according to the SVG viewport. + * @type string $path_d The `d` attribute of the SVG `` to define the icon shape. + * } + * @phpstan-return iconProperties + */ + public function get_icon_properties(): array { + return array( + 'width' => '20', + 'height' => '20', + 'xmlns' => 'http://www.w3.org/2000/svg', + 'viewBox' => '0 0 20 20', + 'path_d' => 'M17.407,4.133l-6.837,-3.954c-0.354,-0.206 -0.786,-0.206 -1.14,0l-6.837,3.967c-0.354,0.207 -0.57,0.584 -0.57,0.984l-0,7.921c-0,0.41 0.216,0.79 0.57,0.994l6.837,3.957c0.016,0.01 0.036,0.02 0.052,0.03l3.367,1.95l-0.01,-1.714l0.007,-0.951l0.003,0.016l0,-0.321c0,-0.19 0.099,-0.361 0.246,-0.466l0.22,-0.124l0.105,-0.059l-0.007,-0l3.994,-2.312c0.354,-0.206 0.57,-0.583 0.57,-0.993l0,-7.931c0,-0.41 -0.216,-0.787 -0.57,-0.994Zm-8.194,8.056c0.102,0.4 -0.01,0.843 -0.331,1.151c-0.456,0.446 -1.184,0.446 -1.639,-0c-0.492,-0.469 -0.492,-1.246 -0,-1.715c0.455,-0.446 1.183,-0.446 1.639,-0c0.02,0.02 0.039,0.039 0.059,0.062l2.767,-1.593l0.571,0.321l-3.066,1.774Zm4.8,-2.007c-0.456,0.446 -1.187,0.446 -1.639,0c-0.344,-0.328 -0.446,-0.809 -0.308,-1.229l-0.01,0.006l-3.122,-1.806c-0.016,0.016 -0.029,0.033 -0.045,0.046c-0.456,0.446 -1.184,0.446 -1.64,-0c-0.492,-0.469 -0.492,-1.246 0,-1.715c0.456,-0.446 1.184,-0.446 1.64,-0c0.327,0.315 0.436,0.764 0.324,1.17l3.144,1.83c0.007,-0.007 0.01,-0.01 0.017,-0.016c0.456,-0.446 1.187,-0.446 1.639,-0c0.489,0.468 0.489,1.245 0,1.714Z', + ); + } + + /** + * Returns the service's logo as a svg vector. + * + * @since 3.6 + * + * @return string + * + * @phpstan-return non-empty-string + */ + public function get_icon(): string { + // Icon from https://www.deepl.com/press.html and modified. + $icon_properties = $this->get_icon_properties(); + return sprintf( + '', + $icon_properties['width'], + $icon_properties['height'], + $icon_properties['xmlns'], + $icon_properties['viewBox'], + $icon_properties['path_d'] + ); + } + + /** + * Returns the client that will be processed for the machine translation. + * + * @since 3.6 + * + * @return Client + */ + public function get_client(): Client_Interface { + return new Client( $this->service_options ); + } + + /** + * Returns the object that will print the settings for the machine translation. + * + * @since 3.6 + * + * @param string $input_base_name Base of the name attribute used by the inputs. + * Can contain a placeholder `{slug}` that will be replaced by the service's slug. + * Ex: `machine_translation_services[{slug}]`. + * @return Settings + * + * @phpstan-param non-falsy-string $input_base_name + */ + public function get_settings( string $input_base_name ): Settings_Interface { + return new Settings( $input_base_name, $this->service_options, $this, $this->model ); + } + + /** + * Returns machine translation service code for target language if available. + * + * @since 3.6 + * + * @param PLL_Language $language Language to check. + * @return string Language code, empty if not available. + */ + public static function get_target_code( PLL_Language $language ): string { + if ( empty( self::$languages ) ) { + self::$languages = include POLYLANG_DIR . '/settings/languages.php'; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.NotAbsolutePath + } + + if ( empty( self::$languages[ $language->locale ] ) ) { + return ''; + } + + return self::$languages[ $language->locale ][ static::get_slug() ] ?? ''; + } + + /** + * Returns machine translation service code for source language if available. + * + * @since 3.6 + * + * @param PLL_Language $language Language to check. + * @return string Language code, empty if not available. + */ + public static function get_source_code( PLL_Language $language ): string { + return substr( static::get_target_code( $language ), 0, 2 ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Service_Interface.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Service_Interface.php new file mode 100644 index 000000000..4d1437ff2 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Services/Service_Interface.php @@ -0,0 +1,104 @@ +` to define the icon shape. + * } + * @phpstan-return iconProperties + */ + public function get_icon_properties(): array; + + /** + * Returns the service's logo as a svg vector. + * + * @since 3.6 + * + * @return string + * + * @phpstan-return non-empty-string + */ + public function get_icon(): string; + + /** + * Returns the client that will be processed for the machine translation. + * + * @since 3.6 + * + * @return Client_Interface + */ + public function get_client(): Client_Interface; + + /** + * Returns the object that will print the settings for the machine translation. + * + * @since 3.6 + * + * @param string $input_base_name Base of the name attribute used by the inputs. + * Can contain a placeholder `{slug}` that will be replaced by the service's slug. + * Ex: `machine_translation_services[{slug}]`. + * @return Settings_Interface + * + * @phpstan-param non-falsy-string $input_base_name + */ + public function get_settings( string $input_base_name ): Settings_Interface; +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Deepl.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Deepl.php new file mode 100644 index 000000000..c6157ef5c --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Deepl.php @@ -0,0 +1,480 @@ +service = $service; + $this->model = $model; + $this->input_base_name = str_replace( '{slug}', $service::get_slug(), $input_base_name ); + $this->options = $options; + + add_action( 'wp_ajax_' . self::API_KEY_ACTION, array( $this, 'check_api_key' ) ); + add_action( 'wp_ajax_' . self::USAGE_ACTION, array( $this, 'update_characters_consumption_view' ) ); + } + + /** + * Ajax callback that checks for the API key validity. + * + * @since 3.6 + * + * @return void + * + * @phpstan-return never + */ + public function check_api_key() { + check_ajax_referer( self::API_KEY_ACTION, '_pll_nonce' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + if ( empty( $_GET['api_key'] ) || ! is_string( $_GET['api_key'] ) ) { + wp_send_json_error( + array( + 'message' => esc_html__( 'Please fill in the API key field.', 'polylang-pro' ), + 'message_class' => 'pll-message-error-auth', // See `get_error_message_class()`. + ) + ); + } + + $valid = $this->is_api_key_valid( + array( + 'api_key' => (string) sanitize_text_field( wp_unslash( $_GET['api_key'] ) ), + 'formality' => 'default', + ) + ); + + if ( $valid->has_errors() ) { + // The key is invalid or we had a failure while checking it. + wp_send_json_error( + array( + 'message' => esc_html( $valid->get_error_message() ), + 'message_class' => $this->get_error_message_class( $valid ), + ) + ); + } + + wp_send_json_success(); + } + + /** + * Displays the characters consumption view. + * + * @since 3.6 + * + * @return void + * + * @phpstan-return never + */ + public function update_characters_consumption_view() { + check_ajax_referer( self::USAGE_ACTION, '_pll_nonce' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + $usage = $this->service->get_client()->get_usage(); + + if ( is_wp_error( $usage ) ) { + // Error while retrieving the data: display the error message. + wp_send_json_error( + array( + 'message' => esc_html( + sprintf( + /* translators: %s is an error message. */ + __( 'Error while retrieving the data: %s.', 'polylang-pro' ), + $usage->get_error_message() + ) + ), + ) + ); + } + + if ( ! $usage['character_limit'] ) { + // The character limit is 0: display only the character count. + wp_send_json_success( + array( + 'message' => esc_html( + sprintf( + /* translators: %s is a formatted count number. */ + _n( '%s translated character.', '%s translated characters.', $usage['character_count'], 'polylang-pro' ), + number_format_i18n( $usage['character_count'] ) + ) + ), + ) + ); + } + + // Display a graphic. + $percent = round( $usage['character_count'] * 100 / $usage['character_limit'], 1 ); + $percent = (float) min( $percent, 100 ); + $decimals = 1; + + if ( floor( $percent ) === $percent ) { + $decimals = 0; + } + + wp_send_json_success( + array( + 'percent_formatted' => number_format_i18n( $percent, $decimals ) . '%', + 'percent' => (string) $percent . '%', + 'message' => esc_html( + sprintf( + /* translators: %1$s is a formatted count number, %2$s is a formatted limit number. */ + _n( '%1$s / %2$s translated character.', '%1$s / %2$s translated characters.', $usage['character_count'], 'polylang-pro' ), + number_format_i18n( $usage['character_count'] ), + number_format_i18n( $usage['character_limit'] ) + ) + ), + ) + ); + } + + /** + * Tells if the given service options contain a non-empty authentication key. + * + * @since 3.6 + * + * @param array $options Options for this service. + * @return bool + */ + public function has_api_key( array $options ): bool { + return ! empty( $options['api_key'] ) && is_string( $options['api_key'] ) && '' !== trim( $options['api_key'] ); + } + + /** + * Tells if the authentication key from the given service options is valid by contacting the service. + * + * @since 3.6 + * + * @param array $options Options for this service (must be sanitized beforehand). + * @return WP_Error { + * An empty `WP_Error` if the authentication succeeded. + * In the other cases, the `WP_Error` data will contain an array as follow: + * + * @type string $type `'error'` if the API key is invalid, or `'warning'` if there was an error while + * contacting the service. + * @type string $field_id CSS ID of the field in fault. + * } + */ + public function is_api_key_valid( array $options ): WP_Error { + if ( ! $this->has_api_key( $options ) ) { + $options['api_key'] = ''; + } + + $error = ( new Service( $options, $this->model ) )->get_client()->is_api_key_valid(); + + if ( ! $error->has_errors() ) { + // The key is valid. + return $error; + } + + $error->add_data( + array( + 'message_class' => $this->get_error_message_class( $error ), + 'field_id' => 'pll-deepl-api-key', + ) + ); + + return $error; + } + + /** + * Sanitizes and validates the options for this service. + * + * @since 3.6 + * + * @param array $options Options for this service. + * @return array Validated options. + * + * @phpstan-return DeeplOptions + */ + public function sanitize_options( array $options ): array { + $new_options = array( + 'api_key' => '', + 'formality' => 'default', + ); + + if ( $this->has_api_key( $options ) ) { + $new_options['api_key'] = (string) sanitize_text_field( $options['api_key'] ); + } + + if ( isset( $options['formality'] ) && in_array( $options['formality'], array( 'prefer_more', 'prefer_less' ), true ) ) { + $new_options['formality'] = $options['formality']; + } + + // Return only the validated options. + return $new_options; + } + + /** + * Prints error notices. + * + * @since 3.6 + * + * @return void + */ + public function print_notices() { + if ( $this->service->is_active() ) { + $this->print_view( + 'inner-notices-row', + array( + 'name' => $this->service->get_name(), + 'languages' => $this->get_unsupported_languages(), + ) + ); + } + } + + /** + * Prints settings fields. + * + * @since 3.6 + * + * @return void + */ + public function print_settings_fields() { + if ( $this->service->is_active() ) { + $this->print_view( + 'characters-consumption-row', + array( + 'ajax_action' => self::USAGE_ACTION, + ) + ); + } + + $this->print_view( + 'service-authentication-row', + array( + 'ajax_action' => self::API_KEY_ACTION, + /* translators: %s is a service name. */ + 'button_label' => sprintf( __( 'Check connection to %s', 'polylang-pro' ), $this->service->get_name() ), + 'id' => 'deepl-api-key', + 'message_default' => sprintf( + /* translators: %1$s is an opening link tag leading to account creation, %2$s is an opening link tag leading to the account page, %3$s is a closing link tag. */ + __( '%1$sCreate your account on DeepL%3$s, then %2$sfind your API key at the bottom of your account page%3$s.', 'polylang-pro' ), + '', + '', + '' + ), + 'messages_error' => array( + 'pll-message-error-auth' => sprintf( + /* translators: %1$s is an opening link tag leading to the service's account page, %2$s is a closing link tag. */ + __( '%1$sVerify your API key at the bottom of your DeepL account page%2$s.', 'polylang-pro' ), + '', + '' + ), + 'pll-message-error-unavailable' => sprintf( + /* translators: %1$s is an opening link tag leading to the service's status page, %2$s is a closing link tag. */ + __( 'You can look at %1$sthe DeepL Pro/Free API\'s status%2$s.', 'polylang-pro' ), + '', + '' + ), + ), + 'message_success' => __( 'Your API key is valid.', 'polylang-pro' ), + 'option' => 'api_key', + 'title' => __( 'API key', 'polylang-pro' ), + ) + ); + + $this->print_view( + 'deepl-formality-row', + array( + 'option' => 'formality', + 'formal' => $this->get_active_languages_by_formality( 'formal' ), + 'informal' => $this->get_active_languages_by_formality( 'informal' ), + ) + ); + } + + /** + * Prints a view. + * + * @since 3.6 + * + * @param string $view Name of the view. + * @param array $atts Optional. Data to print. See views headers. + * @return void + */ + private function print_view( string $view, array $atts = array() ) { + $atts['slug'] = $this->service::get_slug(); + $atts['input_base_name'] = $this->input_base_name; + + if ( isset( $atts['option'] ) && ! isset( $atts['value'] ) ) { + $atts['value'] = $this->options[ $atts['option'] ] ?? ''; + } + + include __DIR__ . "/views/view-{$view}.php"; + } + + /** + * Returns the lists of languages that are not supported by the service. + * + * @since 3.6 + * @return string[] Array of language names (and their locale). + * + * @phpstan-return list + */ + private function get_unsupported_languages(): array { + $languages = array(); + + foreach ( $this->model->get_languages_list() as $language ) { + if ( empty( $this->service::get_target_code( $language ) ) ) { + $languages[] = $this->get_language_label( $language ); + } + } + + sort( $languages ); + + return $languages; + } + + /** + * Returns the lists of active formal or informal languages. + * Formal languages have a locale with a `_formal` suffix (`de_DE_formal`, `nl_NL_formal`), + * Informal languages have a `_informal` suffix (`de_CH_informal`). + * + * @since 3.6 + * + * @param string $formality Formality. + * @return string[] Array of arrays of language names (and their locale). + * + * @phpstan-param 'formal'|'informal' $formality + * @phpstan-return list + */ + private function get_active_languages_by_formality( string $formality ): array { + $languages = array(); + + foreach ( $this->model->get_languages_list() as $language ) { + if ( empty( $this->service::get_target_code( $language ) ) ) { + continue; + } + + if ( ! preg_match( "@_{$formality}$@", $language->locale ) ) { + continue; + } + + $languages[] = $this->get_language_label( $language ); + } + + sort( $languages ); + + return $languages; + } + + /** + * Returns a language name and its locale. + * + * @since 3.6 + * + * @param PLL_Language $language A language object. + * @return string + */ + private function get_language_label( PLL_Language $language ): string { + return sprintf( + /* translators: %1$s is a language name, %2$s is a language locale. */ + _x( '%1$s (%2$s)', 'Language label', 'polylang-pro' ), + $language->name, + sprintf( '%s', $language->locale ) + ); + } + + /** + * Returns the HTML class corresponding to the given error. + * See the array keys for the 'messages_error' in `print_settings_fields()`. + * + * @since 3.6 + * + * @param WP_Error $error An error object. + * @return string `'pll-message-error-auth'` in case of authentication failure, `'pll-message-error-unavailable'` in other cases. + */ + private function get_error_message_class( WP_Error $error ): string { + return 'pll_deepl_authentication_failure' === $error->get_error_code() ? 'pll-message-error-auth' : 'pll-message-error-unavailable'; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Settings_Interface.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Settings_Interface.php new file mode 100644 index 000000000..d9e68eef3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/Settings_Interface.php @@ -0,0 +1,72 @@ + + + + + +

     

    + + diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-deepl-formality-row.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-deepl-formality-row.php new file mode 100644 index 000000000..3ccf0d619 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-deepl-formality-row.php @@ -0,0 +1,69 @@ +` tags. + * @param string[] $informal Messages can contain `` tags. + * @param string $input_base_name + * @param string $value + */ + +defined( 'ABSPATH' ) || exit; + +?> + + + + + +

    + +

    + + +

    + true ) ) + ); + ?> +

    + +

    + true ) ) + ); + ?> +

    + + + diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notice.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notice.php new file mode 100644 index 000000000..8ba1c1751 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notice.php @@ -0,0 +1,21 @@ +` and `` tags. + * @param string $slug + * @param string $type Optional. Possible values are `success`, `warning`, `error`, and `info`. Default is `error`. + */ + +defined( 'ABSPATH' ) || exit; + +$tags = array( + 'br' => true, + 'code' => true, +); + +$atts['type'] = ! empty( $atts['type'] ) && in_array( $atts['type'], array( 'success', 'warning', 'info' ), true ) ? $atts['type'] : 'error'; +?> +
    +

    +
    diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notices-row.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notices-row.php new file mode 100644 index 000000000..ea1497849 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-inner-notices-row.php @@ -0,0 +1,20 @@ +
    ', + esc_attr( $atts['ajax_action'] ), + esc_attr( wp_create_nonce( $atts['ajax_action'] ) ) +); diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-service-authentication-row.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-service-authentication-row.php new file mode 100644 index 000000000..87a002ec2 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/Settings/views/view-service-authentication-row.php @@ -0,0 +1,95 @@ +`, and `` tags. + * @param string $message_success Can contain ``, and `` tags. + * @param string[] $messages_warning Can contain ``, and `` tags. + * @param string[] $messages_error Can contain ``, and `` tags. + * @param string $option + * @param string $title + * @param string $value + */ + +defined( 'ABSPATH' ) || exit; + +$tags = array( + 'a' => array( + 'href' => true, + ), + 'code' => true, +); +?> + + + + + +

    + ', + esc_attr( $atts['id'] ), + esc_attr( $atts['input_base_name'] ), + esc_attr( $atts['option'] ), + esc_attr( $atts['value'] ), + esc_attr( $atts['option'] ) + ); + printf( + '', + esc_attr( $atts['ajax_action'] ), + esc_attr( wp_create_nonce( $atts['ajax_action'] ) ), + esc_html( $atts['button_label'] ) + ); + ?> + +

    + + +

    + +

    + + +

    + $error_message ) { + ?> +

    + + + +

    + $error_message ) { + ?> +

    + + + +

    + + + diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/css/machine-translation-settings.css b/wp-content/plugins/polylang-pro/modules/Machine_Translation/css/machine-translation-settings.css new file mode 100644 index 000000000..5e536e841 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/css/machine-translation-settings.css @@ -0,0 +1,103 @@ +.pll-settings .pll-inner-notice { + margin: 5px 0 15px; + border: 1px solid #c3c4c7; + border-left-width: 4px; + padding: 1px 12px; + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); +} + +.form-table .pll-inner-notice { + margin-bottom: 5px; +} + +.pll-settings .notice-success { + border-left-color: #00a32a; +} + +.pll-settings .notice-warning { + border-left-color: #dba617; +} + +.pll-settings .notice-error { + border-left-color: #d63638; +} + +.pll-settings .pll-inner-notice p { + margin: 0.5em 0; + padding: 2px; +} + +.pll-settings .pll-message:not(.pll-origin-message), +.pll-settings .notice-success .pll-origin-message, +.pll-settings .notice-warning .pll-origin-message, +.pll-settings .notice-error .pll-origin-message { + display: none; +} + +.pll-settings .notice-success .pll-success-message, +.pll-settings .notice-warning .pll-warning-message.pll-message-shown, +.pll-settings .notice-error .pll-error-message.pll-message-shown { + display: block; +} + +.pll-settings [disabled] + .spinner, +.pll-progress-bar-wrapper .spinner { + visibility: visible; +} + +.pll-success-message .pll-icon { + color: rgb(18, 91, 145); +} + +.pll-error-message .pll-icon, +.pll-warning-message .pll-icon { + color: rgb(145, 30, 31); +} + +.pll-icon { + font-size: 1.8em; + margin-right: 3px; + margin-left: 1px; + vertical-align: -2px; +} + +.pll-progress-bar-wrapper { + position: relative; + max-width: 500px; + height: 2em; + line-height: 2em; + vertical-align: middle; + text-align: left; + font-size: 2em; + border: 1px solid rgb(64, 70, 72); + border-radius: 4px; + overflow: hidden; + white-space: nowrap; + color: rgb(23, 114, 181); + text-indent: 1em; +} + +.pll-progress-bar-wrapper div { + position: absolute; + height: 100%; + top: 0; + left: 0; + overflow: hidden; + background-color: rgb(23, 114, 181); + color: rgb(232, 230, 227); +} + +.pll-settings [type="password"] + .button { + margin-left: 20px; + margin-right: 0; +} + +.pll-settings [type="password"] + .button + .spinner { + float: none; +} + +.pll-progress-bar-wrapper .spinner { + float: none; + margin: 0; +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/js/machine-translation-settings.js b/wp-content/plugins/polylang-pro/modules/Machine_Translation/js/machine-translation-settings.js new file mode 100644 index 000000000..a418c142a --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/js/machine-translation-settings.js @@ -0,0 +1,219 @@ +/** + * @package Polylang-Pro + */ + +const { addAction } = wp.hooks; + +const pllMachineTranslation = { + /** + * Init. + */ + init: () => { + if ( document.readyState !== 'loading' ) { + pllMachineTranslation.ajaxButton.attachEvent(); + pllMachineTranslation.dataUsage.fetchData(); + } else { + document.addEventListener( 'DOMContentLoaded', pllMachineTranslation.ajaxButton.attachEvent ); + document.addEventListener( 'DOMContentLoaded', pllMachineTranslation.dataUsage.fetchData ); + } + addAction( 'pll_settings_saved', 'polylang-pro', pllMachineTranslation.saveSettings.highlightRow ); + }, + + /** + * Resets a field's row. + * + * @param {HTMLElement} fieldRow Field's row. + */ + resetFieldRow: ( fieldRow ) => { + fieldRow.querySelectorAll( '.pll-message-shown' ).forEach( ( el ) => { + el.classList.remove( 'pll-message-shown' ); + } ); + fieldRow.classList.remove( 'notice-success', 'notice-warning', 'notice-error', 'notice-alt' ); + fieldRow.querySelectorAll( '.pll-error-message-text' ).forEach( ( el ) => { + el.textContent = ''; + } ); + }, + + /** + * Displays an error message under the field by adding HTML classes. + * + * @param {HTMLElement} fieldRow Field's row. + * @param {String} messageClass HTML class of the error message to display. + * @param {String} type Type of the error: `'error'` or `'warning'`. + */ + displayErrorMessage: ( fieldRow, messageClass, type = 'error' ) => { + if ( messageClass ) { + fieldRow.querySelectorAll( '.' + messageClass ).forEach( ( el ) => { + el.classList.add( 'pll-message-shown' ); + } ); + } + fieldRow.classList.add( 'notice-' + type, 'notice-alt' ); + }, + + ajaxButton: { + /** + * Attaches an event to `.pll-ajax-button` buttons to trigger AJAX requests. + */ + attachEvent: () => { + document.querySelectorAll( '.pll-ajax-button' ).forEach( ( el ) => { + el.addEventListener( 'click', ( event ) => { + const button = event.target; + const action = button.getAttribute( 'data-action' ); + const nonce = button.getAttribute( 'data-nonce' ); + const fieldRow = button.closest( 'tr' ); + const errorElms = fieldRow.querySelectorAll( '.pll-error-message-text' ); + + if ( ! action || ! nonce || ! fieldRow || ! errorElms.length || button.getAttribute( 'disabled' ) ) { + return; + } + + const urlParams = { 'action': action, '_pll_nonce': nonce, 'pll_ajax_settings': 1 }; + fieldRow.querySelectorAll( '[data-name]' ).forEach( ( el ) => { + urlParams[ el.getAttribute( 'data-name' ) ] = el.value; + } ); + const url = wp.url.addQueryArgs( ajaxurl, urlParams ); + + button.setAttribute( 'disabled', 'disabled' ); + pllMachineTranslation.resetFieldRow( fieldRow ); + + fetch( url ).then( ( response ) => { + return response.json(); + } ).then( ( json ) => { + button.removeAttribute( 'disabled' ); + + if ( json.success ) { + fieldRow.classList.add( 'notice-success', 'notice-alt' ); + } else { + errorElms[0].textContent = json.data && json.data.message ? json.data.message : ''; + pllMachineTranslation.displayErrorMessage( fieldRow, json.data ? json.data.message_class : '' ); + } + } ).catch( () => { + button.removeAttribute( 'disabled' ); + fieldRow.classList.add( 'notice-error', 'notice-alt' ); + } ); + } ); + } ); + } + }, + + saveSettings: { + /** + * Highlights a settings row in case of error when the settings are saved. + * Hooked to `'pll_settings_saved'`. + * + * @param {Object} response The response from the AJAX call. + * @param {HTMLElement} tr The HTML element containing the module's fields. + */ + highlightRow: ( response, tr ) => { + switch ( response.what ) { + case 'success': + tr.querySelectorAll( '.notice-alt, .pll-message-shown' ).forEach( ( el ) => { + el.classList.remove( 'notice-success', 'notice-warning', 'notice-error', 'notice-alt', 'pll-message-shown' ); + } ); + break; + + case 'error': + const noticeData = pllMachineTranslation.saveSettings.getNoticeData( response.data ); + + if ( ! noticeData.fieldId ) { + break; + } + + const field = document.getElementById( noticeData.fieldId ); + + if ( ! field ) { + break; + } + + const fieldRow = field.closest( 'tr' ); + + if ( ! fieldRow ) { + break; + } + + pllMachineTranslation.resetFieldRow( fieldRow ); + pllMachineTranslation.displayErrorMessage( fieldRow, noticeData.messageClass, noticeData.type ); + break; + } + }, + + /** + * Returns the data contained in the HTML classes of the given element. + * + * @param {String} htmlString HTML string. + * @returns {Object} + */ + getNoticeData: ( htmlString ) => { + const div = document.createElement( 'div' ); + div.innerHTML = htmlString.trim(); // phpcs:ignore WordPressVIPMinimum.JS.InnerHTML.Found + return { + type: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'notice-(success|warning|error)', 'error' ), + fieldId: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'pll-field-id-([^\\s]+)', '' ), // See `Settings\Deepl::is_api_key_valid()` and `Module_Settings::update()`. + messageClass: pllMachineTranslation.saveSettings.find( div.firstChild.className, 'pll-message-class-([^\\s]+)', '' ) // See `Settings\Deepl::is_api_key_valid()` and `Module_Settings::update()`. + }; + }, + + /** + * Returns the part of the given string matching the given pattern. + * + * @param {String} string A string. + * @param {String} pattern A regex pattern. + * @param {String} def String to return if nothing is found. + * @returns {String} + */ + find: ( string, pattern, def ) => { + const matches = ( ' ' + string + ' ' ).match( new RegExp( '\\s' + pattern + '\\s' ) ); + return matches && matches[1] ? matches[1] : def; + } + }, + + dataUsage: { + fetchData: () => { + document.querySelectorAll( '.pll-progress-bar-wrapper' ).forEach( ( el ) => { + const action = el.getAttribute( 'data-action' ); + const nonce = el.getAttribute( 'data-nonce' ); + const spinner = el.querySelectorAll( '.spinner' ).item( 0 ); + const progress = el.querySelectorAll( 'div' ).item( 0 ); + + if ( ! action || ! nonce || ! spinner || ! progress || ! el.parentElement ) { + return; + } + + const description = el.parentElement.querySelectorAll( '.description' ).item( 0 ); + + if ( ! description ) { + return; + } + + const urlParams = { 'action': action, '_pll_nonce': nonce, 'pll_ajax_settings': 1 }; + const url = wp.url.addQueryArgs( ajaxurl, urlParams ); + + fetch( url ).then( ( response ) => { + return response.json(); + } ).then( ( json ) => { + if ( ! json.success || ! json.data.percent ) { + /* + * 2 cases: + * - Error while retrieving the data: display the error message. + * - The character limit is 0: display only the character count. + */ + el.remove(); + description.textContent = json.data.message; + return; + } + + // Display a graphic. + el.replaceChild( document.createTextNode( json.data.percent_formatted ), spinner ); + progress.textContent = json.data.percent_formatted; + progress.style.width = json.data.percent; + description.textContent = json.data.message; + } ).catch( () => { + el.closest( 'tr' ).remove(); + } ); + } ); + } + } +}; + +pllMachineTranslation.init(); + diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/load.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/load.php new file mode 100644 index 000000000..fd3597747 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/load.php @@ -0,0 +1,44 @@ +model->has_languages() ) { + // Ensure dependencies are loaded. + require_once POLYLANG_PRO_DIR . '/modules/sync/load.php'; + require_once POLYLANG_PRO_DIR . '/modules/sync-post/load.php'; + require_once POLYLANG_DIR . '/modules/sync/load.php'; + + $machine_translation_factory = new Machine_Translation\Factory( $polylang->model ); + + if ( $machine_translation_factory->is_enabled() ) { + $active_service = $machine_translation_factory->get_active_service(); + + if ( $active_service && $polylang instanceof PLL_Admin ) { + new PLL_Admin_Loader( $polylang, 'machine_translation', array( $active_service ) ); + $polylang->machine_translation_action = new Action( $polylang, $active_service ); + } elseif ( $active_service && $polylang instanceof PLL_REST_Request ) { + $polylang->machine_translation = new Machine_Translation\Button_REST( $polylang, $active_service ); + } + } + + if ( $polylang instanceof PLL_Settings ) { + add_filter( + 'pll_settings_modules', + function ( $modules ) { + $k = array_search( PLL_Settings_Preview_Machine_Translation::class, $modules ); + if ( $k ) { + unset( $modules[ $k ] ); + $modules['machine_translation'] = Machine_Translation\Module_Settings::class; + } + return $modules; + }, + 100 + ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/Machine_Translation/uninstall.php b/wp-content/plugins/polylang-pro/modules/Machine_Translation/uninstall.php new file mode 100644 index 000000000..fc2abea8b --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/Machine_Translation/uninstall.php @@ -0,0 +1,8 @@ +options = &$polylang->options; + $this->model = &$polylang->model; + $this->curlang = &$polylang->curlang; + + // Admin. + if ( $polylang instanceof PLL_Settings && ( empty( $_GET['page'] ) || 'mlang' === $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + add_filter( 'pll_languages_row_classes', array( $this, 'row_classes' ), 10, 2 ); + add_filter( 'pll_default_lang_row_action', array( $this, 'remove_default_lang_action' ), 10, 2 ); + add_filter( 'pll_languages_row_actions', array( $this, 'row_actions' ), 10, 2 ); + add_action( 'mlang_action_enable', array( $this, 'enable' ) ); + add_action( 'mlang_action_disable', array( $this, 'disable' ) ); + add_action( 'admin_print_styles', array( $this, 'print_css' ) ); + } + + if ( ! current_user_can( 'edit_posts' ) ) { + add_action( 'pll_language_defined', array( $this, 'init' ) ); + add_action( 'wp_sitemaps_init', array( $this, 'init' ) ); + add_action( 'rest_api_init', array( $this, 'init' ) ); + add_filter( 'pll_languages_for_browser_preferences', array( $this, 'remove_inactive_languages' ) ); + } + } + + /** + * Adds class inactive / active class + * + * @since 1.9 + * + * @param string[] $classes CSS classes applied to a row in the languages list table. + * @param PLL_Language $language The language. + * @return string[] Modified list of classes. + */ + public function row_classes( $classes, $language ) { + return empty( $language->active ) ? array( 'inactive' ) : array(); + } + + /** + * Remove the default lang action for disabled languages + * + * @since 1.9 + * + * @param string $action HTML markup of the action to define the default language. + * @param PLL_Language $language The Language. + * @return string Modified row action. + */ + public function remove_default_lang_action( $action, $language ) { + if ( empty( $language->active ) ) { + return ''; + } + + return $action; + } + + /** + * Adds disable/enable links to row actions in the languages list table + * + * @since 1.9 + * + * @param string[] $actions The list of the HTML markup of row actions. + * @param PLL_Language $language The language. + * @return string[] Modified list of row actions. + */ + public function row_actions( $actions, $language ) { + if ( $language->is_default ) { + return $actions; + } + + $active_action = empty( $language->active ) ? + array( + 'enable' => sprintf( + '
    %s', + esc_attr__( 'Activate this language', 'polylang-pro' ), + wp_nonce_url( '?page=mlang&pll_action=enable&noheader=true&lang=' . $language->term_id, 'enable-lang' ), + esc_html__( 'Activate', 'polylang-pro' ) + ), + ) : + array( + 'disable' => sprintf( + '%s', + esc_attr__( 'Deactivate this language', 'polylang-pro' ), + wp_nonce_url( '?page=mlang&pll_action=disable&noheader=true&lang=' . $language->term_id, 'disable-lang' ), + esc_html__( 'Deactivate', 'polylang-pro' ) + ), + ); + + return array_merge( $active_action, $actions ); + } + + /** + * Enables or disables a language + * + * @since 1.9 + * + * @param int $lang_id The language term id. + * @param bool $enable True to enable, false to disable. + * @return void + */ + public function _enable( $lang_id, $enable ) { + $lang_id = (int) $lang_id; + $language = get_term( $lang_id, 'language' ); + + if ( ! $language instanceof WP_Term ) { + return; + } + + $description = maybe_unserialize( $language->description ); + + $description['active'] = $enable; + + wp_update_term( $lang_id, 'language', array( 'description' => maybe_serialize( $description ) ) ); + $this->model->clean_languages_cache(); + } + + /** + * Enables a language + * + * @since 1.9 + * + * @return void + */ + public function enable() { + check_admin_referer( 'enable-lang' ); + if ( isset( $_GET['lang'] ) ) { + $this->_enable( (int) $_GET['lang'], true ); + } + PLL_Settings::redirect(); + } + + /** + * Disables a language + * + * @since 1.9 + * + * @return void + */ + public function disable() { + check_admin_referer( 'disable-lang' ); + if ( isset( $_GET['lang'] ) ) { + $this->_enable( (int) $_GET['lang'], false ); + } + PLL_Settings::redirect(); + } + + /** + * Sets error 404 if the requested language is not active. + * + * @since 1.9 + * + * @return void + */ + public function maybe_set_404() { + if ( isset( $this->curlang, $this->curlang->active ) && empty( $this->curlang->active ) ) { + $GLOBALS['wp_query']->set_404(); + add_filter( 'wp_sitemaps_enabled', '__return_false' ); + + /** + * Fires when a visitor attempts to access to an inactive language. + * + * @since 2.7 + * + * @param string $slug Requested language code. + * @param PLL_Language $curlang Requested language object. + */ + do_action( 'pll_inactive_language_requested', $this->curlang->slug, $this->curlang ); + } + } + + /** + * Styles the border + * + * @since 1.9 + * + * @return void + */ + public function print_css() { + ?> + + remove_inactive_languages( $this->model->get_languages_list() ); + $this->model->cache->set( 'languages', $languages ); // FIXME access to $this->model->cache which I would prefer to keep protected. + add_action( 'wp', array( $this, 'maybe_set_404' ) ); + } + + /** + * Removes inactive languages from the list of languages. + * + * @since 1.9.3 + * + * @param PLL_Language[] $languages Array of PLL_Language objects. + * @return PLL_Language[] + */ + public function remove_inactive_languages( $languages ) { + foreach ( $languages as $k => $lang ) { + if ( empty( $lang->active ) ) { + unset( $languages[ $k ] ); + } + } + return array_values( $languages ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/active-languages/load.php b/wp-content/plugins/polylang-pro/modules/active-languages/load.php new file mode 100644 index 000000000..f05e528ef --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/active-languages/load.php @@ -0,0 +1,12 @@ +model->has_languages() ) { + $polylang->active_languages = new PLL_Active_Languages( $polylang ); +} diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/abstract-language-switcher-block.php b/wp-content/plugins/polylang-pro/modules/block-editor/abstract-language-switcher-block.php new file mode 100644 index 000000000..47e0426d4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/abstract-language-switcher-block.php @@ -0,0 +1,205 @@ +model = &$polylang->model; + $this->links = &$polylang->links; + } + + /** + * Adds the required hooks. + * + * @since 3.2 + * + * @return self + */ + public function init() { + // Use rest_pre_dispatch_filter to get additionnal parameters for language switcher block. + add_filter( 'rest_pre_dispatch', array( $this, 'get_rest_query_params' ), 10, 3 ); + + // Register language switcher block. + add_action( 'init', array( $this, 'register' ) ); + + return $this; + } + + /** + * Returns the block name with the Polylang's namespace. + * + * @since 3.2 + * + * @return string The block name. + */ + abstract protected function get_block_name(); + + /** + * Renders the Polylang's block on server. + * + * @since 3.2 + * @since 3.3 Accepts two new parameters, $content and $block. + * + * @param array $attributes The block attributes. + * @param string $content The saved content. + * @param WP_Block $block The parsed block. + * @return string The HTML string output to serve. + */ + abstract public function render( $attributes, $content, $block ); + + /** + * Returns the supported pieces of inherited context for the block, by default none are supported.. + * + * @since 3.3 + * + * @return array An array with context subject, default to empty. + */ + protected function get_context() { + return array(); + } + + /** + * Registers the Polylang's block. + * + * @since 2.8 + * @since 3.2 Renamed and now handle any type of block registration based on a dynamic name. + * + * @return void + */ + public function register() { + if ( WP_Block_Type_Registry::get_instance()->is_registered( $this->get_block_name() ) ) { + // Don't register a block more than once or WordPress send an error. See https://github.com/WordPress/wordpress-develop/blob/5.9/src/wp-includes/class-wp-block-type-registry.php#L82-L90 + return; + } + + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + $script_filename = 'js/build/blocks' . $suffix . '.js'; + $script_handle = 'pll_blocks'; + wp_register_script( + $script_handle, + plugins_url( $script_filename, POLYLANG_ROOT_FILE ), + array( + 'wp-block-editor', + 'wp-blocks', + 'wp-components', + 'wp-element', + 'wp-i18n', + 'wp-server-side-render', + 'lodash', + ), + POLYLANG_VERSION, + true + ); + + wp_localize_script( $script_handle, 'pll_block_editor_blocks_settings', PLL_Switcher::get_switcher_options( 'block', 'string' ) ); + + $attributes = array( + 'className' => array( + 'type' => 'string', + 'default' => '', + ), + ); + foreach ( PLL_Switcher::get_switcher_options( 'block', 'default' ) as $option => $default ) { + $attributes[ $option ] = array( + 'type' => 'boolean', + 'default' => $default, + ); + } + + register_block_type( + $this->get_block_name(), + array( + 'editor_script' => $script_handle, + 'attributes' => $attributes, + 'render_callback' => array( $this, 'render' ), + 'uses_context' => $this->get_context(), + ) + ); + + // Translated strings used in JS code + wp_set_script_translations( $script_handle, 'polylang-pro' ); + } + + /** + * Returns the REST parameters for language switcher block. + * Used to store the request's language and context locally. + * Previously was in the `PLL_Block_Editor_Switcher_Block` class. + * + * @see WP_REST_Server::dispatch() + * + * @since 2.8 + * + * @param mixed $result Response to replace the requested version with. Can be anything + * a normal endpoint can return, or null to not hijack the request. + * @param WP_REST_Server $server Server instance. + * @param WP_REST_Request $request Request used to generate the response. + * @return mixed + */ + public function get_rest_query_params( $result, $server, $request ) { + if ( pll_is_edit_rest_request( $request ) ) { + $this->is_edit_context = true; + $this->admin_current_lang = $request->get_param( 'lang' ); + } + return $result; + } + + /** + * Adds the attributes to render the block correctly. + * Also specifies not to echo the switcher in any case. + * + * @since 3.2 + * + * @param array $attributes The attributes of the currently rendered block. + * @return array The modified attributes. + */ + protected function set_attributes_for_block( $attributes ) { + $attributes['echo'] = 0; + if ( $this->is_edit_context ) { + $attributes['admin_render'] = 1; + $attributes['admin_current_lang'] = $this->admin_current_lang; + $attributes['hide_if_empty'] = 0; + $attributes['hide_if_no_translation'] = 0; // Force not to hide the language for the block preview even if the option is checked. + } + return $attributes; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/block-editor-plugin.php b/wp-content/plugins/polylang-pro/modules/block-editor/block-editor-plugin.php new file mode 100644 index 000000000..e512fd594 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/block-editor-plugin.php @@ -0,0 +1,439 @@ +model = &$polylang->model; + $this->posts = &$polylang->posts; + $this->options = &$polylang->options; + $this->curlang = &$polylang->curlang; + $this->block_editor = &$polylang->block_editor; // Used to get a shared instance of `PLL_Filter_REST_Route` and call a single instance through the plugin. + + add_filter( 'block_editor_rest_api_preload_paths', array( $this, 'filter_preload_paths' ), 50, 2 ); + add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'filter_legacy_widgets' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); + } + + /** + * Filters preload paths based on the context (block editor for posts, site editor or widget editor for instance). + * + * @since 3.4 + * + * @param (string|string[])[] $preload_paths Preload paths. + * @param WP_Block_Editor_Context $context Editor context. + * @return array Filtered preload paths. + */ + public function filter_preload_paths( $preload_paths, $context ) { + if ( ! $context instanceof WP_Block_Editor_Context || empty( $this->block_editor ) ) { + return $preload_paths; + } + + if ( $context->post instanceof WP_Post && ! $this->model->is_translated_post_type( $context->post->post_type ) ) { + return $preload_paths; + } + + $preload_paths = (array) $preload_paths; + + // Do nothing if in post editor since `PLL_Admin_Block_Editor` has already filtered. + if ( ! $this->is_edit_post_context( $context ) ) { + $lang = ! empty( $this->curlang ) ? $this->curlang->slug : null; + + if ( empty( $lang ) || $this->is_edit_widgets_context( $context, $preload_paths ) ) { + // WP 6.0+: widget screen filtered by default language. See `pllDefaultLanguage` JS var added. + $lang = $this->model->options['default_lang']; + } + + $preload_paths = $this->block_editor->filter_rest_routes->add_query_parameters( + $preload_paths, + array( + 'lang' => $lang, + ) + ); + + if ( $this->is_edit_site_context( $context, $preload_paths ) ) { + // User data required for the site editor (WP already adds it to the post block editor). + $preload_paths[] = '/wp/v2/users/me'; + } + } + + $preload_paths[] = '/pll/v1/languages'; + + return $preload_paths; + } + + /** + * Enqueue scripts for the block editor plugin. + * + * @since 2.6 + * + * @return void + */ + public function admin_enqueue_scripts() { + $screen = get_current_screen(); + if ( empty( $screen ) ) { + return; + } + + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + $this->enqueue_style_for_specific_screen( $screen, $suffix ); + + // Enqueue scripts for widget screen + if ( $this->is_widget_screen( $screen ) ) { + $script_filename = '/js/build/widget-editor-plugin' . $suffix . '.js'; + $script_handle = 'pll_widget-editor-plugin'; + wp_enqueue_script( + $script_handle, + plugins_url( $script_filename, POLYLANG_BASENAME ), + array( + 'wp-api-fetch', + 'wp-data', + 'lodash', + ), + POLYLANG_VERSION, + true + ); + + $default_lang_script = 'const pllDefaultLanguage = "' . $this->options['default_lang'] . '";'; + wp_add_inline_script( + $script_handle, + $default_lang_script, + 'before' + ); + + if ( ! empty( $this->block_editor ) ) { + $this->block_editor->filter_rest_routes->add_inline_script( $script_handle ); + } + + // Translated strings used in JS code + wp_set_script_translations( $script_handle, 'polylang-pro' ); + + return; + } + + // Enqueue scripts for post screen and in block editor context + if ( $this->is_translatable_post_screen( $screen ) && $this->is_block_editor( $screen ) ) { + $script_filename = '/js/build/block-editor-plugin' . $suffix . '.js'; + $script_handle = 'pll_block-editor-plugin'; + wp_register_script( + $script_handle, + plugins_url( $script_filename, POLYLANG_ROOT_FILE ), + array( + 'wp-api-fetch', + 'wp-data', + 'wp-sanitize', + 'lodash', + ), + POLYLANG_VERSION, + true + ); + + // Set default language according to the context if no language is defined yet. + $editor_lang = $this->get_editor_language(); + if ( ! empty( $editor_lang ) ) { + $editor_lang = $editor_lang->to_array(); + } + $pll_settings = 'let pll_block_editor_plugin_settings = ' . wp_json_encode( + /** + * Filters settings required by the UI. + * + * @since 3.6 + * + * @param array $settings. + */ + (array) apply_filters( + 'pll_block_editor_plugin_settings', + array( + 'lang' => $editor_lang, + ) + ) + ); + + wp_add_inline_script( $script_handle, $pll_settings, 'before' ); + + if ( ! empty( $this->block_editor ) ) { + $this->block_editor->filter_rest_routes->add_inline_script( $script_handle ); + } + + wp_enqueue_script( $script_handle ); + + $script_filename = '/js/build/sidebar' . $suffix . '.js'; + wp_enqueue_script( + 'pll_sidebar', + plugins_url( $script_filename, POLYLANG_ROOT_FILE ), + array( + 'wp-api-fetch', + 'wp-data', + 'wp-i18n', + 'wp-sanitize', + 'lodash', + ), + POLYLANG_VERSION, + true + ); + + // Translated strings used in JS code + wp_set_script_translations( 'pll_sidebar', 'polylang-pro' ); + } + } + + /** + * Enqueue style for a specific screen. + * + * @since 3.1 + * + * @param WP_Screen $screen The current screen. + * @param string $suffix The file suffix. + * @return void + */ + private function enqueue_style_for_specific_screen( $screen, $suffix ) { + // Enqueue specific styles for block and widget editor UI + if ( $this->is_widget_screen( $screen ) || $this->is_widget_customizer_screen( $screen ) || + ( $this->is_translatable_post_screen( $screen ) && $this->is_block_editor( $screen ) ) ) { + wp_enqueue_style( + 'polylang-block-widget-editor-css', + plugins_url( '/css/build/style' . $suffix . '.css', POLYLANG_ROOT_FILE ), + array( 'wp-components' ), + POLYLANG_VERSION + ); + } + } + + /** + * Checks if we're in the context of post or site editor screen. + * + * @since 3.1 + * + * @param WP_Screen $screen The current screen. + * @return bool True if post screen, false otherwise. + */ + private function is_translatable_post_screen( $screen ) { + return ( 'post' === $screen->base && $this->model->is_translated_post_type( $screen->post_type ) ) || + ( 'site-editor' === $screen->base && $this->model->is_translated_post_type( 'wp_template_part' ) ) || + ( 'appearance_page_gutenberg-edit-site' === $screen->base && $this->model->is_translated_post_type( 'wp_template_part' ) ); + } + + /** + * Check if we're in the context of a widget screen. + * + * @since 3.1 + * + * @param WP_Screen $screen The current screen. + * @return bool True if widget screen, false otherwise. + */ + private function is_widget_screen( $screen ) { + return 'widgets' === $screen->base && function_exists( 'wp_use_widgets_block_editor' ) && wp_use_widgets_block_editor(); + } + + /** + * Check if we're in the context of a block editor. + * + * @since 3.1 + * + * @param WP_Screen $screen The current screen. + * @return bool True if block editor, false otherwise. + */ + private function is_block_editor( $screen ) { + return method_exists( $screen, 'is_block_editor' ) && $screen->is_block_editor(); + } + + /** + * Check if we're in the context of a widget customizer screen. + * + * @since 3.2 + * + * @param WP_Screen $screen The current screen. + * @return bool True if widget customizer screen, false otherwise. + */ + private function is_widget_customizer_screen( $screen ) { + return 'customize' === $screen->base; + } + + /** + * Returns the language to use in the editor. + * + * @since 3.2 + * + * @return PLL_Language|null + */ + private function get_editor_language() { + global $post; + + if ( ! empty( $this->curlang ) && PLL_FSE_Tools::is_site_editor() ) { + return $this->curlang; + } + + if ( ! empty( $post ) && $this->model->is_translated_post_type( $post->post_type ) ) { + $this->posts->set_default_language( $post->ID ); + $post_lang = $this->model->post->get_language( $post->ID ); + return ! empty( $post_lang ) ? $post_lang : null; + } + + return null; + } + + /** + * Method that allow legacy widgets in widget block editor previously removed by WP and hide legacy Polylang widget. + * + * @since 3.2 + * + * @param array $widget_ids An array of hidden widget ids. + * @return array + */ + public function filter_legacy_widgets( $widget_ids ) { + $widgets_to_show = array( 'custom_html' ); + $widget_ids = array_diff( $widget_ids, $widgets_to_show ); + + $widgets_to_hide = array( 'polylang' ); + $widget_ids = array_merge( $widget_ids, $widgets_to_hide ); + + return $widget_ids; + } + + /** + * Tells if we're in the post editor context. + * + * @since 3.5 + * + * @param WP_Block_Editor_Context $context Editor context. + * @return bool + */ + private function is_edit_post_context( WP_Block_Editor_Context $context ): bool { + if ( property_exists( $context, 'name' ) ) { + // WP 6.0+. + return 'core/edit-post' === $context->name; + } + + /* + * Backward compatibility with WP < 6.0 where `WP_Block_Editor_Context::$name` doesn't exist yet: + * A post is passed only in the 'core/edit-post' context (still true, so far). + */ + return $context->post instanceof WP_Post; + } + + /** + * Tells if we're in the widgets editor context. + * + * @since 3.5 + * + * @param WP_Block_Editor_Context $context Editor context. + * @param (string|string[])[] $preload_paths Preload paths. + * @return bool + */ + private function is_edit_widgets_context( WP_Block_Editor_Context $context, array $preload_paths ): bool { + if ( property_exists( $context, 'name' ) ) { + // WP 6.0+. + return 'core/edit-widgets' === $context->name; + } + + /* + * Backward compatibility with WP < 6.0 where `WP_Block_Editor_Context::$name` doesn't exist yet: + * Sniff preload paths. + * Search for: + * - '/wp/v2/sidebars?context=edit&per_page=-1', + * - '/wp/v2/widgets?context=edit&per_page=-1&_embed=about'. + * + * @see wp-admin/widgets-form-blocks.php + */ + return $this->match_paths( array( 'sidebars', 'widgets' ), $preload_paths ); + } + + /** + * Tells if we're in the site editor context. + * + * @since 3.5 + * + * @param WP_Block_Editor_Context $context Editor context. + * @param (string|string[])[] $preload_paths Preload paths. + * @return bool + */ + private function is_edit_site_context( WP_Block_Editor_Context $context, array $preload_paths ): bool { + if ( property_exists( $context, 'name' ) ) { + // WP 6.0+. + return 'core/edit-site' === $context->name; + } + + /* + * Backward compatibility with WP < 6.0 where `WP_Block_Editor_Context::$name` doesn't exist yet: + * Sniff preload paths. + * Search for: + * - '/wp/v2/types/wp_template?context=edit', + * - '/wp/v2/types/wp_template-part?context=edit', + * - '/wp/v2/templates?context=edit&per_page=-1', + * - '/wp/v2/template-parts?context=edit&per_page=-1', + * - '/wp/v2/themes?context=edit&status=active', + * - '/wp/v2/global-styles/{$active_global_styles_id}?context=edit'. + * + * @see wp-admin/site-editor.php + */ + return $this->match_paths( + array( + 'types/wp_template', + 'types/wp_template-part', + 'templates', + 'template-parts', + 'themes', + 'global-styles/\d+', + ), + $preload_paths + ); + } + + /** + * Tells if a given list of URIs matches a given list of preload paths. + * Works only for paths in the form of `/wp/v2/{URI}?context=edit`. + * This is used for backward compatibility with WP < 6.0. + * + * @since 3.5 + * + * @param string[] $uris_to_find List of URIs to find in `$paths_haystack`. + * @param (string|string[])[] $paths_haystack List of preload paths to search in. + * @return bool + */ + private function match_paths( array $uris_to_find, array $paths_haystack ): bool { + $pattern = sprintf( '@^/wp/v2/(?:%s)\?(?:.+&)?context=edit(?:&|$)@m', implode( '|', $uris_to_find ) ); + $haystack = implode( "\n", array_filter( $paths_haystack, 'is_string' ) ); + + // We expect a precise number of matches but a plugin could add more. + return preg_match_all( $pattern, $haystack, $matches ) >= count( $uris_to_find ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/frontend-filters-widgets-blocks.php b/wp-content/plugins/polylang-pro/modules/block-editor/frontend-filters-widgets-blocks.php new file mode 100644 index 000000000..2286017a7 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/frontend-filters-widgets-blocks.php @@ -0,0 +1,44 @@ +parse( $widget_data['settings'][ $widget_data['number'] ]['content'] ); + if ( is_array( $parser->output ) ) { + foreach ( $parser->output as $output ) { + if ( isset( $output['attrs'] ) ) { + if ( array_key_exists( 'pll_lang', $output['attrs'] ) ) { + $lang_to_be_displayed = $output['attrs']['pll_lang']; + + if ( $this->curlang->slug !== $lang_to_be_displayed ) { + unset( $sidebars_widgets[ $sidebar ][ $key ] ); + } + } + } + } + } + } + return $sidebars_widgets; + } +} diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/language-switcher-block.php b/wp-content/plugins/polylang-pro/modules/block-editor/language-switcher-block.php new file mode 100644 index 000000000..ef8bbc513 --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/language-switcher-block.php @@ -0,0 +1,66 @@ +set_attributes_for_block( $attributes ); + + $attributes['raw'] = false; + $switcher = new PLL_Switcher(); + $switcher_output = $switcher->the_languages( $this->links, $attributes ); + + if ( empty( $switcher_output ) ) { + return ''; + } + + $wrap_tag = '
      %2$s
    '; + + if ( $attributes['dropdown'] ) { + $switcher_output = '' . $switcher_output; + + $wrap_tag = '
    %2$s
    '; + } + + $wrap_attributes = get_block_wrapper_attributes(); + + return sprintf( $wrap_tag, $wrap_attributes, $switcher_output ); + } +} diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/load.php b/wp-content/plugins/polylang-pro/modules/block-editor/load.php new file mode 100644 index 000000000..d4ae9aa1a --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/load.php @@ -0,0 +1,27 @@ +model->has_languages() && pll_use_block_editor_plugin() ) { + if ( $polylang instanceof PLL_Admin ) { + $polylang->block_editor_plugin = new PLL_Block_Editor_Plugin( $polylang ); + } + + if ( $polylang instanceof PLL_Frontend ) { + $polylang->filters_widgets_blocks = new PLL_Frontend_Filters_Widgets_Blocks( $polylang ); + } + + $polylang->widget_editor = new PLL_Widget_Editor_Language_Attribute(); + $polylang->switcher_block = ( new PLL_Language_Switcher_Block( $polylang ) )->init(); + $polylang->navigation_block = ( new PLL_Navigation_Language_Switcher_Block( $polylang ) )->init(); + } + } +); diff --git a/wp-content/plugins/polylang-pro/modules/block-editor/navigation-language-switcher-block.php b/wp-content/plugins/polylang-pro/modules/block-editor/navigation-language-switcher-block.php new file mode 100644 index 000000000..c9e30b61b --- /dev/null +++ b/wp-content/plugins/polylang-pro/modules/block-editor/navigation-language-switcher-block.php @@ -0,0 +1,300 @@ +set_attributes_for_block( $attributes ); + $switcher = new PLL_Switcher(); + $switcher_elements = (array) $switcher->the_languages( $this->links, array_merge( $attributes, array( 'raw' => true ) ) ); + $output = ''; + + if ( $attributes['dropdown'] ) { + $inner_nav_link_blocks = array(); + $top_level_lang = reset( $switcher_elements ); + foreach ( $switcher_elements as $switcher_element ) { + $nav_link_block_args = array( + 'blockName' => 'core/navigation-link', + 'attrs' => $this->get_core_block_attributes( $attributes, $switcher_element ), + ); + + $inner_nav_link_blocks[] = new WP_Block( $nav_link_block_args, $block->context ); + + if ( $switcher_element['current_lang'] && ! $attributes['hide_current'] ) { + $top_level_lang = $switcher_element; + } + } + + $attributes = $this->get_core_block_attributes( $attributes, $top_level_lang ); + $attributes['className'] .= ' ' . wp_apply_generated_classname_support( $block->block_type )['class']; + $submenu_block_args = array( + 'blockName' => 'core/navigation-submenu', + 'attrs' => $attributes, + 'innerBlocks' => $inner_nav_link_blocks, + ); + + $submenu_block = new WP_Block( $submenu_block_args, $block->context ); + $output = $submenu_block->render(); + } else { + foreach ( $switcher_elements as $switcher_element ) { + $link_attributes = $this->get_core_block_attributes( $attributes, $switcher_element ); + $link_attributes['className'] .= ' ' . wp_apply_generated_classname_support( $block->block_type )['class']; + $nav_link_block_args = array( + 'blockName' => 'core/navigation-link', + 'attrs' => $link_attributes, + ); + + $link_block = new WP_Block( $nav_link_block_args, $block->context ); + $output .= $link_block->render(); + } + } + + if ( version_compare( $GLOBALS['wp_version'], '6.5-alpha', '<' ) ) { + /* + * Backward compatibility with WordPress < 6.5. + * Since WordPress 6.5, our block is rendered automatically inside the auto-generated `
    ', + sprintf( + /* translators: 1: Plugin name 2: Current PHP version 3: Required PHP version */ + esc_html__( '%1$s has deactivated itself because you are using an old version of PHP. You are using using PHP %2$s. %1$s requires PHP %3$s.', 'polylang' ), + esc_html( POLYLANG ), + PHP_VERSION, + esc_html( PLL_MIN_PHP_VERSION ) + ) + ); + } + + /** + * Displays a notice if WP min version is not met. + * + * @since 2.6.7 + * + * @return void + */ + public function wp_version_notice() { + global $wp_version; + + load_plugin_textdomain( 'polylang' ); // Plugin i18n. + + printf( + '

    %s

    ', + sprintf( + /* translators: 1: Plugin name 2: Current WordPress version 3: Required WordPress version */ + esc_html__( '%1$s has deactivated itself because you are using an old version of WordPress. You are using using WordPress %2$s. %1$s requires at least WordPress %3$s.', 'polylang' ), + esc_html( POLYLANG ), + esc_html( $wp_version ), + esc_html( PLL_MIN_WP_VERSION ) + ) + ); + } + + /** + * Get default Polylang options. + * + * @since 1.8 + * + * @return array + */ + public static function get_default_options() { + return array( + 'browser' => 0, // Default language for the front page is not set by browser preference (was the opposite before 3.1). + 'rewrite' => 1, // Remove /language/ in permalinks (was the opposite before 0.7.2). + 'hide_default' => 1, // Remove URL language information for default language (was the opposite before 2.1.5). + 'force_lang' => 1, // Add URL language information (was 0 before 1.7). + 'redirect_lang' => 0, // Do not redirect the language page to the homepage. + 'media_support' => 0, // Do not support languages and translation for media by default (was the opposite before 3.1). + 'uninstall' => 0, // Do not remove data when uninstalling Polylang. + 'sync' => array(), // Synchronisation is disabled by default (was the opposite before 1.2). + 'post_types' => array(), + 'taxonomies' => array(), + 'domains' => array(), + 'version' => POLYLANG_VERSION, + 'first_activation' => time(), + ); + } + + /** + * Plugin activation + * + * @since 0.5 + * + * @return void + */ + protected function _activate() { + if ( $options = get_option( 'polylang' ) ) { + // Check if we will be able to upgrade + if ( version_compare( $options['version'], POLYLANG_VERSION, '<' ) ) { + $upgrade = new PLL_Upgrade( $options ); + $upgrade->can_activate(); + } + } + // Defines default values for options in case this is the first installation + else { + update_option( 'polylang', self::get_default_options() ); + } + + // Avoid 1 query on every pages if no wpml strings is registered + if ( ! get_option( 'polylang_wpml_strings' ) ) { + update_option( 'polylang_wpml_strings', array() ); + } + + // Don't use flush_rewrite_rules at network activation. See #32471 + // Thanks to RavanH for the trick. See https://polylang.wordpress.com/2015/06/10/polylang-1-7-6-and-multisite/ + // Rewrite rules are created at next page load :) + delete_option( 'rewrite_rules' ); + } + + /** + * Plugin deactivation + * + * @since 0.5 + * + * @return void + */ + protected function _deactivate() { + delete_option( 'rewrite_rules' ); // Don't use flush_rewrite_rules at network activation. See #32471 + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/plugin-updater.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/plugin-updater.php new file mode 100644 index 000000000..b0a330f04 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/plugin-updater.php @@ -0,0 +1,645 @@ +api_url = trailingslashit( $_api_url ); + $this->api_data = $_api_data; + $this->plugin_file = $_plugin_file; + $this->name = plugin_basename( $_plugin_file ); + $this->slug = basename( $_plugin_file, '.php' ); + $this->version = $_api_data['version']; + $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false; + $this->beta = ! empty( $this->api_data['beta'] ) ? true : false; + $this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url ); + + $edd_plugin_data[ $this->slug ] = $this->api_data; + + /** + * Fires after the $edd_plugin_data is setup. + * + * @since x.x.x + * + * @param array $edd_plugin_data Array of EDD SL plugin data. + */ + do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data ); + + // Set up hooks. + $this->init(); + + } + + /** + * Set up WordPress filters to hook into WP's update process. + * + * @uses add_filter() + * + * @return void + */ + public function init() { + + add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) ); + add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 ); + add_action( 'after_plugin_row', array( $this, 'show_update_notification' ), 10, 2 ); + add_action( 'admin_init', array( $this, 'show_changelog' ) ); + + } + + /** + * Check for Updates at the defined API endpoint and modify the update array. + * + * This function dives into the update API just when WordPress creates its update array, + * then adds a custom API call and injects the custom plugin data retrieved from the API. + * It is reassembled from parts of the native WordPress plugin update code. + * See wp-includes/update.php line 121 for the original wp_update_plugins() function. + * + * @uses api_request() + * + * @param array $_transient_data Update array build by WordPress. + * @return array Modified update array with custom plugin data. + */ + public function check_update( $_transient_data ) { + + global $pagenow; + + if ( ! is_object( $_transient_data ) ) { + $_transient_data = new stdClass(); + } + + if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) { + return $_transient_data; + } + + $current = $this->get_repo_api_data(); + if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) { + if ( version_compare( $this->version, $current->new_version, '<' ) ) { + $_transient_data->response[ $this->name ] = $current; + } else { + // Populating the no_update information is required to support auto-updates in WordPress 5.5. + $_transient_data->no_update[ $this->name ] = $current; + } + } + $_transient_data->last_checked = time(); + $_transient_data->checked[ $this->name ] = $this->version; + + return $_transient_data; + } + + /** + * Get repo API data from store. + * Save to cache. + * + * @return \stdClass + */ + public function get_repo_api_data() { + $version_info = $this->get_cached_version_info(); + + if ( false === $version_info ) { + $version_info = $this->api_request( + 'plugin_latest_version', + array( + 'slug' => $this->slug, + 'beta' => $this->beta, + ) + ); + if ( ! $version_info ) { + return false; + } + + // This is required for your plugin to support auto-updates in WordPress 5.5. + $version_info->plugin = $this->name; + $version_info->id = $this->name; + + $this->set_version_info_cache( $version_info ); + } + + return $version_info; + } + + /** + * Show the update notification on multisite subsites. + * + * @param string $file + * @param array $plugin + */ + public function show_update_notification( $file, $plugin ) { + + // Return early if in the network admin, or if this is not a multisite install. + if ( is_network_admin() || ! is_multisite() ) { + return; + } + + // Allow single site admins to see that an update is available. + if ( ! current_user_can( 'activate_plugins' ) ) { + return; + } + + if ( $this->name !== $file ) { + return; + } + + // Do not print any message if update does not exist. + $update_cache = get_site_transient( 'update_plugins' ); + + if ( ! isset( $update_cache->response[ $this->name ] ) ) { + if ( ! is_object( $update_cache ) ) { + $update_cache = new stdClass(); + } + $update_cache->response[ $this->name ] = $this->get_repo_api_data(); + } + + // Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin. + if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) { + return; + } + + printf( + '', + $this->slug, + $file, + in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive' + ); + + echo ''; + echo '

    '; + + $changelog_link = ''; + if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) { + $changelog_link = add_query_arg( + array( + 'edd_sl_action' => 'view_plugin_changelog', + 'plugin' => urlencode( $this->name ), + 'slug' => urlencode( $this->slug ), + 'TB_iframe' => 'true', + 'width' => 77, + 'height' => 911, + ), + self_admin_url( 'index.php' ) + ); + } + $update_link = add_query_arg( + array( + 'action' => 'upgrade-plugin', + 'plugin' => urlencode( $this->name ), + ), + self_admin_url( 'update.php' ) + ); + + printf( + /* translators: the plugin name. */ + esc_html__( 'There is a new version of %1$s available.', 'polylang' ), + esc_html( $plugin['Name'] ) + ); + + if ( ! current_user_can( 'update_plugins' ) ) { + echo ' '; + esc_html_e( 'Contact your network administrator to install the update.', 'polylang' ); + } elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) { + echo ' '; + printf( + /* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */ + __( '%1$sView version %2$s details%3$s.', 'polylang' ), + '', + esc_html( $update_cache->response[ $this->name ]->new_version ), + '' + ); + } elseif ( ! empty( $changelog_link ) ) { + echo ' '; + printf( + /* translators: 1. and 4. are opening anchor tags 2. the new plugin version 3. and 5. are closing anchor tags. */ + __( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'polylang' ), + '', + esc_html( $update_cache->response[ $this->name ]->new_version ), + '', + '', + '' + ); + } else { + printf( + ' %1$s%2$s%3$s', + '', + esc_html__( 'Update now.', 'polylang' ), + '' + ); + } + + do_action( "in_plugin_update_message-{$file}", $plugin, $plugin ); + + echo '

    '; + } + + /** + * Gets the plugins active in a multisite network. + * + * @return array + */ + private function get_active_plugins() { + $active_plugins = (array) get_option( 'active_plugins' ); + $active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' ); + + return array_merge( $active_plugins, array_keys( $active_network_plugins ) ); + } + + /** + * Updates information on the "View version x.x details" page with custom data. + * + * @uses api_request() + * + * @param mixed $_data + * @param string $_action + * @param object $_args + * @return object $_data + */ + public function plugins_api_filter( $_data, $_action = '', $_args = null ) { + + if ( 'plugin_information' !== $_action ) { + + return $_data; + + } + + if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) { + + return $_data; + + } + + $to_send = array( + 'slug' => $this->slug, + 'is_ssl' => is_ssl(), + 'fields' => array( + 'banners' => array(), + 'reviews' => false, + 'icons' => array(), + ), + ); + + // Get the transient where we store the api request for this plugin for 24 hours + $edd_api_request_transient = $this->get_cached_version_info(); + + //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now. + if ( empty( $edd_api_request_transient ) ) { + + $api_response = $this->api_request( 'plugin_information', $to_send ); + + // Expires in 3 hours + $this->set_version_info_cache( $api_response ); + + if ( false !== $api_response ) { + $_data = $api_response; + } + } else { + $_data = $edd_api_request_transient; + } + + // Convert sections into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) { + $_data->sections = $this->convert_object_to_array( $_data->sections ); + } + + // Convert banners into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) { + $_data->banners = $this->convert_object_to_array( $_data->banners ); + } + + // Convert icons into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) { + $_data->icons = $this->convert_object_to_array( $_data->icons ); + } + + // Convert contributors into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) { + $_data->contributors = $this->convert_object_to_array( $_data->contributors ); + } + + if ( ! isset( $_data->plugin ) ) { + $_data->plugin = $this->name; + } + + return $_data; + } + + /** + * Convert some objects to arrays when injecting data into the update API + * + * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON + * decoding, they are objects. This method allows us to pass in the object and return an associative array. + * + * @since 3.6.5 + * + * @param stdClass $data + * + * @return array + */ + private function convert_object_to_array( $data ) { + if ( ! is_array( $data ) && ! is_object( $data ) ) { + return array(); + } + $new_data = array(); + foreach ( $data as $key => $value ) { + $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value; + } + + return $new_data; + } + + /** + * Disable SSL verification in order to prevent download update failures + * + * @param array $args + * @param string $url + * @return object $array + */ + public function http_request_args( $args, $url ) { + + if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) { + $args['sslverify'] = $this->verify_ssl(); + } + return $args; + + } + + /** + * Calls the API and, if successful, returns the object delivered by the API. + * + * @uses get_bloginfo() + * @uses wp_remote_post() + * @uses is_wp_error() + * + * @param string $_action The requested action. + * @param array $_data Parameters for the API action. + * @return false|object|void + */ + private function api_request( $_action, $_data ) { + $data = array_merge( $this->api_data, $_data ); + + if ( $data['slug'] !== $this->slug ) { + return; + } + + // Don't allow a plugin to ping itself + if ( trailingslashit( home_url() ) === $this->api_url ) { + return false; + } + + if ( $this->request_recently_failed() ) { + return false; + } + + return $this->get_version_from_remote(); + } + + /** + * Determines if a request has recently failed. + * + * @since 1.9.1 + * + * @return bool + */ + private function request_recently_failed() { + $failed_request_details = get_option( $this->failed_request_cache_key ); + + // Request has never failed. + if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) { + return false; + } + + /* + * Request previously failed, but the timeout has expired. + * This means we're allowed to try again. + */ + if ( time() > $failed_request_details ) { + delete_option( $this->failed_request_cache_key ); + + return false; + } + + return true; + } + + /** + * Logs a failed HTTP request for this API URL. + * We set a timestamp for 1 hour from now. This prevents future API requests from being + * made to this domain for 1 hour. Once the timestamp is in the past, API requests + * will be allowed again. This way if the site is down for some reason we don't bombard + * it with failed API requests. + * + * @see EDD_SL_Plugin_Updater::request_recently_failed + * + * @since 1.9.1 + */ + private function log_failed_request() { + update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) ); + } + + /** + * If available, show the changelog for sites in a multisite install. + */ + public function show_changelog() { + + if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) { + return; + } + + if ( empty( $_REQUEST['plugin'] ) ) { + return; + } + + if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) { + return; + } + + if ( ! current_user_can( 'update_plugins' ) ) { + wp_die( esc_html__( 'You do not have permission to install plugin updates', 'polylang' ), esc_html__( 'Error', 'polylang' ), array( 'response' => 403 ) ); + } + + $version_info = $this->get_repo_api_data(); + if ( isset( $version_info->sections ) ) { + $sections = $this->convert_object_to_array( $version_info->sections ); + if ( ! empty( $sections['changelog'] ) ) { + echo '
    ' . wp_kses_post( $sections['changelog'] ) . '
    '; + } + } + + exit; + } + + /** + * Gets the current version information from the remote site. + * + * @return array|false + */ + private function get_version_from_remote() { + $api_params = array( + 'edd_action' => 'get_version', + 'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '', + 'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false, + 'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false, + 'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false, + 'slug' => $this->slug, + 'author' => $this->api_data['author'], + 'url' => home_url(), + 'beta' => $this->beta, + 'php_version' => phpversion(), + 'wp_version' => get_bloginfo( 'version' ), + ); + + /** + * Filters the parameters sent in the API request. + * + * @param array $api_params The array of data sent in the request. + * @param array $this->api_data The array of data set up in the class constructor. + * @param string $this->plugin_file The full path and filename of the file. + */ + $api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file ); + + $request = wp_remote_post( + $this->api_url, + array( + 'timeout' => 15, + 'sslverify' => $this->verify_ssl(), + 'body' => $api_params, + ) + ); + + if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) { + $this->log_failed_request(); + + return false; + } + + $request = json_decode( wp_remote_retrieve_body( $request ) ); + + if ( $request && isset( $request->sections ) ) { + $request->sections = maybe_unserialize( $request->sections ); + } else { + $request = false; + } + + if ( $request && isset( $request->banners ) ) { + $request->banners = maybe_unserialize( $request->banners ); + } + + if ( $request && isset( $request->icons ) ) { + $request->icons = maybe_unserialize( $request->icons ); + } + + if ( ! empty( $request->sections ) ) { + foreach ( $request->sections as $key => $section ) { + $request->$key = (array) $section; + } + } + + return $request; + } + + /** + * Get the version info from the cache, if it exists. + * + * @param string $cache_key + * @return object + */ + public function get_cached_version_info( $cache_key = '' ) { + + if ( empty( $cache_key ) ) { + $cache_key = $this->get_cache_key(); + } + + $cache = get_option( $cache_key ); + + // Cache is expired + if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) { + return false; + } + + // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point. + $cache['value'] = json_decode( $cache['value'] ); + if ( ! empty( $cache['value']->icons ) ) { + $cache['value']->icons = (array) $cache['value']->icons; + } + + return $cache['value']; + + } + + /** + * Adds the plugin version information to the database. + * + * @param string $value + * @param string $cache_key + */ + public function set_version_info_cache( $value = '', $cache_key = '' ) { + + if ( empty( $cache_key ) ) { + $cache_key = $this->get_cache_key(); + } + + $data = array( + 'timeout' => strtotime( '+3 hours', time() ), + 'value' => wp_json_encode( $value ), + ); + + update_option( $cache_key, $data, 'no' ); + + // Delete the duplicate option + delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) ); + } + + /** + * Returns if the SSL of the store should be verified. + * + * @since 1.6.13 + * @return bool + */ + private function verify_ssl() { + return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this ); + } + + /** + * Gets the unique key (option name) for a plugin. + * + * @since 1.9.0 + * @return string + */ + private function get_cache_key() { + $string = $this->slug . $this->api_data['license'] . $this->beta; + + return 'edd_sl_' . md5( serialize( $string ) ); + } + +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/t15s.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/t15s.php new file mode 100644 index 000000000..3354fc20b --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/t15s.php @@ -0,0 +1,237 @@ +slug = $slug; + $this->api_url = $api_url; + + add_action( 'init', array( __CLASS__, 'register_clean_translations_cache' ), 9999 ); + add_filter( 'translations_api', array( $this, 'translations_api' ), 10, 3 ); + add_filter( 'site_transient_update_plugins', array( $this, 'site_transient_update_plugins' ) ); + } + + /** + * Short-circuits translations API requests for private projects. + * + * @since 2.6 + * + * @param bool|array $result The result object. Default false. + * @param string $requested_type The type of translations being requested. + * @param object $args Translation API arguments. + * @return bool|array + */ + public function translations_api( $result, $requested_type, $args ) { + if ( 'plugins' === $requested_type && $this->slug === $args['slug'] ) { + return self::get_translations( $args['slug'], $this->api_url ); + } + + return $result; + } + + /** + * Filters the translations transients to include the private plugin or theme. + * + * @see wp_get_translation_updates() + * + * @since 2.6 + * + * @param bool|array $value The transient value. + * @return bool|array + */ + public function site_transient_update_plugins( $value ) { + if ( ! $value ) { + $value = new stdClass(); + } + + if ( ! isset( $value->translations ) ) { + $value->translations = array(); + } + + $translations = self::get_translations( $this->slug, $this->api_url ); + + if ( ! isset( $translations['translations'] ) ) { + return $value; + } + + $installed_translations = self::get_installed_translations(); + + foreach ( (array) $translations['translations'] as $translation ) { + if ( in_array( $translation['language'], self::get_available_languages() ) ) { + if ( isset( $installed_translations[ $this->slug ][ $translation['language'] ] ) && $translation['updated'] ) { + $local = new DateTime( $installed_translations[ $this->slug ][ $translation['language'] ]['PO-Revision-Date'] ); + $remote = new DateTime( $translation['updated'] ); + + if ( $local >= $remote ) { + continue; + } + } + + $translation['type'] = 'plugin'; + $translation['slug'] = $this->slug; + + $value->translations[] = $translation; + } + } + + return $value; + } + + /** + * Registers actions for clearing translation caches. + * + * @since 2.6 + * + * @return void + */ + public static function register_clean_translations_cache() { + add_action( 'set_site_transient_update_plugins', array( __CLASS__, 'clean_translations_cache' ) ); + add_action( 'delete_site_transient_update_plugins', array( __CLASS__, 'clean_translations_cache' ) ); + } + + /** + * Clears existing translation cache. + * + * @since 2.6 + * + * @return void + */ + public static function clean_translations_cache() { + $translations = get_site_transient( self::TRANSIENT_KEY_PLUGIN ); + + if ( ! is_object( $translations ) ) { + return; + } + + /* + * Don't delete the cache if the transient gets changed multiple times + * during a single request. Set cache lifetime to maximum 15 seconds. + */ + $cache_lifespan = 15; + $time_not_changed = isset( $translations->_last_checked ) && ( time() - $translations->_last_checked ) > $cache_lifespan; + + if ( ! $time_not_changed ) { + return; + } + + delete_site_transient( self::TRANSIENT_KEY_PLUGIN ); + } + + /** + * Gets the translations for a given project. + * + * @since 2.6 + * + * @param string $slug Project directory slug. + * @param string $url Full GlotPress API URL for the project. + * @return array Translation data. + */ + private static function get_translations( $slug, $url ) { + $translations = get_site_transient( self::TRANSIENT_KEY_PLUGIN ); + + if ( ! is_object( $translations ) ) { + $translations = new stdClass(); + } + + if ( isset( $translations->{$slug} ) && is_array( $translations->{$slug} ) ) { + return $translations->{$slug}; + } + + $result = json_decode( wp_remote_retrieve_body( wp_remote_get( $url, array( 'timeout' => 3 ) ) ), true ); + + // Nothing found. + if ( ! is_array( $result ) ) { + $result = array(); + } + + $translations->{$slug} = $result; + $translations->_last_checked = time(); + + set_site_transient( self::TRANSIENT_KEY_PLUGIN, $translations ); + return $result; + } + + /** + * Returns installed translations. + * + * Used to cache the result of wp_get_installed_translations() as it is very expensive. + * + * @since 2.8 + * + * @return array + */ + private static function get_installed_translations() { + if ( null === self::$installed_translations ) { + self::$installed_translations = wp_get_installed_translations( 'plugins' ); + } + return self::$installed_translations; + } + + /** + * Returns available languages. + * + * Used to cache the result of get_available_languages() as it is very expensive. + * + * @since 2.8 + * + * @return array + */ + private static function get_available_languages() { + if ( null === self::$available_languages ) { + self::$available_languages = get_available_languages(); + } + return self::$available_languages; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/upgrade.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/upgrade.php new file mode 100644 index 000000000..d6a267b5c --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/install/upgrade.php @@ -0,0 +1,288 @@ +options = &$options; + } + + /** + * Check if upgrade is possible otherwise die to avoid activation + * + * @since 1.2 + * + * @return void + */ + public function can_activate() { + if ( ! $this->can_upgrade() ) { + ob_start(); + $this->admin_notices(); // FIXME the error message is displayed two times + die( ob_get_contents() ); // phpcs:ignore WordPress.Security.EscapeOutput + } + } + + /** + * Upgrades if possible otherwise returns false to stop Polylang loading + * + * @since 1.2 + * + * @return bool true if upgrade is possible, false otherwise + */ + public function upgrade() { + if ( ! $this->can_upgrade() ) { + add_action( 'all_admin_notices', array( $this, 'admin_notices' ) ); + return false; + } + + delete_transient( 'pll_languages_list' ); + add_action( 'admin_init', array( $this, '_upgrade' ) ); + return true; + } + + + /** + * Check if we the previous version is not too old + * Upgrades if OK + * /!\ never start any upgrade before admin_init as it is likely to conflict with some other plugins + * + * @since 1.2 + * + * @return bool true if upgrade is possible, false otherwise + */ + public function can_upgrade() { + // Don't manage upgrade from version < 1.8 + return version_compare( $this->options['version'], '1.8', '>=' ); + } + + /** + * Displays a notice when ugrading from a too old version + * + * @since 1.0 + * + * @return void + */ + public function admin_notices() { + load_plugin_textdomain( 'polylang' ); + printf( + '

    %s

    %s

    ', + esc_html__( 'Polylang has been deactivated because you upgraded from a too old version.', 'polylang' ), + sprintf( + /* translators: %1$s and %2$s are Polylang version numbers */ + esc_html__( 'Before upgrading to %2$s, please upgrade to %1$s.', 'polylang' ), + '2.9', + POLYLANG_VERSION // phpcs:ignore WordPress.Security.EscapeOutput + ) + ); + } + + /** + * Upgrades the plugin depending on the previous version + * + * @since 1.2 + * + * @return void + */ + public function _upgrade() { + foreach ( array( '2.0.8', '2.1', '2.7', '3.4' ) as $version ) { + if ( version_compare( $this->options['version'], $version, '<' ) ) { + $method_to_call = array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ); + if ( is_callable( $method_to_call ) ) { + call_user_func( $method_to_call ); + } + } + } + + $this->options['previous_version'] = $this->options['version']; // Remember the previous version of Polylang since v1.7.7 + $this->options['version'] = POLYLANG_VERSION; + update_option( 'polylang', $this->options ); + } + + /** + * Upgrades if the previous version is < 2.0.8 + * Changes the user meta 'user_lang' to 'locale' to match WP 4.7 choice + * + * @since 2.0.8 + * + * @return void + */ + protected function upgrade_2_0_8() { + global $wpdb; + $wpdb->update( $wpdb->usermeta, array( 'meta_key' => 'locale' ), array( 'meta_key' => 'user_lang' ) ); + } + + /** + * Upgrades if the previous version is < 2.1. + * Moves strings translations from polylang_mo post_content to post meta _pll_strings_translations. + * + * @since 2.1 + * + * @return void + */ + protected function upgrade_2_1() { + $posts = get_posts( + array( + 'post_type' => 'polylang_mo', + 'post_status' => 'any', + 'numberposts' => -1, + 'nopaging' => true, + ) + ); + + if ( is_array( $posts ) ) { + foreach ( $posts as $post ) { + $meta = get_post_meta( $post->ID, '_pll_strings_translations', true ); + + if ( empty( $meta ) ) { + $strings = maybe_unserialize( $post->post_content ); + if ( is_array( $strings ) ) { + update_post_meta( $post->ID, '_pll_strings_translations', $strings ); + } + } + } + } + } + + /** + * Upgrades if the previous version is < 2.7 + * Replace numeric keys by hashes in WPML registered strings + * Dismiss the wizard notice for existing sites + * + * @since 2.7 + * + * @return void + */ + protected function upgrade_2_7() { + $strings = get_option( 'polylang_wpml_strings' ); + if ( is_array( $strings ) ) { + $new_strings = array(); + + foreach ( $strings as $string ) { + $context = $string['context']; + $name = $string['name']; + + $key = md5( "$context | $name" ); + $new_strings[ $key ] = $string; + } + update_option( 'polylang_wpml_strings', $new_strings ); + } + + PLL_Admin_Notices::dismiss( 'wizard' ); + } + + /** + * Upgrades if the previous version is < 3.4.0. + * + * @since 3.4 + * + * @return void + */ + protected function upgrade_3_4() { + $this->migrate_locale_fallback_to_language_description(); + + $this->migrate_strings_translations(); + } + + /** + * Moves strings translations from post meta to term meta _pll_strings_translations. + * + * @since 3.4 + * + * @return void + */ + protected function migrate_strings_translations() { + $posts = get_posts( + array( + 'post_type' => 'polylang_mo', + 'post_status' => 'any', + 'numberposts' => -1, + 'nopaging' => true, + ) + ); + + if ( ! is_array( $posts ) ) { + return; + } + + foreach ( $posts as $post ) { + $meta = get_post_meta( $post->ID, '_pll_strings_translations', true ); + + $term_id = (int) substr( $post->post_title, 12 ); + + // Do not delete post metas in case a user needs to rollback to Polylang < 3.4. + + if ( empty( $meta ) || ! is_array( $meta ) ) { + continue; + } + + update_term_meta( $term_id, '_pll_strings_translations', wp_slash( $meta ) ); + } + } + + /** + * Migrate locale fallback to language term description. + * + * @since 3.4 + * + * @return void + */ + protected function migrate_locale_fallback_to_language_description() { + // Migrate locale fallbacks from term metas to language term description. + $terms = get_terms( + array( + 'taxonomy' => 'language', + 'hide_empty' => false, + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + array( + 'key' => 'fallback', + 'compare_key' => 'EXISTS', + ), + ), + ) + ); + + if ( ! is_array( $terms ) ) { + return; + } + + foreach ( $terms as $term ) { + $fallbacks = get_term_meta( $term->term_id, 'fallback', true ); + + delete_term_meta( $term->term_id, 'fallback' ); + + if ( empty( $fallbacks ) || ! is_array( $fallbacks ) ) { + // Empty or invalid value, should not happen. + continue; + } + + $description = maybe_unserialize( $term->description ); + $description = is_array( $description ) ? $description : array(); + + $description['fallbacks'] = $fallbacks; + /** @var string */ + $description = maybe_serialize( $description ); + + wp_update_term( $term->term_id, 'language', array( 'description' => $description ) ); + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/aqua-resizer.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/aqua-resizer.php new file mode 100644 index 000000000..99f930779 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/aqua-resizer.php @@ -0,0 +1,32 @@ + 'aq_resize' ) ) ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/load.php new file mode 100644 index 000000000..132547618 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/aqua-resizer/load.php @@ -0,0 +1,13 @@ +aq_resizer = new PLL_Aqua_Resizer(); +PLL_Integrations::instance()->aq_resizer->init(); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/cache-compat.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/cache-compat.php new file mode 100644 index 000000000..8f9d1fb45 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/cache-compat.php @@ -0,0 +1,105 @@ +options['force_lang'] ) ? wp_parse_url( PLL()->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN; + $samesite = ( 3 === PLL()->options['force_lang'] ) ? 'None' : 'Lax'; + + /** This filter is documented in include/cookie.php */ + $expiration = (int) apply_filters( 'pll_cookie_expiration', YEAR_IN_SECONDS ); + + if ( 0 !== $expiration ) { + $format = 'var expirationDate = new Date(); + expirationDate.setTime( expirationDate.getTime() + %7$d * 1000 ); + document.cookie = "%1$s=%2$s; expires=" + expirationDate.toUTCString() + "; path=%3$s%4$s%5$s%6$s";'; + } else { + $format = 'document.cookie = "%1$s=%2$s; path=%3$s%4$s%5$s%6$s";'; + } + + $js = sprintf( + "(function() { + {$format} + }());\n", + esc_js( PLL_COOKIE ), + esc_js( pll_current_language() ), + esc_js( COOKIEPATH ), + $domain ? '; domain=' . esc_js( $domain ) : '', + is_ssl() ? '; secure' : '', + '; SameSite=' . $samesite, + esc_js( $expiration ) + ); + + $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"'; + + echo "\n{$js}\n\n"; // phpcs:ignore WordPress.Security.EscapeOutput + } + + /** + * Informs cache plugins not to cache the home in the default language + * When the detection of the browser preferred language is active + * + * @since 2.3 + */ + public function do_not_cache_site_home() { + if ( ! defined( 'DONOTCACHEPAGE' ) && PLL()->options['browser'] && PLL()->options['hide_default'] && is_front_page() && pll_current_language() === pll_default_language() ) { + define( 'DONOTCACHEPAGE', true ); + } + } + + /** + * Allows cache plugins to clean the right post type archive cache when cleaning a post cache. + * + * @since 3.0.5 + * + * @param int $post_id Post id. + */ + public function clean_post_cache( $post_id ) { + $lang = PLL()->model->post->get_language( $post_id ); + + if ( $lang ) { + $filter_callback = function ( $link, $post_type ) use ( $lang ) { + return pll_is_translated_post_type( $post_type ) && 'post' !== $post_type ? PLL()->links_model->switch_language_in_link( $link, $lang ) : $link; + }; + add_filter( 'post_type_archive_link', $filter_callback, 99, 2 ); + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/load.php new file mode 100644 index 000000000..3042f81a4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/cache/load.php @@ -0,0 +1,20 @@ +cache_compat = new PLL_Cache_Compat(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/cft.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/cft.php new file mode 100644 index 000000000..1ce9a6bf1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/cft.php @@ -0,0 +1,35 @@ +ID; + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/load.php new file mode 100644 index 000000000..cb5780941 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/custom-field-template/load.php @@ -0,0 +1,21 @@ +cft = new PLL_Cft(); + PLL_Integrations::instance()->cft->init(); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/domain-mapping.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/domain-mapping.php new file mode 100644 index 000000000..2f0aef39a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/domain-mapping.php @@ -0,0 +1,82 @@ + 1 ) { + // Don't go further if we stopped loading the plugin early ( for example when deactivate-polylang=1 ). + if ( ! function_exists( 'PLL' ) ) { + return; + } + + // Don't redirect the main site + if ( is_main_site() ) { + return; + } + + // Don't redirect post previews + if ( isset( $_GET['preview'] ) && 'true' === $_GET['preview'] ) { // phpcs:ignore WordPress.Security.NonceVerification + return; + } + + // Don't redirect theme customizer + if ( isset( $_POST['customize'] ) && isset( $_POST['theme'] ) && 'on' === $_POST['customize'] ) { // phpcs:ignore WordPress.Security.NonceVerification + return; + } + + // If we can't associate the requested domain to a language, redirect to the default domain + $requested_url = pll_get_requested_url(); + $requested_host = wp_parse_url( $requested_url, PHP_URL_HOST ); + + $hosts = PLL()->links_model->get_hosts(); + $lang = array_search( $requested_host, $hosts ); + + if ( empty( $lang ) ) { + $status = get_site_option( 'dm_301_redirect' ) ? '301' : '302'; // Honor status redirect option + $redirect = str_replace( '://' . $requested_host, '://' . $hosts[ $options['default_lang'] ], $requested_url ); + wp_safe_redirect( $redirect, $status ); + exit; + } + } else { + // Otherwise rely on MU Domain Mapping + redirect_to_mapped_domain(); + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/load.php new file mode 100644 index 000000000..ff6d61037 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/domain-mapping/load.php @@ -0,0 +1,12 @@ +dm = new PLL_Domain_Mapping(); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/duplicate-post/duplicate-post.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/duplicate-post/duplicate-post.php new file mode 100644 index 000000000..f73873507 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/duplicate-post/duplicate-post.php @@ -0,0 +1,37 @@ +duplicate_post = new PLL_Duplicate_Post(); + PLL_Integrations::instance()->duplicate_post->init(); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/integrations.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/integrations.php new file mode 100644 index 000000000..3d9882f98 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/integrations.php @@ -0,0 +1,50 @@ +is_active() || false !== $featured_ids ) { + return $featured_ids; + } + + $settings = Featured_Content::get_setting(); + + if ( ! $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) { + return $featured_ids; + } + + // Get featured tag translations + $tags = PLL()->model->term->get_translations( $term->term_id ); + $ids = array(); + + // Query for featured posts in all languages + // One query per language to get the correct number of posts per language + foreach ( $tags as $tag ) { + $args = array( + 'lang' => 0, // Avoid language filters. + 'fields' => 'ids', + 'numberposts' => Featured_Content::$max_posts, + 'tax_query' => array( + array( + 'taxonomy' => 'post_tag', + 'terms' => (int) $tag, + ), + ), + ); + + // Available in Jetpack, but not in Twenty Fourteen. + if ( isset( Featured_Content::$post_types ) ) { + $args['post_type'] = Featured_Content::$post_types; + } + + $_ids = get_posts( $args ); + $ids = array_merge( $ids, $_ids ); + } + + $ids = array_map( 'absint', $ids ); + set_transient( 'featured_content_ids', $ids ); + + return $ids; + } + + /** + * Translates the featured tag id in featured content settings + * Mainly to allow hiding it when requested in featured content options + * Acts only on frontend + * + * @since 1.4 + * + * @param array $settings featured content settings + * @return array modified $settings + */ + public function option_featured_content( $settings ) { + if ( $this->is_active() && PLL() instanceof PLL_Frontend && $settings['tag-id'] && $tr = pll_get_term( $settings['tag-id'] ) ) { + $settings['tag-id'] = $tr; + } + + return $settings; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/jetpack.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/jetpack.php new file mode 100644 index 000000000..a4f989772 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/jetpack.php @@ -0,0 +1,137 @@ +options['force_lang'] > 1 ) { + add_filter( 'infinite_scroll_ajax_url', array( PLL()->links_model, 'site_url' ) ); + add_filter( 'infinite_scroll_js_settings', array( $this, 'jetpack_infinite_scroll_js_settings' ) ); + } + } + + /** + * Filter the Top Posts and Pages by language. + * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php + * + * @since 1.5.4 + * + * @param array $posts Array of the most popular posts. + * @return array + */ + public function jetpack_widget_get_top_posts( $posts ) { + foreach ( $posts as $k => $post ) { + if ( pll_current_language() !== pll_get_post_language( $post['post_id'] ) ) { + unset( $posts[ $k ] ); + } + } + + return $posts; + } + + /** + * Filter the HTML of the Contact Form and output the one requested by language. + * Adapted from the same function in jetpack-3.0.2/3rd-party/wpml.php + * Keeps using 'icl_translate' as the function registers the string. + * + * @since 1.5.4 + * + * @param string $r Contact Form HTML output. + * @param string $field_label Field label. + * @return string + */ + public function grunion_contact_form_field_html_filter( $r, $field_label ) { + if ( function_exists( 'icl_translate' ) ) { + if ( pll_current_language() !== pll_default_language() ) { + $label_translation = icl_translate( 'jetpack ', $field_label . '_label', $field_label ); + $r = str_replace( $field_label, $label_translation, $r ); + } + } + + return $r; + } + + /** + * Adds opengraph support for locale and translations. + * + * @since 1.6 + * + * @param array $tags Opengraph tags to output. + * @return array + */ + public function jetpack_ogp( $tags ) { + if ( did_action( 'pll_init' ) ) { + foreach ( PLL()->model->get_languages_list() as $language ) { + if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) { + $tags['og:locale:alternate'][] = $language->facebook; + } + if ( PLL()->curlang->slug === $language->slug && isset( $language->facebook ) ) { + $tags['og:locale'] = $language->facebook; + } + } + } + return $tags; + } + + /** + * Allows to make sure that related posts are in the correct language. + * + * @since 1.8 + * + * @param array $filters Array of ElasticSearch filters based on the post_id and args. + * @param string $post_id Post ID of the post for which we are retrieving Related Posts. + * @return array + */ + public function jetpack_relatedposts_filter_filters( $filters, $post_id ) { + $slug = sanitize_title( pll_get_post_language( $post_id, 'slug' ) ); + $filters[] = array( 'term' => array( 'taxonomy.language.slug' => $slug ) ); + return $filters; + } + + /** + * Fixes the settings history host for infinite scroll when using subdomains or multiple domains. + * + * @since 2.1 + * + * @param array $settings Infinite scroll JS settings outputted in the head. + * @return array + */ + public function jetpack_infinite_scroll_js_settings( $settings ) { + $settings['history']['host'] = wp_parse_url( pll_home_url(), PHP_URL_HOST ); // Jetpack uses get_option( 'home' ). + return $settings; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/load.php new file mode 100644 index 000000000..9ed976697 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/jetpack/load.php @@ -0,0 +1,14 @@ +jetpack = new PLL_Jetpack(); // Must be loaded before the plugin is active. +add_action( 'pll_init', array( PLL_Integrations::instance()->featured_content = new PLL_Featured_Content(), 'init' ) ); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/load.php new file mode 100644 index 000000000..6cc3722e8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/load.php @@ -0,0 +1,13 @@ +no_category_base = new PLL_No_Category_Base(); +PLL_Integrations::instance()->no_category_base->init(); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/no-category-base.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/no-category-base.php new file mode 100644 index 000000000..703ac6bf7 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/no-category-base/no-category-base.php @@ -0,0 +1,36 @@ +twenty_seventeen = new PLL_Twenty_Seventeen(), 'init' ) ); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/twenty-seventeen/twenty-seven-teen.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/twenty-seventeen/twenty-seven-teen.php new file mode 100644 index 000000000..a75540fa9 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/twenty-seventeen/twenty-seven-teen.php @@ -0,0 +1,30 @@ + 1 ), array( 'context' => 'Twenty Seventeen' ) ); + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/load.php new file mode 100644 index 000000000..fca8ee3e8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/load.php @@ -0,0 +1,12 @@ +wp_importer = new PLL_WordPress_Importer(); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wordpress-importer.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wordpress-importer.php new file mode 100644 index 000000000..7d1e9f2a5 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wordpress-importer.php @@ -0,0 +1,70 @@ +getFileName() ) ) . '/languages' ); + + $GLOBALS['wp_import'] = new PLL_WP_Import(); + register_importer( 'wordpress', 'WordPress', __( 'Import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.', 'polylang' ), array( $GLOBALS['wp_import'], 'dispatch' ) ); // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText + } + + /** + * Sets the flag when importing a language and the file has been exported with Polylang < 1.8. + * + * @since 1.8 + * + * @param array $terms An array of arrays containing terms information form the WXR file. + * @return array + */ + public function wp_import_terms( $terms ) { + $languages = include POLYLANG_DIR . '/settings/languages.php'; + + foreach ( $terms as $key => $term ) { + if ( 'language' === $term['term_taxonomy'] ) { + $description = maybe_unserialize( $term['term_description'] ); + if ( empty( $description['flag_code'] ) && isset( $languages[ $description['locale'] ] ) ) { + $description['flag_code'] = $languages[ $description['locale'] ]['flag']; + $terms[ $key ]['term_description'] = maybe_serialize( $description ); + } + } + } + return $terms; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wp-import.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wp-import.php new file mode 100644 index 000000000..8e7f36930 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-importer/wp-import.php @@ -0,0 +1,204 @@ +terms. + foreach ( $this->terms as $term ) { + if ( 'post_translations' == $term['term_taxonomy'] ) { + $this->post_translations[] = $term; + } + if ( 'term_translations' == $term['term_taxonomy'] ) { + $term_translations[] = $term; + } + } + + parent::process_terms(); + + // First reset the core terms cache as WordPress Importer calls wp_suspend_cache_invalidation( true ); + wp_cache_set( 'last_changed', microtime(), 'terms' ); + + // Assign the default language in case the importer created the first language. + if ( empty( PLL()->options['default_lang'] ) ) { + $languages = get_terms( array( 'taxonomy' => 'language', 'hide_empty' => false, 'orderby' => 'term_id' ) ); + $default_lang = reset( $languages ); + PLL()->options['default_lang'] = $default_lang->slug; + update_option( 'polylang', PLL()->options ); + } + + // Clean languages cache in case some of them were created during import. + PLL()->model->clean_languages_cache(); + + $this->remap_terms_relations( $term_translations ); + $this->remap_translations( $term_translations, $this->processed_terms ); + } + + /** + * Overrides WP_Import::process_post to remap posts translations + * Also merges strings translations from the WXR file to the existing ones + * + * @since 1.2 + */ + public function process_posts() { + $menu_items = $mo_posts = array(); + + // Store this for future usage as parent function unset $this->posts + foreach ( $this->posts as $post ) { + if ( 'nav_menu_item' == $post['post_type'] ) { + $menu_items[] = $post; + } + + if ( 0 === strpos( $post['post_title'], 'polylang_mo_' ) ) { + $mo_posts[] = $post; + } + } + + if ( ! empty( $mo_posts ) ) { + new PLL_MO(); // Just to register the polylang_mo post type before processing posts + } + + parent::process_posts(); + + PLL()->model->clean_languages_cache(); // To update the posts count in ( cached ) languages list + + $this->remap_translations( $this->post_translations, $this->processed_posts ); + unset( $this->post_translations ); + + // Language switcher menu items + foreach ( $menu_items as $item ) { + foreach ( $item['postmeta'] as $meta ) { + if ( '_pll_menu_item' == $meta['key'] ) { + update_post_meta( $this->processed_menu_items[ $item['post_id'] ], '_pll_menu_item', maybe_unserialize( $meta['value'] ) ); + } + } + } + + // Merge strings translations + foreach ( $mo_posts as $post ) { + $lang_id = (int) substr( $post['post_title'], 12 ); + + if ( ! empty( $this->processed_terms[ $lang_id ] ) ) { + if ( $strings = maybe_unserialize( $post['post_content'] ) ) { + $mo = new PLL_MO(); + $mo->import_from_db( $this->processed_terms[ $lang_id ] ); + foreach ( $strings as $msg ) { + $mo->add_entry_or_merge( $mo->make_entry( $msg[0], $msg[1] ) ); + } + $mo->export_to_db( $this->processed_terms[ $lang_id ] ); + } + } + // Delete the now useless imported post + wp_delete_post( $this->processed_posts[ $post['post_id'] ], true ); + } + } + + /** + * Remaps terms languages + * + * @since 1.2 + * + * @param array $terms array of terms in 'term_translations' taxonomy + */ + protected function remap_terms_relations( &$terms ) { + global $wpdb; + + $trs = array(); + + foreach ( $terms as $term ) { + $translations = maybe_unserialize( $term['term_description'] ); + foreach ( $translations as $slug => $old_id ) { + if ( $old_id && ! empty( $this->processed_terms[ $old_id ] ) && $lang = PLL()->model->get_language( $slug ) ) { + // Language relationship + $trs[] = $wpdb->prepare( '( %d, %d )', $this->processed_terms[ $old_id ], $lang->get_tax_prop( 'term_language', 'term_taxonomy_id' ) ); + + // Translation relationship + $trs[] = $wpdb->prepare( '( %d, %d )', $this->processed_terms[ $old_id ], get_term( $this->processed_terms[ $term['term_id'] ], 'term_translations' )->term_taxonomy_id ); + } + } + } + + // Insert term_relationships + if ( ! empty( $trs ) ) { + $trs = array_unique( $trs ); + + // Make sure we don't attempt to insert already existing term relationships + $existing_trs = $wpdb->get_results( + "SELECT tr.object_id, tr.term_taxonomy_id FROM {$wpdb->term_relationships} AS tr + INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id + WHERE tt.taxonomy IN ( 'term_language', 'term_translations' )" + ); + + foreach ( $existing_trs as $key => $tr ) { + $existing_trs[ $key ] = $wpdb->prepare( '( %d, %d )', $tr->object_id, $tr->term_taxonomy_id ); + } + + $trs = array_diff( $trs, $existing_trs ); + + if ( ! empty( $trs ) ) { + // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) ); + } + } + } + + /** + * Remaps translations for both posts and terms + * + * @since 1.2 + * + * @param array $terms array of terms in 'post_translations' or 'term_translations' taxonomies + * @param array $processed_objects array of posts or terms processed by WordPress Importer + */ + protected function remap_translations( &$terms, &$processed_objects ) { + global $wpdb; + + $u = array(); + + foreach ( $terms as $term ) { + $translations = maybe_unserialize( $term['term_description'] ); + $new_translations = array(); + + foreach ( $translations as $slug => $old_id ) { + if ( $old_id && ! empty( $processed_objects[ $old_id ] ) ) { + $new_translations[ $slug ] = $processed_objects[ $old_id ]; + } + } + + if ( ! empty( $new_translations ) ) { + $u['case'][] = $wpdb->prepare( 'WHEN %d THEN %s', $this->processed_terms[ $term['term_id'] ], maybe_serialize( $new_translations ) ); + $u['in'][] = (int) $this->processed_terms[ $term['term_id'] ]; + } + } + + if ( ! empty( $u ) ) { + // PHPCS:disable WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( + "UPDATE {$wpdb->term_taxonomy} + SET description = ( CASE term_id " . implode( ' ', $u['case'] ) . ' END ) + WHERE term_id IN ( ' . implode( ',', $u['in'] ) . ' )' + ); + // PHPCS:enable + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/as3cf.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/as3cf.php new file mode 100644 index 000000000..33d5518de --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/as3cf.php @@ -0,0 +1,72 @@ +is_media_translated[ $post_id ] = ( count( pll_get_post_translations( $post_id ) ) > 1 ); + } + + /** + * Deletes the WP Offload Media information from the attachment being deleted. + * That way WP Offload Media won't delete the file stored in the cloud. + * Done after Polylang has deleted the translations information, to avoid the synchronization of the deletion + * and of course before WP Offload Media deletes the file, normally at priority 20. + * + * @since 2.6 + * + * @param int $post_id Id of the attachment being deleted. + */ + public function prevent_file_deletion( $post_id ) { + if ( ! empty( $this->is_media_translated[ $post_id ] ) ) { + delete_post_meta( $post_id, 'amazonS3_info' ); + delete_post_meta( $post_id, 'as3cf_filesize_total' ); + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/load.php new file mode 100644 index 000000000..15acfd091 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-offload-media/load.php @@ -0,0 +1,20 @@ +as3cf = new PLL_AS3CF(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/load.php new file mode 100644 index 000000000..0ce0e1766 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/load.php @@ -0,0 +1,21 @@ +wp_sweep = new PLL_WP_Sweep(); + PLL_Integrations::instance()->wp_sweep->init(); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/wp-sweep.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/wp-sweep.php new file mode 100644 index 000000000..b9a195d6d --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wp-sweep/wp-sweep.php @@ -0,0 +1,62 @@ +model->get_languages_list() as $language ) { + $excluded_term_ids = array_merge( + $excluded_term_ids, + array_values( $language->get_tax_props( 'term_id' ) ) + ); + } + + return array_unique( $excluded_term_ids ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/load.php new file mode 100644 index 000000000..3965a23c3 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/load.php @@ -0,0 +1,20 @@ +wpseo = new PLL_WPSEO(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo-ogp.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo-ogp.php new file mode 100644 index 000000000..4b6e70162 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo-ogp.php @@ -0,0 +1,54 @@ +locale = $locale; + } + + /** + * Returns the meta Opengraph alternate locale meta tag + * + * @since 2.7.3 + * + * @return string + */ + public function present() { + return sprintf( '', esc_attr( $this->get() ) ); + } + + /** + * Returns the alternate locale + * + * @since 2.7.3 + * + * @return string + */ + public function get() { + return $this->locale; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo.php new file mode 100644 index 000000000..08b4b6809 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/wpseo/wpseo.php @@ -0,0 +1,517 @@ +options['force_lang'] > 1 ) { + add_filter( 'wpseo_enable_xml_sitemap_transient_caching', '__return_false' ); // Disable cache! otherwise WPSEO keeps only one domain (thanks to Junaid Bhura) + add_filter( 'home_url', array( $this, 'wpseo_home_url' ), 10, 2 ); // Fix home_url + add_action( 'setup_theme', array( $this, 'maybe_deactivate_sitemap' ) ); // Deactivate sitemaps for inactive languages. + } else { + // Get all terms in all languages when the language is set from the content or directory name + add_filter( 'get_terms_args', array( $this, 'wpseo_remove_terms_filter' ) ); + add_action( 'pre_get_posts', array( $this, 'before_sitemap' ), 0 ); // Needs to be fired before WPSEO_Sitemaps::redirect() + } + + add_filter( 'pll_home_url_white_list', array( $this, 'wpseo_home_url_white_list' ) ); + add_filter( 'wpseo_frontend_presenters', array( $this, 'wpseo_frontend_presenters' ) ); + add_filter( 'wpseo_canonical', array( $this, 'wpseo_canonical' ) ); + add_filter( 'wpseo_frontend_presentation', array( $this, 'frontend_presentation' ) ); + add_filter( 'wpseo_breadcrumb_indexables', array( $this, 'breadcrumb_indexables' ) ); + } else { + add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ), 10, 4 ); + add_filter( 'pll_translate_post_meta', array( $this, 'translate_post_meta' ), 10, 3 ); + add_filter( 'pll_post_metas_to_export', array( $this, 'export_post_metas' ) ); + + // Yoast SEO adds the columns hooks only for the 'inline-save' action. We need them for 'pll_update_post_rows' too. + if ( wp_doing_ajax() && isset( $_POST['action'] ) && 'pll_update_post_rows' === $_POST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + $GLOBALS['wpseo_meta_columns'] = new WPSEO_Meta_Columns(); + } + } + } + + /** + * Registers options for translation. + * + * @since 2.9 + */ + public function wpseo_translate_options() { + if ( method_exists( 'WPSEO_Options', 'clear_cache' ) ) { + WPSEO_Options::clear_cache(); + } + + $keys = array( + 'title-*', + 'metadesc-*', + 'bctitle-*', + 'breadcrumbs-sep', + 'breadcrumbs-home', + 'breadcrumbs-prefix', + 'breadcrumbs-archiveprefix', + 'breadcrumbs-searchprefix', + 'breadcrumbs-404crumb', + 'company_name', + 'rssbefore', + 'rssafter', + 'social-title-*', + 'social-description-*', + ); + + new PLL_Translate_Option( 'wpseo_titles', array_fill_keys( $keys, 1 ), array( 'context' => 'wordpress-seo' ) ); + + $keys = array( + 'og_frontpage_title', + 'og_frontpage_desc', + ); + + new PLL_Translate_Option( 'wpseo_social', array_fill_keys( $keys, 1 ), array( 'context' => 'wordpress-seo' ) ); + } + + /** + * Fixes the home url as well as the stylesheet url, + * only when using multiple domains or subdomains. + * + * @since 1.6.4 + * + * @param string $url The complete URL including scheme and path. + * @param string $path Path relative to the home URL. + * @return $url + */ + public function wpseo_home_url( $url, $path ) { + if ( empty( $path ) ) { + $path = ltrim( (string) wp_parse_url( pll_get_requested_url(), PHP_URL_PATH ), '/' ); + } + + if ( preg_match( '#sitemap(_index)?\.xml|([^\/]+?)-?sitemap([0-9]+)?\.xml|([a-z]+)?-?sitemap\.xsl#', $path ) ) { + $url = PLL()->links_model->switch_language_in_link( $url, PLL()->curlang ); + } + + return $url; + } + + /** + * Get active languages for the sitemaps + * + * @since 2.0 + * + * @return array list of active language slugs, empty if all languages are active + */ + protected function wpseo_get_active_languages() { + $languages = PLL()->model->get_languages_list(); + if ( wp_list_filter( $languages, array( 'active' => false ) ) ) { + return wp_list_pluck( wp_list_filter( $languages, array( 'active' => false ), 'NOT' ), 'slug' ); + } + return array(); + } + + /** + * Modifies the sql request for posts sitemaps. + * + * @since 1.6.4 + * + * @param string $sql JOIN clause. + * @param string $post_type Post type. + * @return string + */ + public function wpseo_posts_join( $sql, $post_type ) { + return pll_is_translated_post_type( $post_type ) ? $sql . PLL()->model->post->join_clause() : $sql; + } + + /** + * Modifies the sql request for posts sitemaps. + * + * @since 1.6.4 + * + * @param string $sql WHERE clause. + * @param string $post_type Post type. + * @return string + */ + public function wpseo_posts_where( $sql, $post_type ) { + if ( ! pll_is_translated_post_type( $post_type ) ) { + return $sql; + } + + if ( PLL()->options['force_lang'] > 1 && PLL()->curlang instanceof PLL_Language ) { + return $sql . PLL()->model->post->where_clause( PLL()->curlang ); + } + + $languages = $this->wpseo_get_active_languages(); + + if ( empty( $languages ) ) { // Empty when all languages are active. + $languages = pll_languages_list(); + } + + return $sql . PLL()->model->post->where_clause( $languages ); + } + + /** + * Removes the language filter (and remove inactive languages) for the taxonomy sitemaps + * Only when the language is set from the content or directory name + * + * @since 1.0.3 + * + * @param array $args get_terms arguments + * @return array modified list of arguments + */ + public function wpseo_remove_terms_filter( $args ) { + if ( isset( $GLOBALS['wp_query']->query['sitemap'] ) ) { + $args['lang'] = implode( ',', $this->wpseo_get_active_languages() ); + } + return $args; + } + + /** + * Deactivates the sitemap for inactive languages when using subdomains or multiple domains + * + * @since 2.6.1 + */ + public function maybe_deactivate_sitemap() { + global $wpseo_sitemaps; + + if ( isset( $wpseo_sitemaps ) ) { + $active_languages = $this->wpseo_get_active_languages(); + if ( ! empty( $active_languages ) && ! in_array( pll_current_language(), $active_languages ) ) { + remove_action( 'pre_get_posts', array( $wpseo_sitemaps, 'redirect' ), 1 ); + } + } + } + + /** + * Add filters before the sitemap is evaluated and outputted. + * + * @since 2.6 + * + * @param WP_Query $query Instance of WP_Query being filtered. + */ + public function before_sitemap( $query ) { + $type = $query->get( 'sitemap' ); + + // Add the post post type archives in all languages to the sitemap + // Add the homepages for all languages to the sitemap when the front page displays posts + if ( $type && pll_is_translated_post_type( $type ) && ( 'post' !== $type || ! get_option( 'page_on_front' ) ) ) { + add_filter( "wpseo_sitemap_{$type}_content", array( $this, 'add_post_type_archive' ) ); + } + } + + /** + * Generates a post type archive sitemap url + * + * @since 2.6.1 + * + * @param string $link The url. + * @param string $post_type The post type name. + * @return string Formatted sitemap url. + */ + protected function format_sitemap_url( $link, $post_type ) { + global $wpseo_sitemaps; + + return $wpseo_sitemaps->renderer->sitemap_url( + array( + 'loc' => $link, + 'mod' => WPSEO_Sitemaps::get_last_modified_gmt( $post_type ), + 'pri' => 1, + 'chf' => 'daily', + ) + ); + } + + /** + * Adds the home and post type archives urls for all (active) languages to the sitemap + * + * @since 2.6 + * + * @param string $str additional urls to sitemap post + * @return string + */ + public function add_post_type_archive( $str ) { + $post_type = substr( substr( current_filter(), 14 ), 0, -8 ); + $post_type_obj = get_post_type_object( $post_type ); + $languages = wp_list_filter( PLL()->model->get_languages_list(), array( 'active' => false ), 'NOT' ); + + if ( 'post' === $post_type ) { + if ( ! empty( PLL()->options['hide_default'] ) ) { + // The home url is of course already added by WPSEO. + $languages = wp_list_filter( $languages, array( 'slug' => pll_default_language() ), 'NOT' ); + } + + foreach ( $languages as $lang ) { + $str .= $this->format_sitemap_url( pll_home_url( $lang->slug ), $post_type ); + } + } elseif ( $post_type_obj->has_archive ) { + // Exclude cases where a post type archive is attached to a page (ex: WooCommerce). + $slug = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive; + + if ( ! wpcom_vip_get_page_by_path( $slug ) ) { + // The post type archive in the current language is already added by WPSEO. + $languages = wp_list_filter( $languages, array( 'slug' => pll_current_language() ), 'NOT' ); + + foreach ( $languages as $lang ) { + PLL()->curlang = $lang; // Switch the language to get the correct archive link. + $link = get_post_type_archive_link( $post_type ); + $str .= $this->format_sitemap_url( $link, $post_type ); + } + } + } + + return $str; + } + + /** + * Filters the home url. + * + * @since 1.1.2 + * + * @param array $arr The list of files or functions for which `home_url()` must be filtered. + * @return array + */ + public function wpseo_home_url_white_list( $arr ) { + return array_merge( $arr, array( array( 'file' => 'wordpress-seo' ) ) ); + } + + /** + * Get alternate language codes for Opengraph. + * + * @since 2.7.3 + * + * @return string[] + */ + protected function get_ogp_alternate_languages() { + $alternates = array(); + + foreach ( PLL()->model->get_languages_list() as $language ) { + if ( isset( PLL()->curlang ) && PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) { + $alternates[] = $language->facebook; + } + } + + // There is a risk that 2 languages have the same Facebook locale. So let's make sure to output each locale only once. + return array_unique( $alternates ); + } + + /** + * Adds opengraph support for translations + * + * @since 2.7.3 + * + * @param array $presenters An array of objects implementing Abstract_Indexable_Presenter + * @return array + */ + public function wpseo_frontend_presenters( $presenters ) { + $_presenters = array(); + + foreach ( $presenters as $presenter ) { + $_presenters[] = $presenter; + if ( $presenter instanceof Yoast\WP\SEO\Presenters\Open_Graph\Locale_Presenter ) { + foreach ( $this->get_ogp_alternate_languages() as $lang ) { + $_presenters[] = new PLL_WPSEO_OGP( $lang ); + } + } + } + return $_presenters; + } + + /** + * Fixes the canonical front page url as unlike WP, WPSEO does not add a trailing slash to the canonical front page url. + * + * @since 1.7.10 + * + * @param string $url The canonical URL evaluated by Yoast SEO. + * @return $url + */ + public function wpseo_canonical( $url ) { + return is_front_page( $url ) && get_option( 'permalink_structure' ) ? trailingslashit( $url ) : $url; + } + + /** + * Fixes the links and strings stored in the indexable table since Yoast SEO 14.0 + * + * @since 2.8.2 + * + * @param object $presentation The indexable presentation. + * @return object + */ + public function frontend_presentation( $presentation ) { + switch ( $presentation->model->object_type ) { + case 'home-page': + $presentation->model->title = WPSEO_Options::get( 'title-home-wpseo' ); + $presentation->model->description = WPSEO_Options::get( 'metadesc-home-wpseo' ); + $presentation->model->open_graph_title = WPSEO_Options::get( 'og_frontpage_title' ); + $presentation->model->open_graph_description = WPSEO_Options::get( 'og_frontpage_desc' ); + break; + + case 'post-type-archive': + if ( pll_is_translated_post_type( $presentation->model->object_sub_type ) ) { + $presentation->model->title = WPSEO_Options::get( 'title-ptarchive-' . $presentation->model->object_sub_type ); + $presentation->model->description = WPSEO_Options::get( 'metadesc-ptarchive-' . $presentation->model->object_sub_type ); + } + break; + + case 'system-page': + switch ( $presentation->model->object_sub_type ) { + case '404': + $presentation->model->title = WPSEO_Options::get( 'title-404-wpseo' ); + break; + case 'search-result': + $presentation->model->title = WPSEO_Options::get( 'title-search-wpseo' ); + break; + } + break; + } + + return $presentation; + } + + /** + * Fixes the breadcrumb links and strings stored in the indexable table since Yoast SEO 14.0. + * + * In version 17.0, the breadcrumb links do not honor the filter `wpseo_dynamic_permalinks_enabled`. + * + * @since 2.8.3 + * + * @param array $indexables An array of Indexable objects. + * @return array + */ + public function breadcrumb_indexables( $indexables ) { + foreach ( $indexables as &$indexable ) { + if ( 'home-page' === $indexable->object_type || ( 'post' === $indexable->object_type && 'page' === $indexable->object_sub_type && get_option( 'page_on_front' ) === $indexable->object_id ) ) { + // Handles both when the front page displays the list of posts or a static page. + $indexable->permalink = pll_home_url(); + $indexable->breadcrumb_title = pll__( WPSEO_Options::get( 'breadcrumbs-home' ) ); + } elseif ( 'post' === $indexable->object_type && 'page' === $indexable->object_sub_type && get_option( 'page_for_posts' ) === $indexable->object_id ) { + $indexable->permalink = get_permalink( $indexable->object_id ); + } elseif ( 'post-type-archive' === $indexable->object_type && pll_is_translated_post_type( $indexable->object_sub_type ) ) { + $indexable->permalink = get_post_type_archive_link( $indexable->object_sub_type ); + $breadcrumb_title = WPSEO_Options::get( 'bctitle-ptarchive-' . $indexable->object_sub_type ); + $breadcrumb_title = $breadcrumb_title ? $breadcrumb_title : $indexable->breadcrumb_title; // The option may be empty. + $indexable->breadcrumb_title = pll__( $breadcrumb_title ); + } elseif ( 'term' === $indexable->object_type && pll_is_translated_taxonomy( $indexable->object_sub_type ) ) { + $indexable->permalink = get_term_link( $indexable->object_id ); + } + } + + return $indexables; + } + + /** + * Copies or synchronizes the metas. + * + * @since 2.3.3 + * + * @param string[] $keys List of custom fields names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the post from which we copy information. + * @param int $to Id of the post to which we paste information. + * @return array + */ + public function copy_post_metas( $keys, $sync, $from, $to ) { + if ( ! $sync ) { + // Text requiring translation. + $keys = array_merge( $keys, $this->get_translatable_meta_keys() ); + + // Copy the image urls. + $keys[] = '_yoast_wpseo_opengraph-image'; + $keys[] = '_yoast_wpseo_twitter-image'; + + $keys[] = '_yoast_wpseo_meta-robots-noindex'; + $keys[] = '_yoast_wpseo_meta-robots-nofollow'; + $keys[] = '_yoast_wpseo_meta-robots-adv'; + } + + $taxonomies = get_taxonomies( + array( + 'hierarchical' => true, + 'public' => true, + ) + ); + + $sync_taxonomies = PLL()->sync->taxonomies->get_taxonomies_to_copy( $sync, $from, $to ); + + $taxonomies = array_intersect( $taxonomies, $sync_taxonomies ); + + foreach ( $taxonomies as $taxonomy ) { + $keys[] = '_yoast_wpseo_primary_' . $taxonomy; + } + + return $keys; + } + + /** + * Translate the primary term during the synchronization process + * + * @since 2.3.3 + * + * @param int $value Meta value. + * @param string $key Meta key. + * @param string $lang Language of target. + * @return int + */ + public function translate_post_meta( $value, $key, $lang ) { + if ( 0 !== strpos( $key, '_yoast_wpseo_primary_' ) ) { + return $value; + } + + $taxonomy = str_replace( '_yoast_wpseo_primary_', '', $key ); + if ( ! PLL()->model->is_translated_taxonomy( $taxonomy ) ) { + return $value; + } + + return pll_get_term( $value, $lang ); + } + + /** + * Adds the yoast translatable metas to export. + * + * @param array $metas An array of post metas (keyed with meta keys) to export. + * @return array The modified array of post metas to export. + */ + public function export_post_metas( $metas ) { + $metas_to_export = array_fill_keys( $this->get_translatable_meta_keys(), 1 ); + + return array_merge( $metas, $metas_to_export ); + } + + /** + * Returns the meta keys with translatable text. + * + * @since 3.3 + * + * @return string[] + */ + protected function get_translatable_meta_keys() { + return array( + '_yoast_wpseo_title', + '_yoast_wpseo_metadesc', + '_yoast_wpseo_bctitle', + '_yoast_wpseo_focuskw', + '_yoast_wpseo_opengraph-title', + '_yoast_wpseo_opengraph-description', + '_yoast_wpseo_twitter-title', + '_yoast_wpseo_twitter-description', + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/load.php new file mode 100644 index 000000000..68d54841c --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/load.php @@ -0,0 +1,20 @@ +yarpp = new PLL_Yarpp(), 'init' ) ); + } + }, + 0 +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/yarpp.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/yarpp.php new file mode 100644 index 000000000..11e66d688 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/integrations/yarpp/yarpp.php @@ -0,0 +1,20 @@ +yarpp_support = 1; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/admin.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/admin.js new file mode 100644 index 000000000..80997feb8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/admin.js @@ -0,0 +1,426 @@ +/** + * @package Polylang + */ + +jQuery( + function( $ ) { + + // languages list table + // accessibility to row actions on focus + // mainly copy paste of WP code from common.js + var transitionTimeout; + $( 'table.languages' ).on( + { // restricted to languages list table + focusin: function() { + clearTimeout( transitionTimeout ); + var focusedRowActions = $( this ).find( '.row-actions' ); + // transitionTimeout is necessary for Firefox, but Chrome won't remove the CSS class without a little help. + $( '.row-actions' ).not( this ).removeClass( 'visible' ); + focusedRowActions.addClass( 'visible' ); + }, + focusout: function() { + // Tabbing between post title and .row-actions links needs a brief pause, otherwise + // the .row-actions div gets hidden in transit in some browsers ( ahem, Firefox ). + transitionTimeout = setTimeout( + function() { + focusedRowActions.removeClass( 'visible' ); + }, + 30 + ); + } + }, + 'tr' + ); // acts on the whole tr instead of single td as we have actions links in several columns + + /** + * Common functions and variables for overriding languages and flags dropdown list by a jQuery UI selectmenu widget. + */ + + // Add a boolean variable to be able to check jQuery UI >= 1.12 which is introduced in WP 5.6. + // Backward compatibility WP < 5.6 + var isJqueryUImin112 = $.ui.version >= '1.12.0'; + // Allow to check if a flag list dropdown is present. Not present in the Wizard steps or other settings page. + var flagListExist = $( "#flag_list" ).length; + // Allow to check if a language list dropdown is present. Not present in other settings page. + var langListExist = $( "#lang_list" ).length; + // jQuery UI selectmenu widget width option + var defaultSelectmenuWidth = '95%'; + var wizardSelectmenuWidth = '100%'; + + // Inject flag image when jQuery UI selectmenu is created or an item is selected. + // jQuery UI 1.12 introduce a wrapper inside de li tag which is necessary to selectmenu widget to work correctly. + // Mainly copy from the original jQuery UI 1.12 selectmenu widget _renderItem method. + // Note this code works fine with jQuery UI 1.11.4 too. + var selectmenuRenderItem = function( ul, item ) { + var li = $( '
  • ' ); + var wrapper = $( '
    '); + + if ( item.disabled ) { + this._addClass( li, null, "ui-state-disabled" ); + } + this._setText( wrapper, item.label ); + + // Add the flag from the data attribute in the selected element. + wrapper.prepend( $( item.element ).data( 'flag-html' ) ); + wrapper.children( 'img' ).addClass( 'ui-icon' ); + + return li.append( wrapper ).appendTo( ul ); + }; + // Override selected item to inject flag for jQuery UI less than 1.12. + var selectmenuRefreshButtonText = function( selectElement ) { + var buttonText = $( selectElement ).selectmenu( 'instance' ).buttonText; + buttonText.prepend( $( selectElement ).children( ':selected' ).data( 'flag-html' ) ); + buttonText.children( 'img' ).addClass( 'ui-icon' ); + }; + // Override selected item since jQuery UI 1.12 which introduces extension point method _renderButtonItem. + // @see https://api.jqueryui.com/1.12/selectmenu/#method-_renderButtonItem _renderButtonItem documentation. + var selectmenuRenderButtonItem = function ( selectElement ) { + var buttonItem = $( '' ); + this._setText( buttonItem, selectElement.label ); + this._addClass( buttonItem, "ui-selectmenu-text" ); + + // Add the flag from the data attribute in the selected element. + buttonItem.prepend( $( selectElement.element ).data( 'flag-html' ) ); + buttonItem.children( 'img' ).addClass( 'ui-icon' ); + + return buttonItem; + } + + /** + * Initialize a jQuery UI selectmenu widget on a DOM element + * + * @param {*} element - The jQuery object representing the DOM element to attach the widget with. + * @param {*} config - All the parameters - options and callbacks - necessary to configure the jQuery UI selectmenu widget. + * @return {Object} - The jQuery UI selectmenu widget object instance. + */ + function initializeSelectmenuWidget( element, config ) { + // Create the jQuery UI selectmenu widget for flags list dropdown and return its instance. + var selectmenuWidgetInstance = element.selectmenu( config ).selectmenu( 'instance' ); + // Overrides each item in the jQuery UI selectmenu list by injecting flag image. + selectmenuWidgetInstance._renderItem = selectmenuRenderItem; + // Override the selected item rendering for jQuery UI 1.12 + if ( isJqueryUImin112 ) { + selectmenuWidgetInstance._renderButtonItem = selectmenuRenderButtonItem; + // Need to refresh to take in account the new button item rendering method after the selectmenu widget instanciaion. + selectmenuWidgetInstance.refresh(); + } + return selectmenuWidgetInstance + } + /** + * Selectmenu widget common parameters for its configuration: options and callbacks. + */ + + // Selectmenu widget options + var selectmenuOptions = { + width: defaultSelectmenuWidth, + classes: { + 'ui-selectmenu-menu': 'pll-selectmenu-menu', + 'ui-selectmenu-button': 'pll-selectmenu-button', + } + }; + + // Selectmenu widget callbacks + var selectmenuFlagListCallbacks = {}; + // Callbacks when Selectmenu widget create or select event is triggered. + var createSelectCallback = function( event, ui ) { + selectmenuRefreshButtonText( event.target ); + } + + /** + * Overrides the flag dropdown list with our customized jquery ui selectmenu. + */ + + // Callbacks when Selectmenu widget change or open event is triggered. + // Needed to correctly refresh the selected element in the list when editing an existing language or when the value change is triggered by the language choice. + // jQuery UI 1.11 callback version. + var changeOpenCallback = function( event, ui ){ + selectmenuRefreshButtonText( $( event.target ).selectmenu( 'refresh' ) ); + } + // jQueryUI 1.12 callback version. + var changeOpenCallbackjQueryUI112 = function( event, ui ){ + // Just a refresh of the menu is needed with jQuery UI 1.12 because _renderButtonItem is triggered and then inject correctly the flag. + $( event.target ).selectmenu( 'refresh' ); + } + // There is no need of create and select callbacks with jQuery UI 1.12 because overriding _renderButtonItem method do the job. + if ( isJqueryUImin112 ) { + selectmenuFlagListCallbacks = + { + change: changeOpenCallbackjQueryUI112, + open: changeOpenCallbackjQueryUI112, + }; + } else { + selectmenuFlagListCallbacks = { + create: createSelectCallback, + select: createSelectCallback, + change: changeOpenCallback, + open: changeOpenCallback, + }; + } + + // Create the selectmenu widget only if the field is present. + if ( flagListExist ) { + // Create the jQuery UI selectmenu widget for flags list dropdown and return its instance. + var selectmenuFlagList = initializeSelectmenuWidget( $( '#flag_list' ), Object.assign( {}, selectmenuOptions, selectmenuFlagListCallbacks ) ); + $( '#lang_list' ).on( + 'languageChanged', + function( event, flag ) { + // Refresh the flag field + selectmenuFlagList.element.val( flag ); + selectmenuFlagList._trigger( 'change' ); + } + ); + } + + /** + * Language choice in predefined languages in Polylang Languages settings page and wizard. + * Overrides the predefined language dropdown list with our customized jQuery ui selectmenu widget. + */ + + /** + * Fill the other language form fields from the language element selected in the language list dropdown. + * + * @param {Object} language - language object of the selected element in the language list dropdown. + */ + function fillLanguageFields( language ) { + $( '#lang_slug' ).val( language.slug ); + $( '#lang_locale' ).val( language.locale ); + $( 'input[name="rtl"]' ).val( language.rtl ); + $( '#lang_name' ).val( language.name ); + } + + /** + * Parse selected language element in the language list dropdown. + * + * @param {object} event - jQuery triggered event. + * @return {object} The language object with its named properties. + */ + function parseSelectedLanguage( event ) { + var selectedElement = $('option:selected', event.target); + var values = selectedElement.val().split(':') + return { + slug: values[0], + locale: values[1], + rtl: [values[2]], + flag: values[3], + name: selectedElement.text().split(' - ')[0] // At the moment there is no need of the 2nd part because it corresponds on the locale which is already known by splitting the selected element value + }; + } + + // Callback when selectmenu widget change event is triggered. + var changeCallback = function( event, ui ) { + var language = parseSelectedLanguage( event ); + + fillLanguageFields( language ); + + $( event.target ).trigger( 'languageChanged', language.flag ); + }; + + // Create the jQuery UI selectmenu widget languages list dropdown and return its instance. + var selectmenuLangListCallbacks = {}; + // For the wizard we need a 100% width. So we override the previous defined value of selectmenuOptions. + if( $( '#lang_list' ).closest( '.pll-wizard-content' ).length > 0 ) { + selectmenuOptions = Object.assign( selectmenuOptions, { width: wizardSelectmenuWidth } ); + } + + // There is no need of create and select callbacks with jQuery UI 1.12 because overrinding _renderButtonItem method do the job. + if ( isJqueryUImin112 ) { + selectmenuLangListCallbacks = { + change: changeCallback, + }; + } else { + selectmenuLangListCallbacks = { + create: createSelectCallback, + select: createSelectCallback, + change: changeCallback, + }; + } + if ( langListExist ) { + initializeSelectmenuWidget( $( '#lang_list' ), Object.assign( {}, selectmenuOptions, selectmenuLangListCallbacks ) ); + } + + // strings translations + // save translations when pressing enter + $( '.translation input' ).on( + 'keydown', + function( event ){ + if ( 'Enter' === event.key ) { + event.preventDefault(); + $( '#submit' ).trigger( 'click' ); + } + } + ); + + // settings page + // click on configure link + $( '#the-list' ).on( + 'click', + '.configure>a', + function(){ + $( '.pll-configure' ).hide().prev().show(); + $( this ).closest( 'tr' ).hide().next().show(); + return false; + } + ); + + // cancel + $( '#the-list' ).on( + 'click', + '.cancel', + function(){ + $( this ).closest( 'tr' ).hide().prev().show(); + } + ); + + // save settings + $( '#the-list' ).on( + 'click', + '.save', + function(){ + var tr = $( this ).closest( 'tr' ); + var parts = tr.attr( 'id' ).split( '-' ); + + var data = { + action: 'pll_save_options', + pll_ajax_settings: true, + module: parts[parts.length - 1], + _pll_nonce: $( '#_pll_nonce' ).val() + }; + + data = tr.find( ':input' ).serialize() + '&' + $.param( data ); + + $.post( + ajaxurl, + data, + function( response ) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function() { + /** + * Fires after saving the settings, before applying changes to the DOM. + * + * @since 3.6.0 + * + * @param {Object} response The response from the AJAX call. + * @param {HTMLElement} tr The HTML element containing the fields. + */ + wp.hooks.doAction( 'pll_settings_saved', this, tr.get( 0 ) ); + + switch ( this.what ) { + case 'license-update': + $( '#pll-license-' + this.data ).replaceWith( this.supplemental.html ); + break; + case 'success': + tr.hide().prev().show(); // close only if there is no error + case 'error': + $( '.settings-error' ).remove(); // remove previous messages if any + $( 'h1' ).after( this.data ); + + // Make notices dismissible + // copy paste of common.js from WP 4.2.2 + $( '.notice.is-dismissible' ).each( + function() { + var $this = $( this ), + $button = $( '' ), + btnText = pll_admin.dismiss_notice || ''; + + // Ensure plain text + $button.find( '.screen-reader-text' ).text( btnText ); + + // Whitelist because of how the button is built. See above + $this.append( $button ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + $button.on( + 'click.wp-dismiss-notice', + function( event ) { + event.preventDefault(); + $this.fadeTo( + 100, + 0, + function() { + $( this ).slideUp( + 100, + function() { + $( this ).remove(); + } + ); + } + ); + } + ); + } + ); + break; + } + } + ); + } + ); + } + ); + + // act when pressing enter or esc in configurations + $( '.pll-configure' ).on( + 'keydown', + function( event ){ + if ( 'Enter' === event.key ) { + event.preventDefault(); + $( this ).find( '.save' ).trigger( 'click' ); + } + + if ( 'Escape' === event.key ) { + event.preventDefault(); + $( this ).find( '.cancel' ).trigger( 'click' ); + } + } + ); + + // settings URL modifications + // manages visibility of fields + $( "input[name='force_lang']" ).on( + 'change', + function() { + function pll_toggle( a, test ) { + test ? a.show() : a.hide(); + } + + var value = $( this ).val(); + pll_toggle( $( '#pll-domains-table' ), 3 == value ); + pll_toggle( $( "#pll-hide-default" ), 3 > value ); + pll_toggle( $( "#pll-rewrite" ), 2 > value ); + pll_toggle( $( "#pll-redirect-lang" ), 2 > value ); + } + ); + + // settings license + // deactivate button + $( '.pll-deactivate-license' ).on( + 'click', + function() { + var data = { + action: 'pll_deactivate_license', + pll_ajax_settings: true, + id: $( this ).attr( 'id' ), + _pll_nonce: $( '#_pll_nonce' ).val() + }; + $.post( + ajaxurl, + data, + function( response ){ + $( '#pll-license-' + response.id ).replaceWith( response.html ); + } + ); + } + ); + + // Manage closing the metabox. + // close postboxes that should be closed + $( '.if-js-closed' ).removeClass( 'if-js-closed' ).addClass( 'closed' ); + // postboxes setup + if ( 'undefined' !== typeof postboxes ) { + postboxes.add_postbox_toggles( pagenow ); + } + } +); + diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/block-editor.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/block-editor.js new file mode 100644 index 000000000..550069e06 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/block-editor.js @@ -0,0 +1,238 @@ +/** + * @package Polylang + */ + +import { + initializeLanguageOldValue, + initializeConfirmationModal +} from './lib/confirmation-modal'; + +import { + initMetaboxAutoComplete, +} from './lib/metabox-autocomplete'; + +import filterPathMiddleware from './lib/filter-path-middleware'; + +/** + * Filter REST API requests to add the language in the request + * + * @since 2.5 + */ +wp.apiFetch.use( + function ( options, next ) { + /* + * If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes. + * If `filteredRoutes` is not defined, return early. + */ + if ( 'undefined' !== typeof options.url || 'undefined' === typeof pllFilteredRoutes ) { + return next( options ); + } + + return next( filterPathMiddleware( options, pllFilteredRoutes, addLanguageParameter ) ); + } +); + +/** + * Gets the language of the currently edited post, fallback to default language if none is found. + * + * @since 2.5 + * + * @return {Element.value} + */ +function getCurrentLanguage() { + const lang = document.querySelector( '[name=post_lang_choice]' ); + + if ( null === lang ) { + return pllDefaultLanguage; + } + + return lang.value; +} + +/** + * Adds language parameter according to the current one (query string for GET, body for PUT and POST). + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @returns {APIFetchOptions} + */ +function addLanguageParameter( options ) { + if ( 'undefined' === typeof options.data || null === options.data ) { + // GET + options.path += ( ( options.path.indexOf( '?' ) >= 0 ) ? '&lang=' : '?lang=' ) + getCurrentLanguage(); + } else { + // PUT, POST + options.data.lang = getCurrentLanguage(); + } + + return options; +} + +/** + * Handles internals of the metabox: + * Language select, autocomplete input field. + * + * @since 1.5 + * + * Save post after lang choice is done and redirect to the same page for refreshing all the data. + * + * @since 2.5 + * + * Link post saving after refreshing the metabox. + * + * @since 3.0 + */ +jQuery( + function ( $ ) { + // Initialize current language to be able to compare if it changes. + initializeLanguageOldValue(); + + + // Ajax for changing the post's language in the languages metabox + $( '.post_lang_choice' ).on( + 'change', + function ( event ) { + const { select, dispatch, subscribe } = wp.data; + const emptyPost = isEmptyPost(); + const { addQueryArgs } = wp.url; + + // Initialize the confirmation dialog box. + const confirmationModal = initializeConfirmationModal(); + const { dialogContainer : dialog } = confirmationModal; + let { dialogResult } = confirmationModal; + const selectedOption = event.target; // The selected option in the dropdown list. + + // Specific case for empty posts. + // Place at the beginning because window.location change triggers automatically page reloading. + if ( location.pathname.match( /post-new.php/gi ) && emptyPost ) { + reloadPageForEmptyPost( selectedOption.value ); + } + + // Otherwise send an ajax request to refresh the legacy metabox and set the post language with the new language. + // It needs a confirmation of the user before changing the language. + // Need to wait the ajax response before triggering the block editor post save action. + if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! emptyPost ) { + dialog.dialog( 'open' ); + } else { + // Update the old language with the new one to be able to compare it in the next change. + // Because the page isn't reloaded in this case. + initializeLanguageOldValue(); + dialogResult = Promise.resolve(); + } + + dialogResult.then( + () => { + let data = { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + action: 'post_lang_choice', + lang: selectedOption.value, + post_type: $( '#post_type' ).val(), + post_id: $( '#post_ID' ).val(), + _pll_nonce: $( '#_pll_nonce' ).val() + } + + // Update post language in database as soon as possible. + // Because, in addition of the block editor save process, the legacy metabox uses a post.php process to update the language and is too late compared to the page reload. + $.post( + ajaxurl, + data, + function () { + blockEditorSavePostAndReloadPage(); + } + ); + }, + () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button. + ); + + function isEmptyPost() { + const editor = select( 'core/editor' ); + + return ! editor.getEditedPostAttribute( 'title' )?.trim() && ! editor.getEditedPostContent() && ! editor.getEditedPostAttribute( 'excerpt' )?.trim(); + } + + /** + * Reload the block editor page for empty posts. + * + * @param {string} lang The target language code. + */ + function reloadPageForEmptyPost( lang ) { + // Change the new_lang parameter with the new language value for reloading the page + // WPCS location.search is never written in the page, just used to reload page with the right value of new_lang + // new_lang input is controlled server side in PHP. The value come from the dropdown list of language returned and escaped server side. + // Notice that window.location changing triggers automatically page reloading. + if ( -1 != location.search.indexOf( 'new_lang' ) ) { + // use regexp non capturing group to replace new_lang parameter no matter where it is and capture other parameters which can be behind it + window.location.search = window.location.search.replace( /(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + lang + '$1$2' ); // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment + } else { + window.location.search = window.location.search + ( ( -1 != window.location.search.indexOf( '?' ) ) ? '&' : '?' ) + 'new_lang=' + lang; // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment + } + }; + + /** + * Triggers block editor post save and reload the block editor page when everything is ok. + */ + function blockEditorSavePostAndReloadPage() { + + let unsubscribe = null; + const previousPost = select( 'core/editor').getCurrentPost(); + + // Listen if the savePost is completely done by subscribing to its events. + const savePostIsDone = new Promise( + function ( resolve, reject ) { + unsubscribe = subscribe( + function () { + const post = select( 'core/editor').getCurrentPost(); + const { id, status, type } = post; + const error = select( 'core' ) + .getLastEntitySaveError( + 'postType', + type, + id + ); + + if ( error ) { + reject(); + } + + if ( previousPost.modified !== post.modified ) { + + if ( location.pathname.match( /post-new.php/gi ) && status !== 'auto-draft' && id ) { + window.history.replaceState( + { id }, + 'Post ' + id, + addQueryArgs( 'post.php', { post: id, action: 'edit' } ) + ); + } + resolve(); + } + } + ); + } + ); + + // Triggers the post save. + dispatch( 'core/editor' ).savePost(); + + // Process + savePostIsDone.then( + function () { + // If the post is well saved, we can reload the page + window.location.reload(); + }, + function () { + // If the post save failed + unsubscribe(); + } + ).catch( + function () { + // If an exception is thrown + unsubscribe(); + } + ); + }; + } + ); + + initMetaboxAutoComplete(); + } +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/classic-editor.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/classic-editor.js new file mode 100644 index 000000000..480843a39 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/classic-editor.js @@ -0,0 +1,308 @@ +/** + * @package Polylang + */ + +import { + initializeLanguageOldValue, + initializeConfirmationModal +} from './lib/confirmation-modal'; + +import { + initMetaboxAutoComplete, +} from './lib/metabox-autocomplete'; + +// tag suggest in metabox +jQuery( + function ( $ ) { + $.ajaxPrefilter( + function ( options, originalOptions, jqXHR ) { + var lang = $( '.post_lang_choice' ).val(); + if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && lang ) { + options.data = 'lang=' + lang + '&' + options.data; + } + } + ); + } +); + +// overrides tagBox.get +jQuery( + function ( $ ) { + // overrides function to add the language + tagBox.get = function ( id ) { + var tax = id.substr( id.indexOf( '-' ) + 1 ); + + // add the language in the $_POST variable + var data = { + action: 'get-tagcloud', + lang: $( '.post_lang_choice' ).val(), + tax: tax + } + + $.post( + ajaxurl, + data, + function ( r, stat ) { + if ( 0 == r || 'success' != stat ) { + r = wpAjax.broken; + } + + // @see code from WordPress core https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/js/tags-box.js#L291 + // @see wp_generate_tag_cloud function which generate the escaped HTML https://github.com/WordPress/WordPress/blob/a02b5cc2a8eecb8e076fbb7cf4de7bd2ec8a8eb1/wp-includes/category-template.php#L966-L975 + r = $( '
    ' ).addClass( 'the-tagcloud' ).attr( 'id', 'tagcloud-' + tax ).html( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + $( 'a', r ).on( + 'click', + function () { + tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this ); + return false; + } + ); + + var tagCloud = $( '#tagcloud-' + tax ); + // add an if else condition to allow modifying the tags outputted when switching the language + var v = tagCloud.css( 'display' ); + if ( v ) { + // See the comment above when r variable is created. + $( '#tagcloud-' + tax ).replaceWith( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith + $( '#tagcloud-' + tax ).css( 'display', v ); + } + else { + // See the comment above when r variable is created. + $( '#' + id ).after( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + } + } + ); + } + } +); + +jQuery( + function ( $ ) { + // collect taxonomies - code partly copied from WordPress + var taxonomies = new Array(); + $( '.categorydiv' ).each( + function () { + var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy; + + taxonomyParts = this_id.split( '-' ); + taxonomyParts.shift(); + taxonomy = taxonomyParts.join( '-' ); + taxonomies.push( taxonomy ); // store the taxonomy for future use + + // add our hidden field in the new category form - for each hierarchical taxonomy + // to set the language when creating a new category + // html code inserted come from html code itself. + $( '#' + taxonomy + '-add-submit' ).before( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.before + $( '' ).attr( 'type', 'hidden' ) + .attr( 'id', taxonomy + '-lang' ) + .attr( 'name', 'term_lang_choice' ) + .attr( 'value', $( '.post_lang_choice' ).val() ) + ); + } + ); + + // Initialize current language to be able to compare if it changes. + initializeLanguageOldValue(); + + // ajax for changing the post's language in the languages metabox + $( '.post_lang_choice' ).on( + 'change', + function ( event ) { + // Initialize the confirmation dialog box. + const confirmationModal = initializeConfirmationModal(); + const { dialogContainer: dialog } = confirmationModal; + let { dialogResult } = confirmationModal; + // The selected option in the dropdown list. + const selectedOption = event.target; + + if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! isEmptyPost() ) { + dialog.dialog( 'open' ); + } else { + dialogResult = Promise.resolve(); + } + + // phpcs:disable PEAR.Functions.FunctionCallSignature.EmptyLine + dialogResult.then( + () => { + var lang = selectedOption.options[selectedOption.options.selectedIndex].lang; // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + var data = { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + action: 'post_lang_choice', + lang: selectedOption.value, + post_type: $( '#post_type' ).val(), + taxonomies: taxonomies, + post_id: $( '#post_ID' ).val(), + _pll_nonce: $( '#_pll_nonce' ).val() + } + + $.post( + ajaxurl, + data, + function ( response ) { + // Target a non existing WP HTML id to avoid a conflict with WP ajax requests. + var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' ); + $.each( + res.responses, + function () { + switch ( this.what ) { + case 'translations': // translations fields + // Data is built and come from server side and is well escaped when necessary + $( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + initMetaboxAutoComplete(); + break; + case 'taxonomy': // categories metabox for posts + var tax = this.data; + // @see wp_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L175 + // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/class-walker-category-checklist.php#L89-L111 + $( '#' + tax + 'checklist' ).html( this.supplemental.all ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // @see wp_popular_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L236 + $( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // @see wp_dropdown_categories https://github.com/WordPress/WordPress/blob/5.5.1/wp-includes/category-template.php#L336 + // which is called by PLL_Admin_Classic_Editor::post_lang_choice to generate supplemental.dropdown + $( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith + $( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field + break; + case 'pages': // parent dropdown list for pages + // @see wp_dropdown_pages https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/post-template.php#L1186-L1208 + // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/class-walker-page-dropdown.php#L88 + $( '#parent_id' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + break; + case 'flag': // flag in front of the select dropdown + // Data is built and come from server side and is well escaped when necessary + $( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + break; + case 'permalink': // Sample permalink + var div = $( '#edit-slug-box' ); + if ( '-1' != this.data && div.children().length ) { + // @see get_sample_permalink_html https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/post.php#L1425-L1454 + div.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + break; + } + } + ); + + // Update the old language with the new one to be able to compare it in the next changing. + initializeLanguageOldValue(); + // modifies the language in the tag cloud + $( '.tagcloud-link' ).each( + function () { + var id = $( this ).attr( 'id' ); + tagBox.get( id ); + } + ); + + // Modifies the text direction + $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir ); + $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir ); + $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir ); + + pll.media.resetAllAttachmentsCollections(); + } + ) + }, + () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button. + ); + // phpcs:enable PEAR.Functions.FunctionCallSignature.EmptyLine + + function isEmptyPost() { + const title = $( 'input#title' ).val(); + const content = $( 'textarea#content' ).val(); + const excerpt = $( 'textarea#excerpt' ).val(); + + return ! title && ! content && ! excerpt; + } + } + ); + + initMetaboxAutoComplete(); + } +); + +/** + * @since 3.0 + * + * @namespace pll + */ +var pll = window.pll || {}; + +/** + * @since 3.0 + * + * @namespace pll.media + */ +_.extend( pll, { media: {} } ); + +/** + * @since 3.0 + * + * @alias pll.media + * @memberOf pll + * @namespace + */ +var media = _.extend( + pll.media, /** @lends pll.media.prototype */ + { + /** + * TODO: Find a way to delete references to Attachments collections that are not used anywhere else. + * + * @type {wp.media.model.Attachments} + */ + attachmentsCollections : [], + + /** + * Imitates { @see wp.media.query } but log all Attachments collections created. + * + * @param {Object} [props] + * @return {wp.media.model.Attachments} + */ + query: function ( props ) { + var attachments = pll.media.query.delegate( props ); + + pll.media.attachmentsCollections.push( attachments ); + + return attachments; + }, + + resetAllAttachmentsCollections: function () { + this.attachmentsCollections.forEach( + function ( attachmentsCollection ) { + /** + * First reset the { @see wp.media.model.Attachments } collection. + * Then, if it is mirroring a { @see wp.media.model.Query } collection, + * refresh this one too, so it will fetch new data from the server, + * and then the wp.media.model.Attachments collection will synchronize with the new data. + */ + attachmentsCollection.reset(); + if (attachmentsCollection.mirroring) { + attachmentsCollection.mirroring._hasMore = true; + attachmentsCollection.mirroring.reset(); + } + } + ); + } + } +); + +if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.media ) { + + /** + * @since 3.0 + * + * @memberOf pll.media + */ + media.query = _.extend( + media.query, /** @lends pll.media.query prototype */ + { + /** + * @type Function References WordPress { @see wp.media.query } constructor + */ + delegate: wp.media.query + } + ) + + // Substitute WordPress media query shortcut with our decorated function. + wp.media.query = media.query + +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js new file mode 100644 index 000000000..c0200e240 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/confirmation-modal.js @@ -0,0 +1,99 @@ +/** + * @package Polylang + */ + +const languagesList = jQuery( '.post_lang_choice' ); + +// Dialog box for alerting the user about a risky changing. +export const initializeConfirmationModal = () => { + // We can't use underscore or lodash in this common code because it depends of the context classic or block editor. + // Classic editor underscore is loaded, Block editor lodash is loaded. + const { __ } = wp.i18n; + + // Create dialog container. + const dialogContainer = jQuery( + '
    ', + { + id: 'pll-dialog', + style: 'display:none;' + } + ).text( __( 'Are you sure you want to change the language of the current content?', 'polylang' ) ); + + // Put it after languages list dropdown. + // PHPCS ignore dialogContainer is a new safe HTML code generated above. + languagesList.after( dialogContainer ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after + + const dialogResult = new Promise( + ( confirm, cancel ) => { + const confirmDialog = ( what ) => { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + switch ( what ) { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + case 'yes': + // Confirm the new language. + languagesList.data( 'old-value', languagesList.children( ':selected' ).first().val() ); + confirm(); + break; + case 'no': + // Revert to the old language. + languagesList.val( languagesList.data( 'old-value' ) ); + cancel( 'Cancel' ); + break; + } + dialogContainer.dialog( 'close' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + } // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent + + // Initialize dialog box in the case a language is selected but not added in the list. + const dialogOptions = { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: __( 'Change language', 'polylang' ), + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( jQuery( 'body' ).hasClass( 'rtl' ) ) { + jQuery( this ).parent().css( + { + right: jQuery( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + }, + close: function ( event, ui ) { + // When we're closing the dialog box we need to cancel the language change as we click on Cancel button. + confirmDialog( 'no' ); + }, + buttons: [ + { + text: __( 'OK', 'polylang' ), + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: __( 'Cancel', 'polylang' ), + click: function ( event ) { + confirmDialog( 'no' ); + } + } + ] + }; + + if ( jQuery.ui.version >= '1.12.0' ) { + Object.assign( dialogOptions, { classes: { 'ui-dialog': 'pll-confirmation-modal' } } ); + } else { + Object.assign( dialogOptions, { dialogClass: 'pll-confirmation-modal' } ); // jQuery UI 1.11.4 - WP < 5.6 + } + + dialogContainer.dialog( dialogOptions ); + } + ); + return { dialogContainer, dialogResult }; +} + +export const initializeLanguageOldValue = () => { + // Keep the old language value to be able to compare to the new one and revert to it if necessary. + languagesList.attr( 'data-old-value', languagesList.children( ':selected' ).first().val() ); +}; diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/filter-path-middleware.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/filter-path-middleware.js new file mode 100644 index 000000000..b15b458a8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/filter-path-middleware.js @@ -0,0 +1,22 @@ +/** + * @package Polylang + */ + +/** + * Filters requests for translatable entities. + * This logic is shared across all Polylang plugins. + * + * @since 3.5 + * + * @param {APIFetchOptions} options + * @param {Array} filteredRoutes + * @param {CallableFunction} filter + * @returns {APIFetchOptions} + */ +const filterPathMiddleware = ( options, filteredRoutes, filter ) => { + const cleanPath = options.path.split( '?' )[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'. + + return Object.values( filteredRoutes ).find( ( path ) => cleanPath === path ) ? filter( options ) : options; +} + +export default filterPathMiddleware; diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js new file mode 100644 index 000000000..600fd84de --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/lib/metabox-autocomplete.js @@ -0,0 +1,41 @@ +/** + * @package Polylang + */ + +// Translations autocomplete input box. +export function initMetaboxAutoComplete() { + jQuery('.tr_lang').each( + function () { + var tr_lang = jQuery(this).attr('id').substring(8); + var td = jQuery(this).parent().parent().siblings('.pll-edit-column'); + + jQuery(this).autocomplete( + { + minLength: 0, + source: ajaxurl + '?action=pll_posts_not_translated' + + '&post_language=' + jQuery('.post_lang_choice').val() + + '&translation_language=' + tr_lang + + '&post_type=' + jQuery('#post_type').val() + + '&_pll_nonce=' + jQuery('#_pll_nonce').val(), + select: function (event, ui) { + jQuery('#htr_lang_' + tr_lang).val(ui.item.id); + // ui.item.link is built and come from server side and is well escaped when necessary + td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + }, + } + ); + + // when the input box is emptied + jQuery(this).on( + 'blur', + function () { + if ( ! jQuery(this).val() ) { + jQuery('#htr_lang_' + tr_lang).val(0); + // Value is retrieved from HTML already generated server side + td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } + } + ); + } + ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/nav-menu.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/nav-menu.js new file mode 100644 index 000000000..23a17e70b --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/nav-menu.js @@ -0,0 +1,104 @@ +/** + * Handles the options in the language switcher nav menu metabox. + * + * @package Polylang + */ + +jQuery( + function ( $ ) { + $( '#update-nav-menu' ).on( + 'click', + function ( e ) { + if ( e.target && e.target.className && -1 != e.target.className.indexOf( 'item-edit' ) ) { + $( "input[value='#pll_switcher'][type=text]" ).parent().parent().parent().each( + function () { + var item = $( this ).attr( 'id' ).substring( 19 ); + $( this ).children( 'p:not( .field-move )' ).remove(); // remove default fields we don't need + + // item is a number part of id of parent menu item built by WordPress + // pll_data is built server side with i18n strings without HTML and data retrieved from post meta + // the usage of attr method is safe before append call. + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-title-' + item, + name: 'menu-item-title[' + item + ']', + value: pll_data.title + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-url-' + item, + name: 'menu-item-url[' + item + ']', + value: '#pll_switcher' + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + // a hidden field which exits only if our jQuery code has been executed + h = $( '' ).attr( + { + type: 'hidden', + id: 'edit-menu-item-pll-detect-' + item, + name: 'menu-item-pll-detect[' + item + ']', + value: 1 + } + ); + $( this ).append( h ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + + ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // reverse order + + // add the fields + for ( var i = 0, idsLength = ids.length; i < idsLength; i++ ) { + p = $( '

    ' ).attr( 'class', 'description' ); + // p is hardcoded just above by using attr method which is safe. + $( this ).prepend( p ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + // item is a number part of id of parent menu item built by WordPress + // pll_data is built server side with i18n strings without HTML + label = $( '

    ' ).text( lang[1] ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + td.append( desc ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + } + ); + + td.append( '
    ' ); + // Whitelist because description come from html code generated by WordPress + td.append( span ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + } +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/widgets.js b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/widgets.js new file mode 100644 index 000000000..6b9337669 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/js/src/widgets.js @@ -0,0 +1,151 @@ +/** + * Adds a flag to the widgets filtered by a language. + * + * @package Polylang + */ + +jQuery( + function ( $ ) { + var widgets_container, + widgets_selector, + flags, + isBlockEditor = 'undefined' !== typeof wp.blockEditor; + + if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) { + flags = pll_widgets.flags; + } + + /** + * Prepend widget titles with a flag once a language is selected. + * + * @param {object} widget The widget element. + * @return {void} Nothing. + */ + function add_flag( widget ) { + if ( ! flags ) { + return; + } + widget = $( widget ); + var title = isBlockEditor ? widget.prev('h3') : $( '.widget-top .widget-title h3', widget ), + locale = $( '.pll-lang-choice option:selected', widget ).val(), + // Icon is HTML built and come from server side and is well escaped when necessary + icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null; + + if ( icon ) { + icon += '   '; + var current = $( '.pll-lang', title ); + if ( current.length ) { + current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + } else { + flag = $( '' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html + // See the comment above about the icon which is safe. So it is also safe to prepend flag which uses icon. + title.prepend( flag ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + } + } else { + $( '.pll-lang', title ).remove(); + } + } + + if ( isBlockEditor ) { + + widgets_container = $( '.edit-widgets-main-block-list' ); + widgets_selector = '.widget'; + + // Update flags when we click on the legacy widget to display its form. + widgets_container.on( + 'click', + '.wp-block-legacy-widget', + function () { + add_flag( $( this ).find( '.widget' ) ); + } + ); + + } else { + if ( 'undefined' !== typeof wp.customize ) { + + widgets_container = $( '#customize-controls' ); + widgets_selector = '.customize-control .widget'; + + /** + * WP Customizer add control listener. + * + * @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading + * + * @param {object} control The control type. + * @return {void} Nothing. + */ + function customize_add_flag( control ) { + if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) { + return; + } + + /* + * Make sure the widget's contents are embedded; normally this is done + * when the control is expanded, for DOM performance reasons. + */ + control.embedWidgetContent(); + + // Now we know for sure the widget is fully embedded. + add_flag( control.container.find( '.widget' ) ); + } + wp.customize.control.each( customize_add_flag ); + wp.customize.control.bind( 'add', customize_add_flag ); + + } else { + + widgets_container = $( '#widgets-right' ); + widgets_selector = '.widget'; + + } + + // Add flags on load. + $( widgets_selector, widgets_container ).each( + function () { + add_flag( this ); + } + ); + } + + // Update flags. + widgets_container.on( + 'change', + '.pll-lang-choice', + function () { + add_flag( $( this ).parents( '.widget' ) ); + } + ); + + function pll_toggle( a, test ) { + test ? a.show() : a.hide(); + } + + // Remove all options if dropdown is checked. + $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on( + 'change', + '.pll-dropdown', + function () { + var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' ); + pll_toggle( $( '.no-dropdown-' + this_id ), true != $( this ).prop( 'checked' ) ); + } + ); + + // Disallow unchecking both show names and show flags. + var options = ['-show_flags', '-show_names']; + $.each( + options, + function ( i, v ) { + $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on( + 'change', + '.pll' + v, + function () { + var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' ); + if ( true != $( this ).prop( 'checked' ) ) { + $( '#widget-' + this_id + options[ 1 - i ] ).prop( 'checked', true ); + } + } + ); + } + ); + + } +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/load.php new file mode 100644 index 000000000..ea9e04fbf --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/load.php @@ -0,0 +1,18 @@ +model->has_languages() ) { + add_filter( + 'pll_settings_modules', + function ( $modules ) { + $modules[] = 'PLL_Settings_Preview_Machine_Translation'; + return $modules; + } + ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/settings-preview-machine-translation.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/settings-preview-machine-translation.php new file mode 100644 index 000000000..96514330d --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/machine-translation/settings-preview-machine-translation.php @@ -0,0 +1,46 @@ + 'machine_translation', + 'title' => __( 'Machine Translation', 'polylang' ), + 'description' => __( 'Allows linkage to DeepL Translate.', 'polylang' ), + 'active_option' => 'preview', + ); + + parent::__construct( $polylang, array_merge( $default, $args ) ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/load.php new file mode 100644 index 000000000..771939c6f --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/load.php @@ -0,0 +1,20 @@ +model->has_languages() ) { + add_filter( + 'pll_settings_modules', + function ( $modules ) { + $modules[] = 'PLL_Settings_Preview_Share_Slug'; + return $modules; + } + ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/settings-preview-share-slug.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/settings-preview-share-slug.php new file mode 100644 index 000000000..17f691377 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/share-slug/settings-preview-share-slug.php @@ -0,0 +1,56 @@ + 'share-slugs', + 'title' => __( 'Share slugs', 'polylang' ), + 'description' => $this->get_description(), + 'active_option' => 'preview', + ); + + parent::__construct( $polylang, array_merge( $default, $args ) ); + } + + /** + * Returns the module description. + * + * @since 3.1 + * + * @return string + */ + protected function get_description() { + return __( 'Allows to share the same URL slug across languages for posts and terms.', 'polylang' ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/admin-site-health.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/admin-site-health.php new file mode 100644 index 000000000..c71d93f67 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/admin-site-health.php @@ -0,0 +1,520 @@ +model = &$polylang->model; + $this->static_pages = &$polylang->static_pages; + + // Information tab. + add_filter( 'debug_information', array( $this, 'info_options' ), 15 ); + add_filter( 'debug_information', array( $this, 'info_languages' ), 15 ); + add_filter( 'debug_information', array( $this, 'info' ), 15 ); + + // Tests Tab. + add_filter( 'site_status_tests', array( $this, 'status_tests' ) ); + add_filter( 'site_status_test_php_modules', array( $this, 'site_status_test_php_modules' ) ); // Require simplexml in Site health. + } + + /** + * Returns a list of keys to exclude from the site health information. + * + * @since 2.8 + * + * @return string[] List of option keys to ignore. + */ + protected function exclude_options_keys() { + return array( + 'uninstall', + 'first_activation', + ); + } + + /** + * Returns a list of keys to exclude from the site health information. + * + * @since 2.8 + * + * @return string[] List of language keys to ignore. + */ + protected function exclude_language_keys() { + return array( + 'flag', + 'host', + 'taxonomy', + 'description', + 'parent', + 'filter', + 'custom_flag', + ); + } + + /** + * Formats an array to display in options information. + * + * @since 2.8 + * + * @param array $array An array of formatted data. + * @return string + */ + protected function format_array( $array ) { + array_walk( + $array, + function ( &$value, $key ) { + if ( is_array( $value ) ) { + $ids = implode( ' , ', $value ); + $value = "$key => $ids"; + } else { + $value = "$key => $value"; + } + } + ); + return implode( ' | ', $array ); + } + + /** + * Transforms the option value to readable human sentence. + * + * @since 3.3 + * + * @param string $key Option name. + * @param mixed $value Option value. + * @return mixed Option value. + */ + public function format_value( $key, $value ) { + switch ( $key ) { + case 'browser': + if ( ! $value ) { + $value = '0: ' . esc_html__( 'Detect browser language deactivated', 'polylang' ); + break; + } + $value = '1: ' . esc_html__( 'Detect browser language activated', 'polylang' ); + break; + case 'rewrite': + if ( $value ) { + $value = '1: ' . esc_html__( 'Remove /language/ in pretty permalinks', 'polylang' ); + break; + } + $value = '0: ' . esc_html__( 'Keep /language/ in pretty permalinks', 'polylang' ); + break; + case 'hide_default': + if ( $value ) { + $value = '1: ' . esc_html__( 'Hide URL language information for default language', 'polylang' ); + break; + } + $value = '0: ' . esc_html__( 'Display URL language information for default language', 'polylang' ); + break; + case 'force_lang': + switch ( $value ) { + case '0': + $value = '0: ' . esc_html__( 'The language is set from content', 'polylang' ); + break; + case '1': + $value = '1: ' . esc_html__( 'The language is set from the directory name in pretty permalinks', 'polylang' ); + break; + case '2': + $value = '2: ' . esc_html__( 'The language is set from the subdomain name in pretty permalinks', 'polylang' ); + break; + case '3': + $value = '3: ' . esc_html__( 'The language is set from different domains', 'polylang' ); + break; + } + break; + case 'redirect_lang': + if ( $value ) { + $value = '1: ' . esc_html__( 'The front page URL contains the language code instead of the page name or page id', 'polylang' ); + break; + } + $value = '0: ' . esc_html__( 'The front page URL contains the page name or page id instead of the language code', 'polylang' ); + + break; + case 'media_support': + if ( ! $value ) { + $value = '0: ' . esc_html__( 'The media are not translated', 'polylang' ); + break; + } + $value = '1: ' . esc_html__( 'The media are translated', 'polylang' ); + break; + + case 'sync': + if ( empty( $value ) ) { + $value = '0: ' . esc_html__( 'Synchronization disabled', 'polylang' ); + } + break; + } + + return $value; + } + + /** + * Add Polylang Options to Site Health Information tab. + * + * @since 2.8 + * + * @param array $debug_info The debug information to be added to the core information page. + * @return array + */ + public function info_options( $debug_info ) { + $fields = array(); + + foreach ( $this->model->options as $key => $value ) { + if ( in_array( $key, $this->exclude_options_keys() ) ) { + continue; + } + + $value = $this->format_value( $key, $value ); + + switch ( $key ) { + case 'domains': + if ( 3 === $this->model->options['force_lang'] ) { + $value = is_array( $value ) ? $value : array(); + $value = $this->format_array( $value ); + + $fields[ $key ]['label'] = $key; + $fields[ $key ]['value'] = $value; + } + break; + + case 'nav_menus': + $current_theme = get_stylesheet(); + if ( is_array( $value ) && isset( $value[ $current_theme ] ) ) { + foreach ( $value[ $current_theme ] as $location => $lang ) { + $lang = is_array( $lang ) ? $lang : array(); + + $fields[ $location ]['label'] = sprintf( 'menu: %s', $location ); + $fields[ $location ]['value'] = $this->format_array( $lang ); + } + } + break; + + case 'media': + $value = is_array( $value ) ? $value : array(); + foreach ( $value as $sub_key => $sub_value ) { + $fields[ "$key-$sub_key" ]['label'] = "$key $sub_key"; + $fields[ "$key-$sub_key" ]['value'] = $sub_value; + } + break; + + case 'post_types': + $fields[ $key ]['label'] = $key; + $fields[ $key ]['value'] = implode( ', ', $this->model->get_translated_post_types() ); + break; + + case 'taxonomies': + $fields[ $key ]['label'] = $key; + $fields[ $key ]['value'] = implode( ', ', $this->model->get_translated_taxonomies() ); + break; + + default: + $fields[ $key ]['label'] = $key; + $fields[ $key ]['value'] = empty( $value ) ? '0' : $value; + break; + } + } + + $debug_info['pll_options'] = array( + /* translators: placeholder is the plugin name */ + 'label' => sprintf( __( '%s options', 'polylang' ), POLYLANG ), + 'fields' => $fields, + ); + + return $debug_info; + } + + /** + * Adds Polylang Languages settings to Site Health Information tab. + * + * @since 2.8 + * + * @param array $debug_info The debug information to be added to the core information page. + * @return array + */ + public function info_languages( $debug_info ) { + foreach ( $this->model->get_languages_list() as $language ) { + $fields = array(); + + foreach ( $language->to_array() as $key => $value ) { + if ( in_array( $key, $this->exclude_language_keys(), true ) ) { + continue; + } + + if ( empty( $value ) ) { + $value = '0'; + } + + $fields[ $key ]['label'] = $key; + + if ( 'term_props' === $key && is_array( $value ) ) { + $fields[ $key ]['value'] = $this->get_info_term_props( $value ); + } else { + $fields[ $key ]['value'] = $value; + } + + if ( 'term_group' === $key ) { + $fields[ $key ]['label'] = 'order'; // Changed for readability but not translated as other keys are not. + } + } + + $debug_info[ 'pll_language_' . $language->slug ] = array( + /* translators: placeholder is the language name */ + 'label' => sprintf( __( 'Language: %s', 'polylang' ), $language->name ), + /* translators: placeholder is the flag image */ + 'description' => sprintf( esc_html__( 'Flag used in the language switcher: %s', 'polylang' ), $this->get_flag( $language ) ), + 'fields' => $fields, + ); + } + + return $debug_info; + } + + /** + * Adds term props data to the info languages array. + * + * @since 3.4 + * + * @param array $value The term props data. + * @return array The term props data formatted for the info languages tab. + */ + protected function get_info_term_props( $value ) { + $return_value = array(); + + foreach ( $value as $language_taxonomy => $item ) { + $language_taxonomy_array = array_fill( 0, count( $item ), $language_taxonomy ); + + $keys_with_language_taxonomy = array_map( + function ( $key, $language_taxonomy ) { + return "{$language_taxonomy}/{$key}"; + }, + array_keys( $item ), + $language_taxonomy_array + ); + + $value = array_combine( $keys_with_language_taxonomy, $item ); + if ( is_array( $value ) ) { + $return_value = array_merge( $return_value, $value ); + } + } + return $return_value; + } + + /** + * Returns the flag used in the language switcher. + * + * @since 2.8 + * + * @param PLL_Language $language Language object. + * @return string + */ + protected function get_flag( $language ) { + $flag = $language->get_display_flag(); + return empty( $flag ) ? '' . esc_html__( 'Undefined', 'polylang' ) . '' : $flag; + } + + /** + * Add a Site Health test on homepage translation. + * + * @since 2.8 + * + * @param array $tests Array with tests declaration data. + * @return array + */ + public function status_tests( $tests ) { + // Add the test only if the homepage displays static page. + if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) { + $tests['direct']['pll_homepage'] = array( + 'label' => esc_html__( 'Homepage translated', 'polylang' ), + 'test' => array( $this, 'homepage_test' ), + ); + } + return $tests; + } + + /** + * Test if the home page is translated or not. + * + * @since 2.8 + * + * @return array $result Array with test results. + */ + public function homepage_test() { + $result = array( + 'label' => esc_html__( 'All languages have a translated homepage', 'polylang' ), + 'status' => 'good', + 'badge' => array( + 'label' => POLYLANG, + 'color' => 'blue', + ), + 'description' => sprintf( + '

    %s

    ', + esc_html__( 'It is mandatory to translate the static front page in all languages.', 'polylang' ) + ), + 'actions' => '', + 'test' => 'pll_homepage', + ); + + $message = $this->static_pages->get_must_translate_message(); + + if ( ! empty( $message ) ) { + $result['status'] = 'critical'; + $result['label'] = esc_html__( 'The homepage is not translated in all languages', 'polylang' ); + $result['description'] = sprintf( '

    %s

    ', $message ); + } + return $result; + } + + /** + * Add Polylang Warnings to Site Health Information tab. + * + * @since 3.1 + * + * @param array $debug_info The debug information to be added to the core information page. + * @return array + */ + public function info( $debug_info ) { + $fields = array(); + + // Add Post Types without languages. + $posts_no_lang = $this->get_post_ids_without_lang(); + + if ( ! empty( $posts_no_lang ) ) { + $fields['post-no-lang']['label'] = __( 'Posts without language', 'polylang' ); + $fields['post-no-lang']['value'] = $this->format_array( $posts_no_lang ); + } + + $terms_no_lang = $this->get_term_ids_without_lang(); + + if ( ! empty( $terms_no_lang ) ) { + $fields['term-no-lang']['label'] = __( 'Terms without language', 'polylang' ); + $fields['term-no-lang']['value'] = $this->format_array( $terms_no_lang ); + } + + // Add WPML files. + $wpml_files = PLL_WPML_Config::instance()->get_files(); + if ( ! empty( $wpml_files ) ) { + $fields['wpml']['label'] = 'wpml-config.xml files'; + $fields['wpml']['value'] = $wpml_files; + + if ( ! extension_loaded( 'simplexml' ) ) { + $fields['simplexml']['label'] = __( 'PHP SimpleXML extension', 'polylang' ); + $fields['simplexml']['value'] = __( 'Not loaded. Contact your host provider.', 'polylang' ); + } + } + + // Create the section. + if ( ! empty( $fields ) ) { + $debug_info['pll_warnings'] = array( + /* translators: placeholder is the plugin name */ + 'label' => sprintf( __( '%s information', 'polylang' ), POLYLANG ), + 'fields' => $fields, + ); + } + + return $debug_info; + } + + /** + * Get an array with post_type as key and post ids as value. + * + * @since 3.1 + * + * @param int $limit Max number of posts to show per post type. `-1` to return all of them. Default is 5. + * @return int[][] Array containing an array of post ids. + * + * @phpstan-param -1|positive-int $limit + */ + public function get_post_ids_without_lang( $limit = 5 ) { + $posts = array(); + + foreach ( $this->model->get_translated_post_types() as $post_type ) { + $post_ids_with_no_language = $this->model->get_posts_with_no_lang( $post_type, $limit ); + + if ( ! empty( $post_ids_with_no_language ) ) { + foreach ( $post_ids_with_no_language as $id ) { + $posts[ $post_type ][] = $id; + } + } + } + + return $posts; + } + + /** + * Get an array with taxonomy as key and term ids as value. + * + * @since 3.1 + * + * @param int $limit Max number of terms to show per post type. `-1` to return all of them. Default is 5. + * @return int[][] Array containing an array of term ids. + * + * @phpstan-param -1|positive-int $limit + */ + public function get_term_ids_without_lang( $limit = 5 ) { + $terms = array(); + + foreach ( $this->model->get_translated_taxonomies() as $taxonomy ) { + $term_ids_with_no_language = $this->model->get_terms_with_no_lang( $taxonomy, $limit ); + + if ( ! empty( $term_ids_with_no_language ) ) { + foreach ( $term_ids_with_no_language as $id ) { + $terms[ $taxonomy ][] = $id; + } + } + } + + return $terms; + } + + /** + * Requires the simplexml PHP module when a wpml-config.xml has been found. + * + * @since 3.1 + * @since 3.2 Moved from PLL_WPML_Config + * + * @param array $modules An associative array of modules to test for. + * @return array + */ + public function site_status_test_php_modules( $modules ) { + $files = PLL_WPML_Config::instance()->get_files(); + if ( ! empty( $files ) ) { + $modules['simplexml'] = array( + 'extension' => 'simplexml', + 'required' => true, + ); + } + return $modules; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/load.php new file mode 100644 index 000000000..09edf1f2a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/site-health/load.php @@ -0,0 +1,14 @@ +model->has_languages() ) { + $polylang->site_health = new PLL_Admin_Site_Health( $polylang ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/abstract-sitemaps.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/abstract-sitemaps.php new file mode 100644 index 000000000..a74e60e38 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/abstract-sitemaps.php @@ -0,0 +1,37 @@ + 'class-wp-sitemaps-posts' ); + return $whitelist; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/load.php new file mode 100644 index 000000000..9185676aa --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/load.php @@ -0,0 +1,17 @@ +model->has_languages() ) { + if ( $polylang->links_model instanceof PLL_Links_Abstract_Domain ) { + $polylang->sitemaps = new PLL_Sitemaps_Domain( $polylang ); + } else { + $polylang->sitemaps = new PLL_Sitemaps( $polylang ); + } + $polylang->sitemaps->init(); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/multilingual-sitemaps-provider.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/multilingual-sitemaps-provider.php new file mode 100644 index 000000000..535adc79c --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/multilingual-sitemaps-provider.php @@ -0,0 +1,218 @@ +name = $provider->name; + $this->object_type = $provider->object_type; + + $this->provider = $provider; + $this->links_model = &$links_model; + $this->model = &$links_model->model; + } + + /** + * Gets a URL list for a sitemap. + * + * @since 2.8 + * + * @param int $page_num Page of results. + * @param string $object_subtype Optional. Object subtype name. Default empty. + * @return array Array of URLs for a sitemap. + */ + public function get_url_list( $page_num, $object_subtype = '' ) { + return $this->provider->get_url_list( $page_num, $object_subtype ); + } + + /** + * Gets the max number of pages available for the object type. + * + * @since 2.8 + * + * @param string $object_subtype Optional. Object subtype. Default empty. + * @return int Total number of pages. + */ + public function get_max_num_pages( $object_subtype = '' ) { + return $this->provider->get_max_num_pages( $object_subtype ); + } + + /** + * Filters the query arguments to add the language. + * + * @since 2.8 + * + * @param array $args Sitemap provider WP_Query or WP_Term_Query arguments. + * @return array + */ + public static function query_args( $args ) { + if ( ! empty( self::$filter_lang ) ) { + $args['lang'] = self::$filter_lang; + } + return $args; + } + + /** + * Gets data for a given sitemap type. + * + * @since 2.8 + * + * @param string $object_subtype_name Object subtype name if any. + * @param string $lang Optional language name. + * @return array + */ + protected function get_sitemap_data( $object_subtype_name, $lang = '' ) { + $object_subtype_name = (string) $object_subtype_name; + + if ( ! empty( $lang ) ) { + self::$filter_lang = $lang; + } + + $return = array( + 'name' => implode( '-', array_filter( array( $object_subtype_name, $lang ) ) ), + 'pages' => $this->get_max_num_pages( $object_subtype_name ), + ); + + self::$filter_lang = ''; + return $return; + } + + /** + * Gets data about each sitemap type. + * + * @since 2.8 + * + * @return array[] Array of sitemap types including object subtype name and number of pages. + */ + public function get_sitemap_type_data() { + $sitemap_data = array(); + + add_filter( 'wp_sitemaps_posts_query_args', array( __CLASS__, 'query_args' ) ); + add_filter( 'wp_sitemaps_taxonomies_query_args', array( __CLASS__, 'query_args' ) ); + + $object_subtypes = $this->get_object_subtypes(); + + if ( empty( $object_subtypes ) ) { + foreach ( $this->model->get_languages_list( array( 'fields' => 'slug' ) ) as $language ) { + $sitemap_data[] = $this->get_sitemap_data( '', $language ); + } + } + + switch ( $this->provider->name ) { + case 'posts': + $func = array( $this->model, 'is_translated_post_type' ); + break; + case 'taxonomies': + $func = array( $this->model, 'is_translated_taxonomy' ); + break; + default: + return $sitemap_data; + } + + foreach ( array_keys( $object_subtypes ) as $object_subtype_name ) { + if ( call_user_func( $func, $object_subtype_name ) ) { + foreach ( $this->model->get_languages_list( array( 'fields' => 'slug' ) ) as $language ) { + $sitemap_data[] = $this->get_sitemap_data( $object_subtype_name, $language ); + } + } else { + $sitemap_data[] = $this->get_sitemap_data( $object_subtype_name ); + } + } + + return $sitemap_data; + } + + /** + * Gets the URL of a sitemap entry. + * + * @since 2.8 + * + * @param string $name The name of the sitemap. + * @param int $page The page of the sitemap. + * @return string The composed URL for a sitemap entry. + */ + public function get_sitemap_url( $name, $page ) { + // Check if a language was added in $name. + $pattern = '#(' . implode( '|', $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) . ')$#'; + if ( preg_match( $pattern, $name, $matches ) ) { + $lang = $this->model->get_language( $matches[1] ); + + if ( ! empty( $lang ) ) { + $name = preg_replace( '#(-?' . $lang->slug . ')$#', '', $name ); + $url = $this->provider->get_sitemap_url( $name, $page ); + return $this->links_model->add_language_to_link( $url, $lang ); + } + } + + // If no language is present in $name, we may attempt to get the current sitemap url (e.g. in redirect_canonical() ). + if ( get_query_var( 'lang' ) ) { + $lang = $this->model->get_language( get_query_var( 'lang' ) ); + $url = $this->provider->get_sitemap_url( $name, $page ); + return $this->links_model->add_language_to_link( $url, $lang ); + } + + return $this->provider->get_sitemap_url( $name, $page ); + } + + /** + * Returns the list of supported object subtypes exposed by the provider. + * + * @since 2.8 + * + * @return array List of object subtypes objects keyed by their name. + */ + public function get_object_subtypes() { + return $this->provider->get_object_subtypes(); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps-domain.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps-domain.php new file mode 100644 index 000000000..62945471d --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps-domain.php @@ -0,0 +1,71 @@ +links_model = &$polylang->links_model; + } + + /** + * Setups actions and filters. + * + * @since 3.0 + * + * @return void + */ + public function init() { + parent::init(); + + add_filter( 'wp_sitemaps_index_entry', array( $this, 'index_entry' ) ); + add_filter( 'wp_sitemaps_stylesheet_url', array( $this->links_model, 'site_url' ) ); + add_filter( 'wp_sitemaps_stylesheet_index_url', array( $this->links_model, 'site_url' ) ); + add_filter( 'home_url', array( $this, 'sitemap_url' ) ); + } + + /** + * Filters the sitemap index entries for subdomains and multiple domains. + * + * @since 2.8 + * + * @param array $sitemap_entry Sitemap entry for the post. + * @return array + */ + public function index_entry( $sitemap_entry ) { + $sitemap_entry['loc'] = $this->links_model->site_url( $sitemap_entry['loc'] ); + return $sitemap_entry; + } + + /** + * Makes sure that the sitemap urls are always evaluated on the current domain. + * + * @since 2.8.4 + * + * @param string $url A sitemap url. + * @return string + */ + public function sitemap_url( $url ) { + if ( false !== strpos( $url, '/wp-sitemap' ) ) { + $url = $this->links_model->site_url( $url ); + } + return $url; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps.php new file mode 100644 index 000000000..799f61497 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sitemaps/sitemaps.php @@ -0,0 +1,128 @@ +links_model = &$polylang->links_model; + $this->model = &$polylang->model; + $this->options = &$polylang->options; + } + + /** + * Setups actions and filters. + * + * @since 2.8 + * + * @return void + */ + public function init() { + parent::init(); + + add_filter( 'pll_set_language_from_query', array( $this, 'set_language_from_query' ), 10, 2 ); + add_filter( 'rewrite_rules_array', array( $this, 'rewrite_rules' ) ); + add_filter( 'wp_sitemaps_add_provider', array( $this, 'replace_provider' ) ); + } + + /** + * Assigns the current language to the default language when the sitemap url + * doesn't include any language. + * + * @since 2.8 + * + * @param string|bool $lang Current language code, false if not set yet. + * @param WP_Query $query Main WP query object. + * @return string|bool + */ + public function set_language_from_query( $lang, $query ) { + if ( isset( $query->query['sitemap'] ) && empty( $query->query['lang'] ) ) { + $lang = $this->options['default_lang']; + } + return $lang; + } + + /** + * Filters the sitemaps rewrite rules to take the languages into account. + * + * @since 2.8 + * + * @param string[] $rules Rewrite rules. + * @return string[] Modified rewrite rules. + */ + public function rewrite_rules( $rules ) { + global $wp_rewrite; + + $languages = $this->model->get_languages_list( + array( + 'fields' => 'slug', + 'hide_default' => $this->options['hide_default'], + ) + ); + + if ( empty( $languages ) ) { + return $rules; + } + + $slug = $wp_rewrite->root . ( $this->options['rewrite'] ? '^' : '^language/' ) . '(' . implode( '|', $languages ) . ')/'; + + $newrules = array(); + + foreach ( $rules as $key => $rule ) { + if ( false !== strpos( $rule, 'sitemap=$matches[1]' ) ) { + $newrules[ str_replace( '^wp-sitemap', $slug . 'wp-sitemap', $key ) ] = str_replace( + array( '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]', '?' ), + array( '[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '?lang=$matches[1]&' ), + $rule + ); // Should be enough! + } + + $newrules[ $key ] = $rule; + } + return $newrules; + } + + /** + * Replaces a sitemap provider by our decorator. + * + * @since 2.8 + * + * @param WP_Sitemaps_Provider $provider Instance of a WP_Sitemaps_Provider. + * @return WP_Sitemaps_Provider + */ + public function replace_provider( $provider ) { + if ( $provider instanceof WP_Sitemaps_Provider ) { + $provider = new PLL_Multilingual_Sitemaps_Provider( $provider, $this->links_model ); + } + return $provider; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/admin-sync.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/admin-sync.php new file mode 100644 index 000000000..5d55e3284 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/admin-sync.php @@ -0,0 +1,233 @@ +model->post->get_translation( $id, sanitize_key( $_GET['new_lang'] ) ) ) { + $post_parent = $parent; + } + } + return $post_parent; + } + + /** + * Copy menu order, comment, ping status and optionally the date when creating a new translation + * + * @since 2.5 + * + * @param array $data An array of slashed post data. + * @return array + */ + public function wp_insert_post_data( $data ) { + if ( isset( $GLOBALS['pagenow'], $_GET['from_post'], $_GET['new_lang'] ) && 'post-new.php' === $GLOBALS['pagenow'] && $this->model->is_translated_post_type( $data['post_type'] ) ) { + check_admin_referer( 'new-post-translation' ); + + $from_post_id = (int) $_GET['from_post']; + $from_post = get_post( $from_post_id ); + + if ( $from_post instanceof WP_Post ) { + foreach ( array( 'menu_order', 'comment_status', 'ping_status' ) as $property ) { + $data[ $property ] = $from_post->$property; + } + + // Copy the date only if the synchronization is activated + if ( in_array( 'post_date', $this->options['sync'] ) ) { + $data['post_date'] = $from_post->post_date; + $data['post_date_gmt'] = $from_post->post_date_gmt; + } + } + } + + return $data; + } + + /** + * Copy post metas, and taxonomies when using "Add new" ( translation ) + * + * @since 2.5 + * @since 3.1 Use of use_block_editor_for_post filter instead of rest_api_init which is triggered too early in WP 5.8. + * + * @param bool $is_block_editor Whether the post can be edited or not. + * @return bool + */ + public function new_post_translation( $is_block_editor ) { + global $post; + static $done = array(); + + if ( ! empty( $post ) && isset( $GLOBALS['pagenow'], $_GET['from_post'], $_GET['new_lang'] ) && 'post-new.php' === $GLOBALS['pagenow'] && $this->model->is_translated_post_type( $post->post_type ) ) { + check_admin_referer( 'new-post-translation' ); + + // Capability check already done in post-new.php + $from_post_id = (int) $_GET['from_post']; + $lang = $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); + + if ( ! $from_post_id || ! $lang || ! empty( $done[ $from_post_id ] ) ) { + return $is_block_editor; + } + + $done[ $from_post_id ] = true; // Avoid a second duplication in the block editor. Using an array only to allow multiple phpunit tests. + + $this->taxonomies->copy( $from_post_id, $post->ID, $lang->slug ); + $this->post_metas->copy( $from_post_id, $post->ID, $lang->slug ); + + if ( is_sticky( $from_post_id ) ) { + stick_post( $post->ID ); + } + } + + return $is_block_editor; + } + + /** + * Get post fields to synchronize. + * + * @since 2.4 + * + * @param WP_Post $post Post object. + * @return array Fields to synchronize. + */ + protected function get_fields_to_sync( $post ) { + global $wpdb; + + $postarr = parent::get_fields_to_sync( $post ); + + // For new drafts, save the date now otherwise it is overridden by WP. Thanks to JoryHogeveen. See #32. + if ( in_array( 'post_date', $this->options['sync'] ) && isset( $GLOBALS['pagenow'], $_GET['from_post'], $_GET['new_lang'] ) && 'post-new.php' === $GLOBALS['pagenow'] ) { + check_admin_referer( 'new-post-translation' ); + + unset( $postarr['post_date'] ); + unset( $postarr['post_date_gmt'] ); + + $original = get_post( (int) $_GET['from_post'] ); + + if ( $original instanceof WP_Post ) { + $wpdb->update( + $wpdb->posts, + array( + 'post_date' => $original->post_date, + 'post_date_gmt' => $original->post_date_gmt, + ), + array( 'ID' => $post->ID ) + ); + } + } + + if ( isset( $GLOBALS['post_type'] ) ) { + $post_type = $GLOBALS['post_type']; + } elseif ( isset( $_REQUEST['post_type'] ) ) { + $post_type = sanitize_key( $_REQUEST['post_type'] ); // 2nd case for quick edit + } + + // Make sure not to impact media translations when creating them at the same time as post + if ( in_array( 'post_parent', $this->options['sync'] ) && ( ! isset( $post_type ) || $post_type !== $post->post_type ) ) { + unset( $postarr['post_parent'] ); + } + + return $postarr; + } + + /** + * Synchronizes post fields in translations. + * + * @since 1.2 + * + * @param int $post_id Post id. + * @param WP_Post $post Post object. + * @param int[] $translations Post translations. + */ + public function pll_save_post( $post_id, $post, $translations ) { + parent::pll_save_post( $post_id, $post, $translations ); + + // Sticky posts + if ( in_array( 'sticky_posts', $this->options['sync'] ) ) { + $stickies = get_option( 'sticky_posts' ); + if ( isset( $_REQUEST['sticky'] ) && 'sticky' === $_REQUEST['sticky'] ) { // phpcs:ignore WordPress.Security.NonceVerification + $stickies = array_merge( $stickies, array_values( $translations ) ); + } else { + $stickies = array_diff( $stickies, array_values( $translations ) ); + } + update_option( 'sticky_posts', array_unique( $stickies ) ); + } + } + + /** + * Some backward compatibility with Polylang < 2.3 + * allows to call PLL()->sync->copy_post_metas() and PLL()->sync->copy_taxonomies() + * used for example in Polylang for WooCommerce + * the compatibility is however only partial as the 4th argument $sync is lost + * + * @since 2.3 + * + * @param string $func Function name + * @param array $args Function arguments + * @return mixed|void + */ + public function __call( $func, $args ) { + $obj = substr( $func, 5 ); + + if ( is_object( $this->$obj ) && method_exists( $this->$obj, 'copy' ) ) { + if ( WP_DEBUG ) { + $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions + $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func + + trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions + sprintf( + '%1$s was called incorrectly in %3$s on line %4$s: the call to PLL()->sync->%1$s() has been deprecated in Polylang 2.3, use PLL()->sync->%2$s->copy() instead.' . "\nError handler", + esc_html( $func ), + esc_html( $obj ), + esc_html( $debug[ $i ]['file'] ), + absint( $debug[ $i ]['line'] ) + ) + ); + } + return call_user_func_array( array( $this->$obj, 'copy' ), $args ); + } + + $debug = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions + trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions + sprintf( + 'Call to undefined function PLL()->sync->%1$s() in %2$s on line %3$s' . "\nError handler", + esc_html( $func ), + esc_html( $debug[0]['file'] ), + absint( $debug[0]['line'] ) + ), + E_USER_ERROR + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/load.php new file mode 100644 index 000000000..6978cd6f8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/load.php @@ -0,0 +1,26 @@ +model->has_languages() ) { + if ( $polylang instanceof PLL_Admin_Base ) { + $polylang->sync = new PLL_Admin_Sync( $polylang ); + } else { + $polylang->sync = new PLL_Sync( $polylang ); + } + + add_filter( + 'pll_settings_modules', + function ( $modules ) { + $modules[] = 'PLL_Settings_Sync'; + return $modules; + } + ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/settings-sync.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/settings-sync.php new file mode 100644 index 000000000..4f0028569 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/settings-sync.php @@ -0,0 +1,115 @@ + 'sync', + 'title' => __( 'Synchronization', 'polylang' ), + 'description' => __( 'The synchronization options allow to maintain exact same values (or translations in the case of taxonomies and page parent) of meta content between the translations of a post or page.', 'polylang' ), + ) + ); + } + + /** + * Deactivates the module + * + * @since 1.8 + */ + public function deactivate() { + $this->options['sync'] = array(); + update_option( 'polylang', $this->options ); + } + + /** + * Displays the settings form + * + * @since 1.8 + */ + protected function form() { + ?> +
      + $str ) { + printf( + '
    • ', + esc_attr( $key ), + checked( in_array( $key, $this->options['sync'] ), true, false ), + esc_html( $str ) + ); + } + ?> +
    + empty( $options['sync'] ) ? array() : array_keys( $options['sync'], 1 ) ); + return $newoptions; // Take care to return only validated options. + } + + /** + * Get the row actions. + * + * @since 1.8 + * + * @return string[] Row actions. + */ + protected function get_actions() { + return empty( $this->options['sync'] ) ? array( 'configure' ) : array( 'configure', 'deactivate' ); + } + + /** + * Get the list of synchronization settings. + * + * @since 1.0 + * + * @return string[] Array synchronization options. + */ + public static function list_metas_to_sync() { + return array( + 'taxonomies' => __( 'Taxonomies', 'polylang' ), + 'post_meta' => __( 'Custom fields', 'polylang' ), + 'comment_status' => __( 'Comment status', 'polylang' ), + 'ping_status' => __( 'Ping status', 'polylang' ), + 'sticky_posts' => __( 'Sticky posts', 'polylang' ), + 'post_date' => __( 'Published date', 'polylang' ), + 'post_format' => __( 'Post format', 'polylang' ), + 'post_parent' => __( 'Page parent', 'polylang' ), + '_wp_page_template' => __( 'Page template', 'polylang' ), + 'menu_order' => __( 'Page order', 'polylang' ), + '_thumbnail_id' => __( 'Featured image', 'polylang' ), + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-metas.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-metas.php new file mode 100644 index 000000000..5a77213a4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-metas.php @@ -0,0 +1,406 @@ +model = &$polylang->model; + + add_filter( "add_{$this->meta_type}_metadata", array( $this, 'can_synchronize_metadata' ), 1, 3 ); + add_filter( "update_{$this->meta_type}_metadata", array( $this, 'can_synchronize_metadata' ), 1, 3 ); + add_filter( "delete_{$this->meta_type}_metadata", array( $this, 'can_synchronize_metadata' ), 1, 3 ); + + $this->add_all_meta_actions(); + + add_action( "pll_save_{$this->meta_type}", array( $this, 'save_object' ), 10, 3 ); + } + + /** + * Removes "added_{$this->meta_type}_meta" action + * + * @since 2.3 + * + * @return void + */ + protected function remove_add_meta_action() { + remove_action( "added_{$this->meta_type}_meta", array( $this, 'add_meta' ) ); + } + + /** + * Removes all meta synchronization actions and filters + * + * @since 2.3 + * + * @return void + */ + public function remove_all_meta_actions() { + $this->remove_add_meta_action(); + + remove_filter( "update_{$this->meta_type}_metadata", array( $this, 'update_metadata' ), 999 ); + remove_action( "update_{$this->meta_type}_meta", array( $this, 'update_meta' ) ); + + remove_action( "delete_{$this->meta_type}_meta", array( $this, 'store_metas_to_sync' ) ); + remove_action( "deleted_{$this->meta_type}_meta", array( $this, 'delete_meta' ) ); + } + + /** + * Adds "added_{$this->meta_type}_meta" action + * + * @since 2.3 + * + * @return void + */ + protected function restore_add_meta_action() { + add_action( "added_{$this->meta_type}_meta", array( $this, 'add_meta' ), 10, 4 ); + } + + /** + * Adds meta synchronization actions and filters + * + * @since 2.3 + * + * @return void + */ + public function add_all_meta_actions() { + $this->restore_add_meta_action(); + + add_filter( "update_{$this->meta_type}_metadata", array( $this, 'update_metadata' ), 999, 5 ); // Very late in case a filter prevents the meta to be updated + add_action( "update_{$this->meta_type}_meta", array( $this, 'update_meta' ), 10, 4 ); + + add_action( "delete_{$this->meta_type}_meta", array( $this, 'store_metas_to_sync' ), 10, 2 ); + add_action( "deleted_{$this->meta_type}_meta", array( $this, 'delete_meta' ), 10, 4 ); + } + + /** + * Maybe modify ("translate") a meta value when it is copied or synchronized + * + * @since 2.3 + * + * @param mixed $value Meta value + * @param string $key Meta key + * @param int $from Id of the source + * @param int $to Id of the target + * @param string $lang Language of target + * @return mixed + */ + protected function maybe_translate_value( $value, $key, $from, $to, $lang ) { + /** + * Filter a meta value before is copied or synchronized + * + * @since 2.3 + * + * @param mixed $value Meta value + * @param string $key Meta key + * @param string $lang Language of target + * @param int $from Id of the source + * @param int $to Id of the target + */ + return apply_filters( "pll_translate_{$this->meta_type}_meta", maybe_unserialize( $value ), $key, $lang, $from, $to ); + } + + /** + * Get the custom fields to copy or synchronize. + * + * @since 2.3 + * + * @param int $from Id of the post from which we copy information. + * @param int $to Id of the post to which we paste information. + * @param string $lang Language slug. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @return string[] List of meta keys. + */ + protected function get_metas_to_copy( $from, $to, $lang, $sync = false ) { + /** + * Filters the custom fields to copy or synchronize. + * + * @since 0.6 + * @since 1.9.2 The `$from`, `$to`, `$lang` parameters were added. + * + * @param string[] $keys List of custom fields names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the post from which we copy information. + * @param int $to Id of the post to which we paste information. + * @param string $lang Language slug. + */ + return array_unique( apply_filters( "pll_copy_{$this->meta_type}_metas", array(), $sync, $from, $to, $lang ) ); + } + + /** + * Disallow modifying synchronized meta if the current user can not modify translations + * + * @since 2.6 + * + * @param null|bool $check Whether to allow adding/updating/deleting metadata. + * @param int $id Object ID. + * @param string $meta_key Meta key. + * @return null|bool + */ + public function can_synchronize_metadata( $check, $id, $meta_key ) { + if ( ! $this->model->{$this->meta_type}->current_user_can_synchronize( $id ) ) { + $tr_ids = $this->model->{$this->meta_type}->get_translations( $id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + if ( $tr_id != $id ) { + $to_copy = $this->get_metas_to_copy( $id, $tr_id, $lang, true ); + if ( in_array( $meta_key, $to_copy ) ) { + return false; + } + } + } + } + return $check; + } + + /** + * Synchronize added metas across translations + * + * @since 2.3 + * + * @param int $mid Meta id. + * @param int $id Object ID. + * @param string $meta_key Meta key. + * @param mixed $meta_value Meta value. Must be serializable if non-scalar. + * @return void + */ + public function add_meta( $mid, $id, $meta_key, $meta_value ) { + static $avoid_recursion = false; + + if ( ! $avoid_recursion ) { + $avoid_recursion = true; + $tr_ids = $this->model->{$this->meta_type}->get_translations( $id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + if ( $tr_id != $id ) { + $to_copy = $this->get_metas_to_copy( $id, $tr_id, $lang, true ); + if ( in_array( $meta_key, $to_copy ) ) { + $meta_value = $this->maybe_translate_value( $meta_value, $meta_key, $id, $tr_id, $lang ); + add_metadata( $this->meta_type, $tr_id, wp_slash( $meta_key ), is_object( $meta_value ) ? $meta_value : wp_slash( $meta_value ) ); + } + } + } + + $avoid_recursion = false; + } + } + + /** + * Stores the previous value when updating metas + * + * @since 2.3 + * + * @param null|bool $r Not used + * @param int $id Object ID. + * @param string $meta_key Meta key. + * @param mixed $meta_value Meta value. Must be serializable if non-scalar. + * @param mixed $prev_value If specified, only update existing metadata entries with the specified value. + * @return null|bool Unchanged + */ + public function update_metadata( $r, $id, $meta_key, $meta_value, $prev_value ) { + if ( null === $r ) { + $hash = md5( "$id|$meta_key|" . maybe_serialize( $meta_value ) ); + $this->prev_value[ $hash ] = $prev_value; + } + return $r; + } + + /** + * Synchronize updated metas across translations + * + * @since 2.3 + * + * @param int $mid Meta id. + * @param int $id Object ID. + * @param string $meta_key Meta key. + * @param mixed $meta_value Meta value. Must be serializable if non-scalar. + * @return void + */ + public function update_meta( $mid, $id, $meta_key, $meta_value ) { + static $avoid_recursion = false; + $id = (int) $id; + + if ( ! $avoid_recursion ) { + $avoid_recursion = true; + $hash = md5( "$id|$meta_key|" . maybe_serialize( $meta_value ) ); + + $prev_meta = get_metadata_by_mid( $this->meta_type, $mid ); + + if ( $prev_meta ) { + $this->remove_add_meta_action(); // We don't want to sync back the new metas + $tr_ids = $this->model->{$this->meta_type}->get_translations( $id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + if ( $tr_id != $id && in_array( $meta_key, $this->get_metas_to_copy( $id, $tr_id, $lang, true ) ) ) { + if ( empty( $this->prev_value[ $hash ] ) || $this->prev_value[ $hash ] === $prev_meta->meta_value ) { + $prev_value = $this->maybe_translate_value( $prev_meta->meta_value, $meta_key, $id, $tr_id, $lang ); + $meta_value = $this->maybe_translate_value( $meta_value, $meta_key, $id, $tr_id, $lang ); + update_metadata( $this->meta_type, $tr_id, wp_slash( $meta_key ), is_object( $meta_value ) ? $meta_value : wp_slash( $meta_value ), $prev_value ); + } + } + } + $this->restore_add_meta_action(); + } + + unset( $this->prev_value[ $hash ] ); + $avoid_recursion = false; + } + } + + /** + * Store metas to synchronize before deleting them. + * + * @since 2.3 + * + * @param int[] $mids Not used. + * @param int $id Object ID. + * @return void + */ + public function store_metas_to_sync( $mids, $id ) { + $tr_ids = $this->model->{$this->meta_type}->get_translations( $id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + $this->to_copy[ $id ][ $tr_id ] = $this->get_metas_to_copy( $id, $tr_id, $lang, true ); + } + } + + /** + * Synchronizes deleted meta across translations. + * + * @since 2.3 + * + * @param int[] $mids Not used. + * @param int $id Object ID. + * @param string $key Meta key. + * @param mixed $value Meta value. + * @return void + */ + public function delete_meta( $mids, $id, $key, $value ) { + static $avoid_recursion = false; + + if ( ! $avoid_recursion ) { + $avoid_recursion = true; + + $tr_ids = $this->model->{$this->meta_type}->get_translations( $id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + if ( $tr_id != $id ) { + if ( in_array( $key, $this->to_copy[ $id ][ $tr_id ] ) ) { + if ( '' !== $value && null !== $value && false !== $value ) { // Same test as WP + $value = $this->maybe_translate_value( $value, $key, $id, $tr_id, $lang ); + } + delete_metadata( $this->meta_type, $tr_id, wp_slash( $key ), is_object( $value ) ? $value : wp_slash( $value ) ); + } + } + } + } + + $avoid_recursion = false; + } + + /** + * Copy or synchronize metas + * + * @since 2.3 + * + * @param int $from Id of the source object + * @param int $to Id of the target object + * @param string $lang Language code of the target object + * @param bool $sync Optional, defaults to true. True if it is synchronization, false if it is a copy + * @return void + */ + public function copy( $from, $to, $lang, $sync = false ) { + $this->remove_all_meta_actions(); + + $to_copy = $this->get_metas_to_copy( $from, $to, $lang, $sync ); + $metas = get_metadata( $this->meta_type, $from ); + $metas = is_array( $metas ) ? $metas : array(); + $tr_metas = get_metadata( $this->meta_type, $to ); + $tr_metas = is_array( $tr_metas ) ? $tr_metas : array(); + + foreach ( $to_copy as $key ) { + if ( empty( $metas[ $key ] ) ) { + if ( ! empty( $tr_metas[ $key ] ) ) { + // If the meta key is not present in the source object, delete all values + delete_metadata( $this->meta_type, $to, wp_slash( $key ) ); + } + } elseif ( ! empty( $tr_metas[ $key ] ) && 1 === count( $metas[ $key ] ) && 1 === count( $tr_metas[ $key ] ) ) { + // One custom field to update + $value = reset( $metas[ $key ] ); + $value = maybe_unserialize( $value ); + $to_value = $this->maybe_translate_value( $value, $key, $from, $to, $lang ); + update_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) ); + } else { + // Multiple custom fields, either in the source or the target + if ( ! empty( $tr_metas[ $key ] ) ) { + // The synchronization of multiple values custom fields is easier if we delete all metas first + delete_metadata( $this->meta_type, $to, wp_slash( $key ) ); + } + + foreach ( $metas[ $key ] as $value ) { + $value = maybe_unserialize( $value ); + $to_value = $this->maybe_translate_value( $value, $key, $from, $to, $lang ); + add_metadata( $this->meta_type, $to, wp_slash( $key ), is_object( $to_value ) ? $to_value : wp_slash( $to_value ) ); + } + } + } + + $this->add_all_meta_actions(); + } + + /** + * If synchronized custom fields were previously not synchronized, it is expected + * that saving a post (or term) will synchronize them. + * + * @since 2.3 + * + * @param int $object_id Id of the object being saved. + * @param object $obj Not used. + * @param int[] $translations The list of translations object ids. + * @return void + */ + public function save_object( $object_id, $obj, $translations ) { + foreach ( $translations as $tr_lang => $tr_id ) { + if ( $tr_id != $object_id ) { + $this->copy( $object_id, $tr_id, $tr_lang, true ); + } + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-post-metas.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-post-metas.php new file mode 100644 index 000000000..47c66cc97 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-post-metas.php @@ -0,0 +1,94 @@ +meta_type = 'post'; + + parent::__construct( $polylang ); + + $this->options = &$polylang->options; + + add_filter( 'pll_translate_post_meta', array( $this, 'translate_thumbnail_id' ), 10, 3 ); + } + + /** + * Get the custom fields to copy or synchronize. + * + * @since 2.3 + * + * @param int $from Id of the post from which we copy information. + * @param int $to Id of the post to which we paste information. + * @param string $lang Language slug. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @return string[] List of meta keys. + */ + protected function get_metas_to_copy( $from, $to, $lang, $sync = false ) { + $keys = array(); + + // Get public meta keys ( including from translated post in case we just deleted a custom field ). + if ( ! $sync || in_array( 'post_meta', $this->options['sync'] ) ) { + $from_keys = (array) get_post_custom_keys( $from ); + $to_keys = (array) get_post_custom_keys( $to ); + + $keys = array_unique( array_merge( $from_keys, $to_keys ) ); + foreach ( $keys as $k => $meta_key ) { + if ( is_protected_meta( $meta_key ) ) { + unset( $keys[ $k ] ); + } + } + } + + // Add page template and featured image. + foreach ( array( '_wp_page_template', '_thumbnail_id' ) as $meta ) { + if ( ! $sync || in_array( $meta, $this->options['sync'] ) ) { + $keys[] = $meta; + } + } + + if ( $this->options['media_support'] ) { + $keys[] = '_wp_attached_file'; + $keys[] = '_wp_attachment_metadata'; + $keys[] = '_wp_attachment_backup_sizes'; + $keys[] = '_wp_attachment_is_custom_header'; // Random header image. + } + + /** This filter is documented in modules/sync/sync-metas.php */ + return array_unique( apply_filters( 'pll_copy_post_metas', $keys, $sync, $from, $to, $lang ) ); + } + + /** + * Translates the thumbnail id. + * + * @since 2.3 + * + * @param int $value Thumbnail id. + * @param string $key Meta key. + * @param string $lang Language code. + * @return int + */ + public function translate_thumbnail_id( $value, $key, $lang ) { + return ( $this->options['media_support'] && '_thumbnail_id' === $key && $to_value = $this->model->post->get_translation( $value, $lang ) ) ? $to_value : $value; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-tax.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-tax.php new file mode 100644 index 000000000..4d969eb6a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-tax.php @@ -0,0 +1,310 @@ +model = &$polylang->model; + $this->options = &$polylang->options; + + add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 5 ); + add_action( 'pll_save_term', array( $this, 'create_term' ), 10, 3 ); + add_action( 'pre_delete_term', array( $this, 'pre_delete_term' ) ); + add_action( 'delete_term', array( $this, 'delete_term' ) ); + } + + /** + * Get the list of taxonomies to copy or to synchronize. + * + * @since 1.7 + * @since 2.1 The `$from`, `$to`, `$lang` parameters were added. + * @since 3.2 Changed visibility from protected to public. + * + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the post from which we copy information, optional, defaults to null. + * @param int $to Id of the post to which we paste information, optional, defaults to null. + * @param string $lang Language slug, optional, defaults to null. + * @return string[] List of taxonomy names. + */ + public function get_taxonomies_to_copy( $sync, $from = null, $to = null, $lang = null ) { + $taxonomies = ! $sync || in_array( 'taxonomies', $this->options['sync'] ) ? $this->model->get_translated_taxonomies() : array(); + if ( ! $sync || in_array( 'post_format', $this->options['sync'] ) ) { + $taxonomies[] = 'post_format'; + } + + /** + * Filters the taxonomies to copy or synchronize. + * + * @since 1.7 + * @since 2.1 The `$from`, `$to`, `$lang` parameters were added. + * + * @param string[] $taxonomies List of taxonomy names. + * @param bool $sync True if it is synchronization, false if it is a copy. + * @param int $from Id of the post from which we copy information. + * @param int $to Id of the post to which we paste information. + * @param string $lang Language slug. + */ + return array_unique( apply_filters( 'pll_copy_taxonomies', $taxonomies, $sync, $from, $to, $lang ) ); + } + + /** + * When copying or synchronizing terms, translate terms in translatable taxonomies + * + * @since 2.3 + * + * @param int $object_id Object ID. + * @param int[] $terms List of terms ids assigned to the source post. + * @param string $taxonomy Taxonomy name. + * @param string $lang Language slug. + * @return int[] List of terms ids to assign to the target post. + */ + protected function maybe_translate_terms( $object_id, $terms, $taxonomy, $lang ) { + if ( is_array( $terms ) && $this->model->is_translated_taxonomy( $taxonomy ) ) { + $newterms = array(); + + // Convert to term ids if we got tag names + $strings = array_map( 'is_string', $terms ); + if ( in_array( true, $strings, true ) ) { + $terms = get_the_terms( $object_id, $taxonomy ); + $terms = wp_list_pluck( $terms, 'term_id' ); + } + + foreach ( $terms as $term ) { + /** + * Filter the translated term when a post translation is created or synchronized + * + * @since 2.3 + * + * @param int $tr_term Translated term id + * @param int $term Source term id + * @param string $lang Language slug + */ + if ( $term_id = apply_filters( 'pll_maybe_translate_term', (int) $this->model->term->get_translation( $term, $lang ), $term, $lang ) ) { + $newterms[] = (int) $term_id; // Cast is important otherwise we get 'numeric' tags + } + } + + return $newterms; + } + + return $terms; // Empty $terms or untranslated taxonomy + } + + /** + * Maybe copy taxonomy terms from one post to the other. + * + * @since 2.6 + * + * @param int $object_id Source object ID. + * @param int $tr_id Target object ID. + * @param string $lang Target language. + * @param array $terms An array of object terms. + * @param string $taxonomy Taxonomy slug. + * @param bool $append Whether to append new terms to the old terms. + * @return void + */ + protected function copy_object_terms( $object_id, $tr_id, $lang, $terms, $taxonomy, $append ) { + $to_copy = $this->get_taxonomies_to_copy( true, $object_id, $tr_id, $lang ); + + if ( in_array( $taxonomy, $to_copy ) ) { + $newterms = $this->maybe_translate_terms( $object_id, $terms, $taxonomy, $lang ); + + // For some reasons, the user may have untranslated terms in the translation. Don't forget them. + if ( $this->model->is_translated_taxonomy( $taxonomy ) ) { + $tr_terms = get_the_terms( $tr_id, $taxonomy ); + if ( is_array( $tr_terms ) ) { + foreach ( $tr_terms as $term ) { + if ( ! $this->model->term->get_translation( $term->term_id, $this->model->post->get_language( $object_id ) ) ) { + $newterms[] = (int) $term->term_id; + } + } + } + } + + wp_set_object_terms( $tr_id, $newterms, $taxonomy, $append ); + } + } + + /** + * When assigning terms to a post, assign translated terms to the translated posts (synchronisation). + * + * @since 2.3 + * + * @param int $object_id Object ID. + * @param array $terms An array of object terms. + * @param int[] $tt_ids An array of term taxonomy IDs. + * @param string $taxonomy Taxonomy slug. + * @param bool $append Whether to append new terms to the old terms. + * @return void + */ + public function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy, $append ) { + static $avoid_recursion = false; + $taxonomy_object = get_taxonomy( $taxonomy ); + + // Make sure that the taxonomy is registered for a post type + if ( ! $avoid_recursion && ! empty( $taxonomy_object ) && array_filter( $taxonomy_object->object_type, 'post_type_exists' ) ) { + $avoid_recursion = true; + + $tr_ids = $this->model->post->get_translations( $object_id ); + + foreach ( $tr_ids as $lang => $tr_id ) { + if ( $tr_id !== $object_id ) { + if ( $this->model->post->current_user_can_synchronize( $object_id ) ) { + $this->copy_object_terms( $object_id, $tr_id, $lang, $terms, $taxonomy, $append ); + } else { + // No permission to synchronize, so let's synchronize in reverse order + $orig_lang = array_search( $object_id, $tr_ids ); + $tr_terms = get_the_terms( $tr_id, $taxonomy ); + + if ( false === $tr_terms ) { + $tr_terms = array(); + } + + if ( is_string( $orig_lang ) && is_array( $tr_terms ) ) { + $tr_terms = wp_list_pluck( $tr_terms, 'term_id' ); + $this->copy_object_terms( $tr_id, $object_id, $orig_lang, $tr_terms, $taxonomy, $append ); + } + break; + } + } + } + + $avoid_recursion = false; + } + } + + /** + * Copy terms from one post to a translation, does not sync + * + * @since 2.3 + * + * @param int $from Id of the source post + * @param int $to Id of the target post + * @param string $lang Language slug + * @return void + */ + public function copy( $from, $to, $lang ) { + remove_action( 'set_object_terms', array( $this, 'set_object_terms' ) ); + + // Get taxonomies to sync for this post type + $taxonomies = array_intersect( get_post_taxonomies( $from ), $this->get_taxonomies_to_copy( false, $from, $to, $lang ) ); + + // Update the term cache to reduce the number of queries in the loop + update_object_term_cache( array( $from ), get_post_type( $from ) ); + + // Copy + foreach ( $taxonomies as $tax ) { + if ( $terms = get_the_terms( $from, $tax ) ) { + $terms = array_map( 'intval', wp_list_pluck( $terms, 'term_id' ) ); + $newterms = $this->maybe_translate_terms( $from, $terms, $tax, $lang ); + + if ( ! empty( $newterms ) ) { + wp_set_object_terms( $to, $newterms, $tax ); + } + } + } + + add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 5 ); + } + + /** + * When creating a new term, associate it to posts having translations associated to the translated terms. + * + * @since 2.3 + * + * @param int $term_id Id of the created term. + * @param string $taxonomy Taxonomy. + * @param int[] $translations Ids of the translations of the created term. + * @return void + */ + public function create_term( $term_id, $taxonomy, $translations ) { + if ( doing_action( 'create_term' ) && in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) { + // Get all posts associated to the translated terms + $tr_posts = get_posts( + array( + 'numberposts' => -1, + 'nopaging' => true, + 'post_type' => 'any', + 'post_status' => 'any', + 'fields' => 'ids', + 'tax_query' => array( + array( + 'taxonomy' => $taxonomy, + 'field' => 'id', + 'terms' => array_merge( array( $term_id ), array_values( $translations ) ), + 'include_children' => false, + ), + ), + ) + ); + + $lang = $this->model->term->get_language( $term_id ); // Language of the created term + $posts = array(); + + foreach ( $tr_posts as $post_id ) { + $post = $this->model->post->get_translation( $post_id, $lang ); + + if ( $post ) { + $posts[] = $post; + } + } + + $posts = array_unique( $posts ); + + foreach ( $posts as $post_id ) { + if ( current_user_can( 'assign_term', $term_id ) ) { + wp_set_object_terms( $post_id, $term_id, $taxonomy, true ); + } + } + } + } + + /** + * Deactivate the synchronization of terms before deleting a term + * to avoid translated terms to be removed from translated posts + * + * @since 2.3.2 + * + * @return void + */ + public function pre_delete_term() { + remove_action( 'set_object_terms', array( $this, 'set_object_terms' ) ); + } + + /** + * Re-activate the synchronization of terms after a term is deleted + * + * @since 2.3.2 + * + * @return void + */ + public function delete_term() { + add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 5 ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-term-metas.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-term-metas.php new file mode 100644 index 000000000..e26088fad --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync-term-metas.php @@ -0,0 +1,25 @@ +meta_type = 'term'; + + parent::__construct( $polylang ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync.php new file mode 100644 index 000000000..6fe7a65ff --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/sync/sync.php @@ -0,0 +1,268 @@ +model = &$polylang->model; + $this->options = &$polylang->options; + + $this->taxonomies = new PLL_Sync_Tax( $polylang ); + $this->post_metas = new PLL_Sync_Post_Metas( $polylang ); + $this->term_metas = new PLL_Sync_Term_Metas( $polylang ); + + add_filter( 'wp_insert_post_parent', array( $this, 'can_sync_post_parent' ), 10, 3 ); + add_filter( 'wp_insert_post_data', array( $this, 'can_sync_post_data' ), 10, 2 ); + + add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 ); + add_action( 'created_term', array( $this, 'sync_term_parent' ), 10, 3 ); + add_action( 'edited_term', array( $this, 'sync_term_parent' ), 10, 3 ); + + add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 ); + + if ( $this->options['media_support'] ) { + add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 ); + add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 ); + add_action( 'edit_attachment', array( $this, 'edit_attachment' ) ); + } + + add_filter( 'pre_update_option_sticky_posts', array( $this, 'sync_sticky_posts' ), 10, 2 ); + } + + /** + * Get post fields to synchronize. + * + * @since 2.4 + * + * @param WP_Post $post Post object. + * @return array + */ + protected function get_fields_to_sync( $post ) { + $postarr = array(); + + foreach ( array( 'comment_status', 'ping_status', 'menu_order' ) as $property ) { + if ( in_array( $property, $this->options['sync'] ) ) { + $postarr[ $property ] = $post->$property; + } + } + + if ( in_array( 'post_date', $this->options['sync'] ) ) { + $postarr['post_date'] = $post->post_date; + $postarr['post_date_gmt'] = $post->post_date_gmt; + } + + if ( in_array( 'post_parent', $this->options['sync'] ) ) { + $postarr['post_parent'] = wp_get_post_parent_id( $post->ID ); + } + + return $postarr; + } + + /** + * Prevents synchronized post parent modification if the current user hasn't enough rights + * + * @since 2.6 + * + * @param int $post_parent Post parent ID + * @param int $post_id Post ID, unused + * @param array $postarr Array of parsed post data + * @return int + */ + public function can_sync_post_parent( $post_parent, $post_id, $postarr ) { + if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) { + $tr_ids = $this->model->post->get_translations( $postarr['ID'] ); + foreach ( $tr_ids as $tr_id ) { + if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) { + $post_parent = $post->post_parent; + break; + } + } + } + return $post_parent; + } + + /** + * Prevents synchronized post data modification if the current user hasn't enough rights + * + * @since 2.6 + * + * @param array $data An array of slashed post data. + * @param array $postarr An array of sanitized, but otherwise unmodified post data. + * @return array + */ + public function can_sync_post_data( $data, $postarr ) { + if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) { + foreach ( $this->model->post->get_translations( $postarr['ID'] ) as $tr_id ) { + if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) { + $to_sync = $this->get_fields_to_sync( $post ); + $data = array_merge( $data, $to_sync ); + break; + } + } + } + return $data; + } + + /** + * Synchronizes post fields in translations. + * + * @since 2.4 + * + * @param int $post_id Post id. + * @param WP_Post $post Post object. + * @param int[] $translations Post translations. + * @return void + */ + public function pll_save_post( $post_id, $post, $translations ) { + global $wpdb; + + if ( $this->model->post->current_user_can_synchronize( $post_id ) ) { + $postarr = $this->get_fields_to_sync( $post ); + + if ( ! empty( $postarr ) ) { + foreach ( $translations as $lang => $tr_id ) { + if ( ! $tr_id || $tr_id === $post_id ) { + continue; + } + + $tr_arr = $postarr; + unset( $tr_arr['post_parent'] ); + + // Do not update the translation parent if the user set a parent with no translation. + if ( isset( $postarr['post_parent'] ) ) { + $post_parent = $postarr['post_parent'] ? $this->model->post->get_translation( $postarr['post_parent'], $lang ) : 0; + if ( ! ( $postarr['post_parent'] && ! $post_parent ) ) { + $tr_arr['post_parent'] = $post_parent; + } + } + + // Update all the rows at once. + if ( ! empty( $tr_arr ) ) { + // Don't use wp_update_post to avoid infinite loop. + $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) ); + clean_post_cache( $tr_id ); + } + } + } + } + } + + /** + * Synchronize term parent in translations + * Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated + * + * @since 2.3 + * + * @param int $term_id Term id. + * @param int $tt_id Term taxonomy id, not used. + * @param string $taxonomy Taxonomy name. + * @return void + */ + public function sync_term_parent( $term_id, $tt_id, $taxonomy ) { + global $wpdb; + + if ( is_taxonomy_hierarchical( $taxonomy ) && $this->model->is_translated_taxonomy( $taxonomy ) ) { + $term = get_term( $term_id ); + + if ( $term instanceof WP_Term ) { + $translations = $this->model->term->get_translations( $term_id ); + + foreach ( $translations as $lang => $tr_id ) { + if ( $tr_id !== $term_id ) { + $tr_parent = $this->model->term->get_translation( $term->parent, $lang ); + $tr_term = get_term( (int) $tr_id, $taxonomy ); + + if ( $tr_term instanceof WP_Term && ! ( $term->parent && empty( $tr_parent ) ) ) { + $wpdb->update( + $wpdb->term_taxonomy, + array( 'parent' => $tr_parent ? $tr_parent : 0 ), + array( 'term_taxonomy_id' => $tr_term->term_taxonomy_id ) + ); + + clean_term_cache( $tr_id, $taxonomy ); // OK since WP 3.9. + } + } + } + } + } + } + + /** + * Synchronizes terms and metas in translations for media + * + * @since 1.8 + * + * @param int $post_id post id + * @return void + */ + public function edit_attachment( $post_id ) { + $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) ); + } + + /** + * Synchronize sticky posts. + * + * @since 2.3 + * + * @param int[] $value New option value. + * @param int[] $old_value Old option value. + * @return int[] + */ + public function sync_sticky_posts( $value, $old_value ) { + if ( in_array( 'sticky_posts', $this->options['sync'] ) ) { + // Stick post + if ( $sticked = array_diff( $value, $old_value ) ) { + $translations = $this->model->post->get_translations( reset( $sticked ) ); + $value = array_unique( array_merge( $value, array_values( $translations ) ) ); + } + + // Unstick post + if ( $unsticked = array_diff( $old_value, $value ) ) { + $translations = $this->model->post->get_translations( reset( $unsticked ) ); + $value = array_unique( array_diff( $value, array_values( $translations ) ) ); + } + } + + return $value; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/load.php new file mode 100644 index 000000000..0a1442336 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/load.php @@ -0,0 +1,20 @@ +model->has_languages() ) { + add_filter( + 'pll_settings_modules', + function ( $modules ) { + $modules[] = 'PLL_Settings_Preview_Translate_Slugs'; + return $modules; + } + ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/settings-preview-translate-slugs.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/settings-preview-translate-slugs.php new file mode 100644 index 000000000..a17d7415a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/translate-slugs/settings-preview-translate-slugs.php @@ -0,0 +1,56 @@ + 'translate-slugs', + 'title' => __( 'Translate slugs', 'polylang' ), + 'description' => $this->get_description(), + 'active_option' => 'preview', + ); + + parent::__construct( $polylang, array_merge( $default, $args ) ); + } + + /** + * Returns the module description. + * + * @since 3.1 + * + * @return string + */ + protected function get_description() { + return __( 'Allows to translate custom post types and taxonomies slugs in URLs.', 'polylang' ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/css/wizard.css b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/css/wizard.css new file mode 100644 index 000000000..b6c6a62a9 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/css/wizard.css @@ -0,0 +1,951 @@ +@charset "UTF-8"; +body { + margin: 65px auto 24px; + box-shadow: none; + background: #f1f1f1; + padding: 0; + border: 0; /* fix-pro #856 override WP install.css */ +} + +#pll-logo { + border: 0; + margin: 0 0 24px; + padding: 0; + text-align: center; + font-family: sans-serif; + font-size: 64px; + text-transform: uppercase; + color: #000; + line-height: normal; +} +#pll-logo a { + display: flex; + justify-content: center; + color: #000; + text-decoration: none; +} + +#pll-logo img { + max-width: 100%; + margin-right: 16px; +} +.rtl #pll-logo img { + margin-right: 0; + margin-left: 16px; +} + +.pll-wizard-footer { + text-align: center +} + +.pll-wizard .select2-container { + text-align: left; + width: auto +} + +.pll-wizard .hidden { + display: none +} + +.pll-wizard-content { + box-shadow: 0 1px 3px rgba(0, 0, 0, .13); + padding: 2em; + margin: 0 0 20px; + background: #fff; + overflow: hidden; + zoom: 1; + text-align: left; +} +.rtl .pll-wizard-content{ + text-align: right; +} + +.pll-wizard-content h1, +.pll-wizard-content h2, +.pll-wizard-content h3, +.pll-wizard-content table { + margin: 0 0 20px; + border: 0; + padding: 0; + color: #666; + clear: none; + font-weight: 500 +} + +.pll-wizard-content p { + margin: 20px 0; + font-size: 1em; + line-height: 1.75em; + color: #666 +} + +.pll-wizard-content table { + font-size: 1em; + line-height: 1.75em; + color: #666; + width: 100%; + margin-top: 20px; +} +.pll-wizard-content table td span{ + display: inline-block; +} + +.pll-wizard-content table caption { + caption-side: bottom; + font-style: italic; + text-align: right; +} +.rtl .pll-wizard-content table caption { + text-align: left; +} + +.pll-wizard-content table caption .icon-default-lang{ + font-style: normal; +} + +.pll-wizard-content a { + color: #a03f3f; +} + +.pll-wizard-content a:focus, +.pll-wizard-content a:hover, +.pll-wizard-footer-links:hover { + color: #dd5454 +} + +.pll-wizard-content .pll-wizard-next-steps { + overflow: hidden; + margin: 0 0 24px; + padding-bottom: 2px +} + +.pll-wizard-content .pll-wizard-next-steps h2 { + margin-bottom: 12px +} + +.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-first { + float: left; + width: 50%; + box-sizing: border-box +} + +.pll-wizard-content .pll-wizard-next-steps .pll-wizard-next-steps-last { + float: right; + width: 50%; + box-sizing: border-box +} + +.pll-wizard-content .pll-wizard-next-steps ul { + padding: 0 2em 0 0; + list-style: none outside; + margin: 0 +} + +.pll-wizard-content .pll-wizard-next-steps ul li a { + display: block; + padding: 0 0 .75em +} + +.pll-wizard-content .pll-wizard-next-steps ul li a::before { + color: #82878c; + font: normal 20px/1 dashicons; + speak: none; + display: inline-block; + padding: 0 10px 0 0; + top: 1px; + position: relative; + text-decoration: none!important; + vertical-align: top +} + +.pll-wizard-steps { + padding: 0 0 24px; + margin: 0; + list-style: none outside; + overflow: hidden; + color: #ccc; + width: 100%; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: inline-flex +} + +.pll-wizard-steps li { + width: 100%; + float: left; + padding: 0 0 .8em; + margin: 0; + text-align: center; + position: relative; + border-bottom: 4px solid #ccc; + line-height: 1.4em +} + +.pll-wizard-steps li a { + color: #a03f3f; + text-decoration: none; + padding: 1.5em; + margin: -1.5em; + position: relative; + z-index: 1 +} + +.pll-wizard-steps li a:focus, +.pll-wizard-steps li a:hover { + color: #dd5454; + text-decoration: underline +} + +.pll-wizard-steps li::before { + content: ""; + border: 4px solid #ccc; + border-radius: 100%; + width: 4px; + height: 4px; + position: absolute; + bottom: 0; + left: 50%; + margin-left: -6px; + margin-bottom: -8px; + background: #fff +} + +.pll-wizard-steps li.active { + border-color: #a03f3f; + color: #a03f3f; + font-weight: 700 +} + +.pll-wizard-steps li.active::before { + border-color: #a03f3f +} + +.pll-wizard-steps li.done { + border-color: #a03f3f; + color: #a03f3f +} + +.pll-wizard-steps li.done::before { + border-color: #a03f3f; + background: #a03f3f +} + +.pll-wizard .pll-wizard-actions { + overflow: hidden; + margin: 20px 0 0; + position: relative +} + +.pll-wizard .pll-wizard-actions .button { + font-size: 16px; + font-weight: 300; + padding: 1em 2em; + line-height: 1em; + margin-right: .5em; + margin-bottom: 2px; + margin-top: 10px; + height: auto; + border-radius: 4px; + box-shadow: none; + min-width: auto; + border-color: #a03f3f; + color: #a03f3f; +} + +.pll-wizard .pll-wizard-content .button { + border-color: #a03f3f; + color: #a03f3f; +} + +.pll-wizard .pll-wizard-content .button-primary, +.pll-wizard .pll-wizard-actions .button-primary { + background-color: #a03f3f; + border-color: #a03f3f; + color: #fff; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #a03f3f; + text-shadow: 0 -1px 1px #a03f3f, 1px 0 1px #a03f3f, 0 1px 1px #a03f3f, -1px 0 1px #a03f3f; + margin: 0; + opacity: 1 +} + +.pll-wizard .pll-wizard-content .button-small .dashicons { + font-size: 15px; + height: auto; + vertical-align: middle; +} + +.pll-wizard .button-primary:active, +.pll-wizard .button-primary:focus, +.pll-wizard input[type="checkbox"]:focus + label.button-primary, +.pll-wizard .button-primary:hover { + background: #dd5454; + border-color: #dd5454; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #dd5454 +} +.pll-wizard .pll-wizard-actions .button-primary[disabled], +.pll-wizard .pll-wizard-actions .button-primary:disabled, +.pll-wizard .pll-wizard-actions .button-primary.disabled { + cursor: wait; + background-color: #bb5454 !important; + border-color: #bb5454 !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 0 #bb5454 !important; + text-shadow: 0 -1px 1px #bb5454, 1px 0 1px #bb5454, 0 1px 1px #bb5454, -1px 0 1px #bb5454 !important; + color: #ffa3a3 !important; +} +.pll-wizard-content p:last-child { + margin-bottom: 0 +} + +.pll-wizard-footer-links { + font-size: .85em; + color: #7b7b7b; + margin: 1.18em auto; + display: inline-block; + text-align: center +} + +.pll-wizard-services { + border: 1px solid #eee; + padding: 0; + margin: 0 0 1em; + list-style: none outside; + border-radius: 4px; + overflow: hidden +} + +.pll-wizard-services p { + margin: 0 0 1em 0; + padding: 0; + font-size: 1em; + line-height: 1.5em +} + +.pll-wizard-service-item { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + padding: 0; + border-bottom: 1px solid #eee; + color: #666; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center +} + +.media-step .pll-wizard-service-item{ + border: 0; +} + +.media-step .pll-wizard-service-item:last-child{ + display: block; +} + +.media-step .pll-wizard-service-item .pll-wizard-service-enable{ + padding-bottom: 0; +} + +.pll-wizard-service-item:last-child { + border-bottom: 0 +} + +.pll-wizard-service-item .pll-wizard-service-name { + -webkit-flex-basis: 0; + flex-basis: 0; + min-width: 160px; + text-align: center; + font-weight: 700; + padding: 2em 0; + -webkit-align-self: stretch; + align-self: stretch; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: baseline; + -webkit-align-items: baseline; + align-items: baseline +} + +.pll-wizard-service-item .pll-wizard-service-name img { + max-width: 75px +} + +.pll-wizard-service-item .pll-wizard-service-description { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + padding: 20px +} + +.pll-wizard-service-item .pll-wizard-service-example { + padding: 0 20px 20px +} + +.pll-wizard-service-item .pll-wizard-service-example p{ + text-align: right; +} +.rtl .pll-wizard-service-item .pll-wizard-service-example p{ + text-align: left; +} + +.pll-wizard-service-item .pll-wizard-service-description p { + margin-bottom: 1em +} + +.pll-wizard-service-item .pll-wizard-service-description p:last-child { + margin-bottom: 0 +} + +.pll-wizard-service-item .pll-wizard-service-description .pll-wizard-service-settings-description { + display: block; + font-style: italic; + color: #999 +} + +.pll-wizard-service-item .pll-wizard-service-enable { + -webkit-flex-basis: 0; + flex-basis: 0; + min-width: 75px; + text-align: center; + cursor: pointer; + padding: 2em 0; + position: relative; + max-height: 1.5em; + -webkit-align-self: flex-start; + align-self: flex-start; + -webkit-box-ordinal-group: 4; + -webkit-order: 3; + order: 3 +} + +.pll-wizard-service-item .pll-wizard-service-toggle { + position: relative +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] { + position:absolute; + opacity: 0; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label { + position: relative; + display: inline-block; + width: 44px; + height: 20px; + border-radius: 10em; + cursor: pointer; + text-indent: -9999px; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:focus + label { + border:1px dashed #777; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::before, +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::after { + content: ''; + position: absolute; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::before { + left: 0; + top: 0; + width: 44px; + height: 20px; + background: #ddd; + border-radius: 10em; + transition: background-color .2s; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox] + label::after { + width: 16px; + height: 16px; + transition: all .2s; + border-radius: 50%; + background: #fff; + margin: 2px; + top: 0; + left: 0; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked + label::before { + background:#a03f3f; +} + +.pll-wizard-service-item .pll-wizard-service-toggle input[type=checkbox]:checked + label::after { + right: 0; + left:auto; +} + +.pll-wizard-service-item .pll-wizard-service-settings { + display: none; + margin-top: .75em; + margin-bottom: 0; + cursor: default +} + +.pll-wizard-service-item .pll-wizard-service-settings.hide { + display: none +} + +.pll-wizard-service-item.checked .pll-wizard-service-settings { + display: inline-block +} + +.pll-wizard-service-item.checked .pll-wizard-service-settings.hide { + display: none +} + +.pll-wizard-service-item.closed { + border-bottom: 0 +} + +.step { + text-align: center +} + +.pll-wizard .button .dashicons{ + vertical-align: middle; +} +.rtl .dashicons-arrow-right-alt2:before { + content: "\f341"; +} +.pll-wizard .pll-wizard-actions .button:active, +.pll-wizard .pll-wizard-actions .button:focus, +.pll-wizard .pll-wizard-actions .button:hover { + box-shadow: none +} + +.pll-wizard-next-steps { + border: 1px solid #eee; + border-radius: 4px; + list-style: none; + padding: 0 +} + +.pll-wizard-next-steps li { + padding: 0 +} + +.pll-wizard-next-steps .pll-wizard-next-step-item { + display: -webkit-box; + display: -webkit-flex; + display: flex; + border-top: 1px solid #eee +} + +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border, +.pll-wizard-next-steps .pll-wizard-next-step-item:first-child { + border-top: 0 +} + +.pll-wizard-next-steps .pll-wizard-next-step-description { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + margin: 1.5em +} + +.pll-wizard-next-steps .pll-wizard-next-step-action { + -webkit-box-flex: 0; + -webkit-flex-grow: 0; + flex-grow: 0; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center +} + +.pll-wizard-next-steps .pll-wizard-next-step-action .button { + margin: 1em 1.5em +} + +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-description, +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-actions, +.pll-wizard-next-steps .pll-wizard-next-step-item.no-border .pll-wizard-next-step-action .button{ + margin-top: 0; +} + + +.pll-wizard-next-steps p.next-step-heading { + margin: 0; + font-size: .95em; + font-weight: 400; + font-variant: all-petite-caps +} + +.pll-wizard-next-steps p.next-step-extra-info { + margin: 0 +} + +.pll-wizard-next-steps h3.next-step-description { + margin: 0; + font-size: 16px; + font-weight: 600; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps { + border-top: 1px solid #eee; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-next-step-description { + margin-bottom: 0 +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions { + margin: 0 0 1.5em 0; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button { + font-size: 15px; + margin: 1em 0 1em 1.5em; +} +.rtl .pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button { + margin: 1em 1.5em 1em 0; +} + +.pll-wizard-next-steps .pll-wizard-additional-steps .pll-wizard-actions .button::last-child { + margin-right: 1.5em; +} + +.pll-wizard-content img{ + max-width: 100%; + margin-right: 0.5em; +} +.rtl .pll-wizard-content img{ + margin-left: 0.5em; +} + +.pll-wizard-content .form-field label{ + margin-bottom: 5px; + display: block; +} + +.pll-wizard-content .form-field select{ + padding: 3px; +} + +.pll-wizard-content .languages-step select, +.pll-wizard-content .untranslated-contents-step select{ + width: 100%; +} + +.languages-step .form-field .button{ + margin-left: 15px; +} +.languages-step .form-field .button > span{ + margin-right: 0.3em; +} +.rtl .languages-step .form-field .button{ + margin-left: 0; + margin-right: 15px; +} +.rtl .languages-step .form-field .button > span{ + margin-left: 0.3em; + margin-right: 0; +} + +.pll-wizard-content .languages-step .select-language-field{ + display: flex; +} + +.pll-wizard-content #languages{ + display: none; +} +.pll-wizard-content #languages tr th:first-child{ + width: 80%; +} +.pll-wizard-content #languages .dashicons{ + color: #a03f3f; +} +.pll-wizard-content #languages img{ + margin-right: 5px; +} +.pll-wizard-content .error{ + color: #a03f3f; + font-weight: bold; +} +.pll-wizard-content #messages .error{ + background: #fccfcf; + padding: 0.5rem; + border: 1px solid #a03f3f; + margin-bottom: 0.5rem; +} + +.pll-wizard-content #slide-toggle{ + position:absolute; + opacity: 0; +} + +.pll-wizard-content #slide-toggle + label{ + position:relative; +} +.pll-wizard-content #slide-toggle + label + span{ + display: block; +} + +.pll-wizard-content #slide-toggle + label .dashicons{ + margin-right: 0.3em; +} +.rtl .pll-wizard-content #slide-toggle + label .dashicons{ + margin-left: 0.3em; + margin-right: 0; +} +.pll-wizard-content #slide-toggle ~ #screenshot > img { + max-height: 500px; + margin-top: 10px; + -webkit-transition: all .5s cubic-bezier(0, 1, 0.5, 1); + transition: all .5s cubic-bezier(0, 1, 0.5, 1); +} +.pll-wizard-content #slide-toggle:checked ~ #screenshot > img { + max-height: 0; +} +.hide { + display: none; +} + +input[type="text"].field-in-error, +input[type="password"].field-in-error, +input[type="checkbox"].field-in-error, +input[type="color"].field-in-error, +input[type="date"].field-in-error, +input[type="datetime"].field-in-error, +input[type="datetime-local"].field-in-error, +input[type="email"].field-in-error, +input[type="month"].field-in-error, +input[type="number"].field-in-error, +input[type="search"].field-in-error, +input[type="radio"].field-in-error, +input[type="tel"].field-in-error, +input[type="text"].field-in-error, +input[type="time"].field-in-error, +input[type="url"].field-in-error, +input[type="week"].field-in-error, +select.field-in-error, +textarea.field-in-error, +span.field-in-error, +.field-in-error{ + border-color: #a03f3f; +} + +input[type="text"].field-in-error:focus, +input[type="password"].field-in-error:focus, +input[type="checkbox"].field-in-error:focus, +input[type="color"].field-in-error:focus, +input[type="date"].field-in-error:focus, +input[type="datetime"].field-in-error:focus, +input[type="datetime-local"].field-in-error:focus, +input[type="email"].field-in-error:focus, +input[type="month"].field-in-error:focus, +input[type="number"].field-in-error:focus, +input[type="search"].field-in-error:focus, +input[type="radio"].field-in-error:focus, +input[type="tel"].field-in-error:focus, +input[type="text"].field-in-error:focus, +input[type="time"].field-in-error:focus, +input[type="url"].field-in-error:focus, +input[type="week"].field-in-error:focus, +select.field-in-error:focus, +textarea.field-in-error:focus, +span.field-in-error:focus, +.field-in-error:focus{ + border: 1px solid #a03f3f; + box-shadow: 0 0 2px rgba(160, 63, 63, 0.8); + outline-color: #a03f3f; + outline-style: auto; + outline-width: thin; +} + +/* override install styles by returning back to forms styles */ +.form-table input.regular-text{ + width: 25em; +} +.form-table input.field-in-error{ + border-color: #a03f3f; +} +#pll-licenses-table td{ + padding: 10px 9px; +} +#pll-licenses-table .license-valid td p{ + min-width: 35em; +} +#pll-licenses-table .pll-deactivate-license{ + margin: 0 0 0 20px; +} +.rtl #pll-licenses-table .pll-deactivate-license{ + margin: 0 10px 0 0; +} +.pll-wizard-content .documentation { + padding: 24px 24px 0; + margin: 0 0 24px; + overflow: hidden; + background: #f5f5f5 +} + +.pll-wizard-content .documentation p { + padding: 0; + margin: 0 0 12px; +} +.documentation-container { + display: -webkit-box; + display: -webkit-flex; + display: flex; + justify-content: flex-end; +} + +.documentation-container .documentation-button-container { + -webkit-box-flex: 0; + -webkit-flex-grow: 0; + flex-grow: 0; +} + +.wc-setup .wc-setup-actions .button.documentation-button { + height: 42px; + padding: 0 1em; + margin: 0; +} +#dialog{ + display: none; +} +.pll-wizard .ui-dialog.ui-widget-content{ + max-height: none; +} +.pll-wizard .ui-dialog-title::before{ + content: "\f534"; + font-family: dashicons; + display: inline-block; + line-height: 1; + font-weight: 400; + font-style: normal; + speak: none; + text-decoration: inherit; + text-transform: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 20px; + height: 20px; + font-size: 20px; + vertical-align: middle; + text-align: center; + margin: 0 5px 5px 0; + transition: color 0.1s ease-in; +} +.rtl.pll-wizard .ui-dialog-title::before{ + margin-right: 0; + margin-left: 5px; +} +.pll-wizard .ui-dialog ul{ + list-style: disc; + padding-left: 20px; +} +.rtl.pll-wizard .ui-dialog ul{ + padding-left: 0; + padding-right: 20px; +} +.pll-wizard li{ + margin-bottom: 0; +} +#translations{ + border-collapse: collapse; +} +#translations tbody:nth-child(odd){ + background-color: #f9f9f9; +} +#translations.striped > tbody > :nth-child(odd) { + background-color: transparent; /* Override common WordPress style */ +} +.pll-wizard-content mark{ + background: transparent none; +} +.pll-wizard-content mark{ + color: #7ad03a; +} +@media screen and (max-width: 782px) { + /* Override WordPress button css rules */ + .languages-step .form-field .button{ + font-size: 13px; + line-height: 26px; + height: 28px; + padding: 0 10px 1px; + vertical-align: top; + } + + #pll-licenses-table .pll-deactivate-license{ + margin: 10px 0 5px; + } +} +@media only screen and (max-width:620px) { + /* Override dialog width rule */ + .ui-dialog{ + width: 100% !important; + } + +} +@media only screen and (max-width:500px) { + #pll-logo a, + .select-language-field{ + flex-direction: column; + } + .select-language-field .action-buttons{ + display: flex; + justify-content: flex-end; + } + .languages-step .form-field .button{ + margin: 5px 0 0; + } +} +@media only screen and (max-width:400px) { + #pll-logo { + font-size: 56px; + } + .pll-wizard-steps { + display: none + } + .pll-wizard-service-item { + -webkit-flex-wrap: wrap; + flex-wrap: wrap + } + .pll-wizard-service-item .pll-wizard-service-enable { + -webkit-box-ordinal-group: 3; + -webkit-order: 2; + order: 2; + padding: 20px 0 0 + } + .pll-wizard-service-item .pll-wizard-service-description { + -webkit-box-ordinal-group: 4; + -webkit-order: 3; + order: 3 + } + .pll-wizard-service-item .pll-wizard-service-name { + padding: 20px 20px 0; + text-align: left; + -webkit-box-pack: justify!important; + -webkit-justify-content: space-between!important; + justify-content: space-between!important + } + .pll-wizard-service-item .pll-wizard-service-name img { + margin: 0 + } + .pll-wizard-next-steps .pll-wizard-next-step-item { + -webkit-flex-wrap: wrap; + flex-wrap: wrap + } + .pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-description { + margin-bottom: 0 + } + .pll-wizard-next-steps .pll-wizard-next-step-item .pll-wizard-next-step-action p { + margin: 0 + } +} +@media only screen and (max-width:360px) { + #pll-logo { + font-size: 48px; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/html-wizard-notice.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/html-wizard-notice.php new file mode 100644 index 000000000..d2ef5a948 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/html-wizard-notice.php @@ -0,0 +1,49 @@ + 'mlang_wizard', + ), + admin_url( 'admin.php' ) +); +?> +

    + + + + +

    +

    + + + + +

    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen-rtl.png b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen-rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..293e18f4f922e56c08d7f736f3333b4c30880dd3 GIT binary patch literal 21885 zcmZ^~cRZDE{0Ds9XW$@?y>*ZgG9%k5dt}Rq%#cl15qA=@vx|@v*(19+MJR=2&m$QX z*^&92zQ5=BJ+Id@{<`n`I@kJquJ`->`P}z)od-q+TBj)4DFFbdbhOn?06>v$5yccp z(nXxIf0}f$HPScJI6ORDTU*=O+B!KonV6bg{_$gEY;y1KUiclj;92pvZ{PaA3^&(S zew_M7c-JK@tLWnFnwXmXylr4(?921?`;(oow~miODn4#UCv1z#AD|hxn_Js8_0LDw zkFcF_Ze()>)Xdnde5TFD`07d}D|Eq}j8UezC`aCaRVWfD+Z>-JB_;CBrak4_}mBv4% zb^W=A;$x+Qt+C=(s<2Ypx7x* zkmF#Emyn$cS?B_#jGyXL{1?+oOq3r}Ye*$=!127UQg8(_8)79Bi}g&9V+&a|wrvSx z;vjn%`TTA3-LAJXat{^C7aWijhQePT$-sMyfHXroO|aYy?vWAmUd{Nrvk-N@yO7zla-F$2>M2rJ@av9) zF{kFwsFAOOx>fOV#yOBUc)^KS5eZpEms45Tr)$-3Igyr3m*PJ3oA}y_A4Xx zqTcla$T@?p)=v;!o7?L8H_siUr4qmDMBB{Nk;1{!GMNw@=aP1c%wykYRg9|QnGyB2& z$gHY~Po}P*14Z!5@O9|Y=dUM?>(pw|Z%Pe`Lce`kR3F2#s*gxbzj9i?379pY|5(1MdfFb&ao z`z=>L;J&bb0VzRUJXNT3`}ucKwUFO0ErSn&oi=Zh;pD>TC1Rwt?rO;g()*T0{PWvK zA4YNuYqb8YpZ?Sj*|$XaMoRn?qf;Bp5q;^0y6@})S%_BNTGD_zu=rnn0td@fYXy6i zTf)0Im{S>kOdgidLjKo!z)x8v^~UcZI_ZdEFFf&f*eQ@!HwouEu!^6SUGO-YVYXIp z{(PrhUV^h$h)G$>f?VABN$AaGy8~{*qcm79h-*wDp(s}eTl=$!@!^^`nb~K{S6QJ& zQOzRGZzEPUa2*mvsh3~TX_{XSq>I>X>Dm;K;b z&Cy(Y9>f}L{K&xv!QLfKNfyd9wwE}qFyM9y0KQ z_PJ0lX-@#30@V_nYZ{fcH^Smn6vbR<3pghmDeXZ*G#4jl=}Wu{Wa&eHQjUXM3bi%Ge__VdR^{I=r7XU z`*=+fBXa~nM^=zr5>>%ibU(G;X$}b;<$1eHdrTU%L6DpnJWEf3L!faeeK+&Goa&Lg zmzqk|M_Jcp-cG10)`SF!Lj%K`=N27)SUnxCW^T-5oAdjsrD?&Qw@W1w+WsNqwV@dU zp`8&Vcc6()ARLnwjg?N0rgP$1k?cY~?X;}YC8~@zTNX((UoF#3K4V$W_x_PdVhx?Z z`PNmuWI7varoD?*Y7{dHF}CL4eXiT;?Pyj+ zb0a&q6jB?a$J;Xac5&GbBS6>0=_YOd#TZax_Mg}6{M}iZ?{O-7Po|h6)M##eT5j0D zYKL+#H+6rdX9-p04=k&neAzvjLdd;sbHF>Oo#Zv*I>~+6)6$WqKS*yfd6pAz^`t0TKIRnp`%dnDkyi&o3@R9FK;b02g4~IYs9cwucBU1LxNdsw2gT`E zYXY%PCx^Z7W;xLKCiBto73D1`C`45Ybtz>6ZoZNWqS=zK-URZ`M6-staq9s(T+P8B zG1zqeYy+yg8RX8+BZORb2l;M)|8*b@Z>Mw-e_;sgZ$Q!`V2NO*hX+K&SoJ{NHOB{0 z4AE|4w$cDF;MbTa@G)!RsdA+%0fzd3sR<9So?RGnSe82vn8m{o%&k4gp+XHBPE zZE4F}b}RES6~PZWj5eK|9EdjknW8!EJ#BO*IYhU2F#HVsXi8U6#(pQu_d6++3cCUg z1S8)&O=Hys+YhdSZa*l6i*p4;>mV zY73poE3$w(_Ro&rY@WGKdRRPg&!|+Xcih-8eZb}WAMa|E#b;#0_4_|NS+Z>f+Rkqg z;$&Y}?Xe49Olox9DqoM;^Lr*!vBPIQKk8Z0^2Y0MYQxIseNfn5@a-9&98g$FXFHtK z_>d2>8G85Wu2%kkuCo&Qy|=sWmQa-|*`>e7HmxflRwF>h(vp_1nnpY8Th&~-kv zn~NA<_*X9?h8?UQyeGt9;=|Vu=nr|0-qMLds!@V_aqZYnKj<}u*`?BEXLf!+VZXn) z3=?SyM}A`ZftReA(X^h9#bXgClaGC7l-$39A?%!Vafxh~v=a-wCENtIS%qH+IGU9Q zP!(Gb#j0F**fb`~;c~adnnmIIiw1{6>s#hXf-Nl>|2reEkV|LnQ(II}M%-4EVqodI zFQk3@m)(qkqTB+nmJdgkT-lAWnw@(w_g9DBTyT-s?Ytre`8M8bWtK!l_XW`CsBeda zuPwz;8Pr%)?wQeTutdsL-KQeF8{x=rV2Ky7qABR)mDE%;cuNnoYt8Z2J_I!o5<1_# zCVKi)QF3EME_)0+-*%74`!fO34+$E{!)plNYjiC5%zKf_Xo)kcXMO*^vqZ=(G@*=K z1y#`!{;clx9)0ztnNvFywi?%w!CulYvvUh;T-J>qxXb@!A$h>R33yK!eP7lr?!=vX z85Iu4aGsCP0!fZ@E3{CoGrf7n&<=(tqf$CtMByPat?*H`rPuK#?9zK*s3-;`J$27~ zS!VgYuB^+{4TB#NQbJV^219O(rU4`BGJm>vLrV(n;FxkgJnt%-ur#U%Dj~IJP)EfQ=$J~?H|Aiz?GwGI4_LjJG2pv1j zpCInPN&Sb?*Uaf2Z=h@jNS_T~A~P?-ITCGJp%_jZ5=nk*nw}}m?Ad#`TZ)L}A@VKh zj{ocRn4|H^Ylyv6K zDE^^MK8@M70ZhMRMk^kP}ti}q7Wm`ia+s*!zYb%?w$R_%C5##xbj?> z2pQ4L;mnt4K|N3u)ILT3tfcETlk$vd1Wzn!()Xgc*XHj5ylr6^7H@^9PK;Rzag80? zy;0+(ud!QJ^l*`JHwMUlL0XdWtg}f+U_nW&!M90%m^1i4qn{aFSl`luV*qSjh8EpB z!Vp+5C|-#u2rPM$iX91%iDoQuyL|ROb_dip@B`ha9@KRMxbo!4I;@YDVI$oRnM zBU9?SbJYKJck|@PHTpcazdgrh7sb_|iIUC35*~lLin(n>%T1`ksn(sI;`2Qa+}mK1-oOZds!vE}Qf_w5pG!dfihJqj|C|ey%=8^uc?V%J_eZUk zXY@-faXIx*;$yGtM_0t^=}&j+SFVl>Hy8!*Y!Ixw`C+TnN*2E>F(2;?4`VUeiWt5ui4%QyRiQU?1(2rv|-&?^ZGbDd}->& zqXBafW~DX>W;K@JPDgCU&(r8|9!?hg^)PZfVpjU6J(^OseEZVpWboVUv+YTMvl~rF zh#)`7_v!w0y8r)6r%9ub=rMbbo8__!dYkiveEI9|=O`j6xih6zsee)`e2R+ljburg z`ZpeTjOt>eH?fd>h9|e`k1BZ}N%f;l+52yBki>j>BD=SA)RcBRR$~mK{iDVJg>!}3 z@-b&^G{Pxi6ObbOgxyXbB+Vn_ZeL}1bBag*QfAi_hpCSSYX<@d`vZ-i^$nAc-`Qk* z3aPafQF;H)I%6G6nBjo5L*)OZpm=_IHv`^8zb_nh=LVQSz$K9K!b3` zvr9#mg-D;z*Pz58;2T*{eec4ECEzEQ^Q33!Nx;0J!gV#2v%0p8uRTW6smJ9Cn85fn`Vcy^~R96rjt+p|Es+JcQWulAUlnlUT&<~n!e&UxhJpOeY(cBgKv5!kGyT| zTmRMn2+raAVEbjH$p)RuDvfYqSzU?qqU41=h?AB$;!5j#P5EgF=bm7w&-TWj!9AJ( zK+5YMCN|~Q#itV{QcEjua6^ZEUi#%PD1kLDdSHI#t&$PyIu-InhOVSU+)DaiLmQxl3%e4b`j88V{Df{r&(Mxt|D3}DX-=_53e2@L9|7VIPVQb_LC zlW3=cb&+RsgFsKvovp2r$won-@*FySLXEF(GT_}goWm51(d4E!@YLOMQkG~QPO$MX zrYd|M#FSVcd*(m)Q~CM;7M)KQMX9~iM5JjyP}eAa*f0lSy8JCIF`PFUiX@r&>9;yK z?NjebI+OEk%Z3`AVQj7~jIK=UGH$0^Bjr%y-w*>j4}>-ND?iIvTO>xkFRkCwr4bWe zonHb?oi+Yl&K1-ef?Z3)YPJh|Lf`>@x$N0Br|iUkO^Jxuv(IOKPc}&QdmPneI~8KR zow^;vrM(lpLMI#6R501K<}+8?Ldrv~g5x1hDef_(jAG%9ncdyv#}T?m-F(yD{HhQ45BS!M zXVMx01;L}JvURbiJvLS;=zROSD1F^Znsch(w;wtzted%yV$@}bfdVe?9L0@168g!JVQ7u&W$Vcn3wB4ZdecUg2T%tfc>4y zb#dTwZ~=oiHUo)gtR*5=E>q!7r=m9>`s-wYMM>fS*RQMSqb^QrQ zNEORO$jx^#9pE_+8ByfGRQL!!Y@QFXS&<)|mVyTHn+ zkP`p*t1%?E_%NI2t(1!%ENTUNcp_lxtnut9GHInA$kK8|--GHGJG`m&43WZ5>HL{B zl7HPqtmFC{6rLsq4fNFlz5^0uV|ew`-G2aantK; zr@$OMO@mM{)spn)zZ0i>oRpU07!K!AhQ3`$*Ss%h9X$_Me;2| zLV+_yOO3F{`fWsgK6W%6b|L`JH8U$yfTV@s7Kl_G zk$pLA1yFzPN{WgQNcW}9Sz+500?o8{=C(Q~FBNRQrNO%^RpCMy@zZgDbs#&A!4_$h zZb*sG+^j`fUS@oKiJMG4is9?hDOv>Uiu?=9-OzeQ&h-6Su~8FMUI0-9l(C&g;hr0C zTzqi~-fJ=cLW4I}ISUUD@W8{GpQ5WDN0B$(uR=fhU~}#+h2ZP4EH3!dB%APiA3EQw z@;;+pWeKh*M7SxSo@waNX}ipeZKnqexO$_?$Roy#pDG^UpAm5OAR1SO=?aE=JSk}e z$n>el7bt$XxP7Q~x#a2$WVd+WvTe@rj zc`h*a;4cGoeL>SX8ntt&4bZ959Rb*e{NY_a5x$Oz!gDv~%``><su$!!O=bvJXanh*{~UAux8DG_3xq3>3NQ_k8FwIBQyk>7DLq*wM}jp%7CbUDA$jg<9W_De3CnFcSh32>fY0L z@;jG{+PB*wriDh-|H)N^kr{}qgoH@+ZKu;FVSyx%!k`Z$ZuOaA=Ayoh^!y`-vmwaZ zE9-_mGC$b~CnTm41ac`9JTk@U@Isr{=nfhBe$1lx3`orHxpQ8X0@vIM#_A5^fxt;6 z*s}t>A)h%Aa%r1UWX~l_K^vrj#(5Nym_WfUl8;CkcMY*Ag*T z3?Pai=lX71(w<6G($sF`@Zde*;&eG(n#`)O;9^58CDDTvQ38Ti>7_ng1_FKK$lhDM zaStSF_<5Y){&k+qSmF$ZEH&>jGbB6SNo_S}!75Y1-iU%cRMwmFTXJaMAzSIHMIDz8 zUp;zBLxN*y0p+BD&}%&WRCdn-Wi;WK4>)7%FQMvC^Jj15>N(vH+i ze`a2JkwW#I5$@$)Qeo}pIgKDVr#dbA)vU%`xX;q@_G6s_Uhl>8f!m3pQ}qMbat;>p z7P9qv(juB-%j=uHj+8&X9-Hds3J`K`{r-N86AGrl*{MrJeHsbUi&CjiDd2kwa+P8E z?z}sny?!@SH2r?QwMuzz@Luh9XG2!k07r_lljN$`L56Ot;cD=Uo%|C+TT7PY>jY%G${fNQgn)_f`mv9=mL_fNIF~cAB)TY3IG3< zQs1L+PC;sOTmpq{52zIfp|zBN=q@W_-vUDkSYCQ#22NzY9SUWoZMk?U_CN;ee{lFt zubbYSS{H8Tn^eo9LI=B#hI<<4=L;P4XW5TdPHKXqL%n_}aW*h$C5c+JKggIqdEVyp zSU5v|)geY;Tzlsg{%mzE?d`p*HC`?)gbNfVY>s&t-8R2lbE#q=eQaU96cKw}sN>7; zFQMRo-cnsS!$AlTY*>s=PyKA!JbY=>``3CRZMwI7xG$vU?|6aMT1Bx^{sp7ktz1k zV*NiYUT6ip4SN(j9)+>3FZDJ)wUO~dv3tK1!MdrmPASj%{mz9Z5ahzz49>j|qaE1o zT@sA!?QV7v57sy>fHrY&JFi+V1h(tQ0HP)SR>j{OONrMdz;QWQqel#Wf{_q=P6moD z@E#2eao%W-(5xi`YPzLBO@|i#AxnP0OtIX~KJs~6IoN;p@C|wO1&P`#Cu?f^b2Tg` z2-CNCP3nD@kL_bQXTy*F3MjzlRCI+@M4=GG7}sO;dTXFzuo>Qd)(UAe)7bA}%TW$l zW8fs5_OwG28KN}X7W9)|6QL=c^-=3Lu6H%bg1#5zTdi1JMW5fP@}Z>$DaUU)DN7ue z5PQO6fCV0js9mTE*7ll9yL^aJAEmu*LF@LWzds^O>aH;USKIk|)!9V;6+w~&fmU!0 z55_~mB;i@mUz6G+8AZ4;uxi-QdiNA?Zg)axPp?ZlzQPpv!79ag)8qF_OUuEHW^xPHf(-IRs`Psnlhl`Wg1%Z-6?(qudL42L>n0^{lvPZ&Dv8=As8wI8CeJ$Xsj*ZFj-JgAB`N`ZQMRdraZ}& zJ)S&`Zj$Df;H}2Tf2Mp-X}_EtPgP)a9+BPtG<{ha4z%at4b70 z52Ao0?75gkT9TpXhF~_@X#d$agiuFHi&Xm7*{t(i4q-oAEb08#QPpHm#Sqz&5qqQW zGvB;W*h)E8-dENe$#e4w?cyYYE-mwp z?G^BA_OITDul1ik%Oa1KTJJ`sw8~M}P+l}4pnU_N?_xt%;N;|tS%Phbo&2VPGGGCz zw$I7Wd>X@9{@rAlnLHQnp1(f-Y+YI={l%=A-83-%VBGTUuz zFbx;4s~odxz4b%H(?TN*@S7gZS_^sQe2^*#cTnLLZ*jC>^-4F(Xyt9zZ-HOfYFP^i z?%GyH87V=pha3w`=z0Y_AR7==GkpOIeyj!F=TZ2~m+ z1mWpN=z@ro_KOIiMA8A6l(4JoRo@WnDElQS0~Ha;VSnxDFG02Cl(+n^b{GjJ|<5A=8kVs#E5R?t8P@L!Seoom^?i~`lw37ioYfO7cpffGqymQ0gY5M$mH z_Vi#!5o>JJ8}WP5(1=OrsNKW`%BFzpRi(sWB|*4n206Aag%d>(!$VUk8fTgnV2zIv z`k?3Nt{=oGmW3MF$pa1aa7E|G&>__c3on*k-9sM)_UAtd$-S<08G}m}WFZ8R@`{)> zKA5KF<(#wFPbir+yqyFfxfW1*So#eyW&^725EPi4eta%4RtaD{`qxD zqYad=FZ7zv@P5mVHA(D$yz>$R>hKWaG4MpKqlgIB=qDqH5CrUj8auR4ad6iDc%+Fl z=X_1FXY8g-fgsF=V{2$f*|SFk(*rk6&1yj6B9YIgXO(W0mS- zbsP&!MG!~2^IZ9Kl6-_ zfXw|}(rv6wu?_e2gNeJ`XUFc1`~Q(i_CvL9UjP{>66p;FBg zN$9Y>D^*8DAjy^GDeRy^E^)%EjXis1vtt{|#-%?!DIy13Ts@8G+0!fp2i7Q}3;6c< zAm%&IuAv%VT4wcARtOt^%uZW{5SkDhJIw;`0vdcV$95m09lOS>T0e0eNpp+EI{7)9DIDb&G7&B)!rdg#t{gn2-2Fz7IrX0!CkGC7FsS@x7Gc zt{`{t5CTJQ_LS+GpL4ajXEPZ*SEIt(L&K)@UnM*$5AEChb^ZZ-MqAxXi>ANLv2xV` zwV-xX_n9r39&aT{Qij*$L_~Hmgj0Ile((I#jl&P4oRfF%c>ZNb&OV6wgpk--vw;4a z75v#8bj>*&3(DYEugG%_3FFbIto=2WzkxEOMC}S`e-ELZb?}S}lGa0;gml)v>y0xL z$kvfiQy1MAQMz`jNtBZmO8!$SGg%qSn%1l3)B*Q2aNGS-W^~THxO3q+$00V5j5}ip z#K0OZ2vZz-oumf7nFhQ5LZ$@+jPw{n2cIH@p6%qC>$x z-7hz;J%DFBKa~_7#9&uHXwS@EfGc)ZF;n`--f4TQQt9bsE2I$5cZb;VV<*x90|EG> z7+m#@6tv-NP0s3~wx?4+Pgll}yLTI$sumXp=#sV-^#XbukO%V4B$Y!aefor`ohv5{ z1=xqa#|#LZ7s>IYu!9Imb#SiZ>mi32D*~q z#DU%sn~c@bYB81{0UxUG`<+ZYlZEiSmD9a{fPWxF3SVc*9F7iXPNP!FMpPeN4ij6J z37J#ngHstn<;MLSn6#CQA+p6$+9Oiw@VF>-O(1{}eJ^-D0$P5GUl>M%^n=%tk+!4> zXLj5jZpHYM8Nfc)a!)Lcy@pHY=Uzu>@ zqu{Q{c?=Gk|3w4w1|F?PLH}^YI(`@^7CY4%r5DK3lew$5#hP)HK?n)0{+1|nLYaQ7Q(2fA}k24rt z#`SXp@dhaWk)NdKIlz5NNa6w*BZIf?86sqW?)U|$s1O5UOQ{Hd*)@R*EuaSv2cCbF zcpikn7KJWv76_;B>Vx;WG{@Tw#D5DigB*DF*7xT!-6ez~s7@d9m%%4SxKkL}1*(#= zAm3LxyWkHCJk5|&z4+th3*?^UVU{D!l8wPuhqo5Aj0Nzuy#OLTZI=WoDeF^ru#`Q( zm9R>WG(c`OS;QfPL`@pBnF@4Gpn)<<`ySiA?%M|p7y`Ol6pe5^t2CJK1Y!SWzg?LY zJh+~G#ooo>}Fp7j^jW-2{LA3E6oLdm2!k z!oB$g3!*H8axhK$>YO&f?mY>?_HF2+-g`kuc7vN@!H)q8JD*t;7c+9a42XU~uXDDs z573fdc3~_S_W3z$uMQRkU2&3wix_;wDN+I*f>`H<*-%34zrC83d%(-PQ4J~|2ev`1 zr2-2jl|ebz#69}tu@dUD?TSL&IXpa)K~vfxdZYNojT z6)Lho7&jqmd;>Z0=0x`wBtmu+?#4`UbEbrX;=>;t>6OA0qNbJ))}6EC39zNPMGwk( zNuF^pwL9I>9pIBS$3Ymoba(a2GDy7)0#-Wi+5%O&=QECkb&@qloRUHEOMxVj8W@zx zLay!X_8w6e%ucz0r>j@QAOGk>^?u8?Bu4b`{Kv@IODuiGcQuoiHV&D459D%ZXRd3z`a_;6fM}px z2E~oEztsfDGZQX1QYcALQG^0_9BZ33i@u&aqpAMTR4Yr1b##@a1~@lKzGFo?!v0*I zH0&FH=bdohxEce@X+@HUJ|9~lR43ky5_>W0=E+U<$oeIc-ch3f?Tdpc9fqmS6gN93qH zKtoEyg`Rg-#!DV2zmc~09bg>e)oKLg&I zQo-Wf&tne!?&jJjTss97dEy6H8trS1(1wbD6eN0ZnG=ucmc1BqmqFFH4GPOdr65=Z z(J5*`3NCDoT746~7ja6$(3Q&mf$F(psQUvqUI6X`8&o^(UuBL_lim>@K;z`i`IwxO zB~h5o!T`$E6oB=CUkCcV>}|B$X(L+S01Wa~cX7mY{OB!jjw;!MhsZbz90LLKZvyH3 zzgwE`(BliP-u2w|Z(EG)XCwZ}_4KM5EvuL9_oxVbVy9&%{mPj%-&}Dx7fpcNp?kEH zM2q=>rE!AmU*kis%Hi40(bR+e$EWjAMp971LuHr||CI-?Klcz4y3MUSk>%gWMYFj< z6gNGpZD_a>eDkgk$L0UbKYW82!=gLih@N`2dVyPacWT3&|v}*YU)IyTzcZhvZT4?D+bxewZsV z(Ld`*4SgZb>XiMjGPk3CG2AKIkx_+dssEYoG-AN~@bJ~8&pCu(MAM^qQ1n8QF!eJn ztFlf#V$v}96jb%s?|`gV)Z*2+DOgHFG*Oz~Ogj`m2QKdwBm&c-Qb|Hr9OPYZK1<=n z+9P3q&083VL<3z)qP_`u1c+&fqQf_O;4Ujph0S@Wy;)-o_V}wASXIHq1Xjr#Z|Oh@ zDgWGi9?B+zE8oeimvIT%UX;RnRm?Ol8^^cL-3n(s^Haqi5A^XxB-==6T5jBbsAW8~ z_+>^5B5x{WBaC>3x68)wTae?J^4c11(L?Gtc^L?-XWmm65erf<_9-inGomCKa+Z|PJDIY%NZS2ed$AO(chAde+XcX2m3B|rgOWspWuE&7M<*7%;>+`Y={0&to(sXH8^XNEh-=7f6gsSojo z1cdDQ8<{|EV}bHQl=wZ>2OUMg1Uw#S_1VWFhvu;bO>BY^mqNZqFh~|Yq`}dTy{u3U zf*7d>Ou#*7T3imC9#IS%vJoW^omZQG_qRBb8 z!6&3}sxdwvl^dE#z1h@xFBW+6Ggermie0?xulus(XdZ)#yvRRkAqNxru2he=xd z`0(_;yHcD1QRE6@G1I|h*;ne_3RsR`hvFTTMym8EMK>_nMRv` z_g{vTJatGeVx7N;h>bJLrZ%#%SG43VJO|@Jjy4{Mc-IEfB zCS1!`U}9bIHsVZp3hr}Re=&$0X}9j)zF!jVrNsJhVRM$s_Y&DZ@&(Md+kZh-Pqz$* z-<1^U8BnR@Y`mBjr#DxU-s=puwnvs3Ra^wpL z&sCsEqh6tMl;f1T-4?h}ONiyv)M#XmNV|LRS> zxbcCTVA#b6F~+Y+lK`wcA^tJOVGetF#2*{KWnu zKOyBS3THqkk^ua#5GLRF-8!ahHXyR%`rNXZ@TmyaV%aC()qwpOFfHEWhLD5s4vz|` zQ7x!}3W!1>0tb5t!e`JDeG}iOvmUmx7xd7fuuO(s776>K(ZJw~4xSFb%8$MKRth>Z zj$~bIkbUWoSq@m1f3Z_FyE3PVu$o)n-(cpXS_*CO5LVo)p26is#qCj5g z=jVj}*$BP9@4JkIBu1%t|K}kxKwZQCOkATLH8wHgEiC`u0JOZcr?7vM4t^)ES-le6 zywhygidjy)A*1^% zlW&i>Ta<+8Zru_@rQ;D>!iPpJ_B*WlbI%I}(A?gy{^aR|2FojJ4s*Tml9``A{oa9r=} zh>X#q&DGD;1>+efW$4HxCUw{CS5~`qA3q&Pk^Uy4g!BF&f3weigt}2`DOR?B1jO7y z5j_V4cdGlG%V8bOQzJDGnhwqa?O-26Q(wA)XdV#k=|akoarKGwTM_kImromT?za!z zaX7M8UeeaZm>jf6le+yKrlY5su$-#bdp%LfSk|w>r5VKql}~AHN83ttWeB{tYWZe^ zgw+ZP)52a-6sx4Yl3g&0iZ~FtWOI=kwFD z=N*dJ(i2)JM9wDHkjk>rM)dvG-&z;f(PbJmA$N&it2$U|BD=0G^V8=CeA*o|s%{Nl zmreLK_NJcveo}(gF>d8lZ3QS?1o%Tq%ptz9dcF1rgTHQKSK$=*bL$R8N{jdG!HJU= zAf2E8;Ks}kxR$6#Sw5fyg8tk$M0vdO#VoGGsmT3Ju-Xdr;3Ze<6T4YGx8T|N{cHUqKKCT91xmt2D^=7b2c0{|vZv^36V3YT}KDewFr%Ux^=LL3j)>5{QjJ z6Lsluzftzjr6ta}y1bxxt^U!C1@6&f?yUw3Y_~X|%v2mAFM~3BE@y`A|4PL-^EK-V=|q{{I8_YqREIlp4hu7_LNf2tRU93`fZnd&9j`l z*%_4*bk#NeVj$aCKD=VcYTuhRFr{EQZ{r6GwOqEv>xipHY@<(szX6Ft@wiZV&+Wv# z0V9r{l&{lLL$o9BWYsQxMy9{5>?K3~`GF?54w(k7LnpP#&WY<#6YVoyIBj&a{HgKZAlfzm; z_{r9VRXXU9`W_FEP1~FmOAw!=*@=wM;7~nJ6=fE7cAFo? zP~&2-HaEEf_6KL4&4|az@xoQ4dcKa!V%_H5UPHvani)s)Kdtm`j{$M*VJq|I#(dQK zOLmVvw_U%3aQH12_?3H)|2Ci#e#yLV+g9%sGfGD|;4G$m-t=|3A4{qL=Qq(6^mloj zs4nhtIesMLu>4bLHTn1&MUt4(xBn{m%t<>f?3uK^Fhp=po|gwqzodWvve~tGcGotk zrb|=}kg0(-wT}s>jw17i86fuVtr?i;J z`P%HcE&2I2Z;pwaodkIIDDL*pHEF7T5zy6a*OC0 zX=zWFRk-b9vm)PUw1045SJp?(Rky=-R^_#?ut93=4dKbP68#U<&|bUK``!nzEZ8Jt z{GQF>eHkYl>01DfnOepVTVMT(xcOHP;hZwtrGUh$F%R!=l_OG8^(t}oT2(!M6a>}I zABIg1HZA#o{G5Wt^Si&L8hwXLSh~5xjQE8bJ%2*>>Xjw(gyQgP9D1AZ|d+PFv^R%yLUlBe_2SxiH zv5s8xdHs4?W|4nadd-mYT^_tmVC`u^M2*P(*FIU}>d$Xn> zaCH}MSUznpK+!#T@&ZAT4k%`xMr=PIoxRSRhTuy+;(IK)q|?8GzEH{u={rT3sSQXW z;6i6#Cw2J!k*PY`bM9ZWBOQ^waVQAhazNfZd+zT9FJN{Z8L@e=4d~n2GlXYk*;H-! zimH|p@xi5DwKM02oTHJSQdd~NM@GEhi=bGR>!%{(%wEjz;$xCJ-qg)c+ck1&{aJRa zeRny77Ez#xkW1aJIgFv&k4M0t*59Crd(r^0tVN_s3^Ld^*yj!v-??Wy7^-Mun529| zTz_7sHTY`ch8H68OB!FnDiFFOq+2|M#?OZ?nS=9=Ecn~43|#jKmF2UJ&V0$i0JX;< zBrQJcLr&bI!TF**rM#r(yF`oVe4@O(U5YI#jX9eQR%Vu{erxzYxU&U6ddAHA z-O{V&eO&q8Up0dIgeXRmh%CwEN0I&&>`{jV>YVZU`XH#Y+|}rPoa}@6 zK5uKGJn>P3M|DM)XF{2oYZd!|edDW3LXP?HW8V?h@MElm)~X(Mka1m?fIRYS1>bhV z$Vgs=@%VbM8KLIzR3L4c$?xT*SaXA=_!l~?bWs<#b!ipw`;=A!`n6Z0v9&H1%eEzf zBUo+Tc(+srL>&hBeq5rmVj~?ki)K0d_&woddK=EM@fT0L=jO>prc@V*Zi`Zwty-LLz&R_Y+zW*&|fx>v<_kB2BZ$BF0d&mYd*$f&a>T*L;W%O!AN<WfQHF^k=HmxC}TMVvi=6*sX z&K+O~8(ajOYb}~0r}I*V$9ND_jlt>t@?cuPf*Cr%Ae@82T|?s-gu#BHEwGl)AB8u? zV7=;3NT^(ST>$oF0>KccWZ1d|+%loqJ=*eTmC(f;S?*PG-@h|u)fB~b67-*queNO1 zAnhW1#a{Mot;a>*xAe{UF$_;!l%HM}^Nk=+xz590ECvgd8CVvb(fx`^C}q;J?QbwI zD7vmawrQ@JXwV8|AE^J#5q+7rbl&N8P5D>0Q8w84L{2mG9UAX4X z`ApPF?5#e3)kO3sCo6+b#ePEr!Bddju>}zLt=Gd{`7{@kLlOU}=bh-Uoz2>vKDyig zM<-_j4Q2N~@H>wg#x5dR1{Ebj2%|75B&MWSlx>8vN7gKP^pcVyWzB2LE^D$gBm1th zy%cI}m3=SE{GRdqFXw;$=RN0t{^y>1pPA?RKKFj_z29^1bMF0qZZ>GN#JC0}ozTUA zKelS5ci>*VpE*a?&dIvh5qRdcwyX|NBIm*^SMYNuozz@;38!OY9aDLJa7`)975AV) zr)^t?v{<;&#mAMd_*Bg^pR~R3H?{7-|3F;7dN;!b4Ef&BuqKNka*u zVs&tSIoECW{Dkh8#=(*jT|~RTeM+v(tXz998B@Z=Z{%_JeR>1Yu^F>!HyLGX7}ge+ z=6UPY1=o*pU#4!P=c6OrxpQq^J#;IH&{|K;tYb*2J`KlOVb6}aepD?Sk+-_vWoLIV zqf@M=bZ}eM4ogN9p-BNv-r1v@0{|CFttj`y7K=QqQ{PT%p%Os!25I5UvPkAyeME6Y z5JzVtVTo>-5RK`}uf>y#7%Qd5!>mKx) zdqz(9$EPs2-N zp~%dDqmwxZvhojnEy5!T(V>n10p0%7O@!J(B* z$(`U4hI;Q|9FYZESya;5N=n>Jl zuUMmbudl320@$$%Y}Kc^U5Dxz;^RAh7BjS76@6wEF<~EMSz5AG$_n4@WG)Q%m<94; z#8BslMVHm=yv|jz5PGII>R%oh&Z>3NL#i$VYaID53$L#XK2_y7cYqMRHkY@>Li8Ap z-RNz2e(4}5s*l^1n$4_7q@wMD-B8Ys=x|kRG^mU;`aAOE~BOD zB`0Oz$mOWH%)fdwl{VO#xU(F6_6iwesM`KI6!GV&R)v9~QmxN#z8I6RUC@Q5-vY6H zp;bUpl62!(VM3ZCEydaT1Gg0weTuR6$VHxUw+=O9W2s7uJ292=GeXaI-!k|*SSP&+ z&=NEm?cdKunR*j+SNc8va%%Kmm-XxzkM;Go>q!OkD?ODoEuD<# zt6%~5*kj0Scy0kv-@fDT*s}Y3(UD`uQ^gEJ!TP{l`Nq8)rJ{YFtr&q%)gV${#{gxw zFJITT>e^RcNttu+!kP7bIG!@m&CLe_b~T{?9V|;qo|-0 z5o-4N_7Aeu>)Kdy3T~|P7Q4kjgqn|W)8^m}FLOdC@O#=HrTW-`?cI#W6HS?3`w*p* zjs{W&vCSyr39s1RJD2k>icw}y(*g4RmHTfEWNM(__^RL0lFe9+d15!nG8kgYMik{R z=bux({`?e)@ARD7j&SJyybH6F`JFN_k@QLZJAQaQET{8n^v%M$o(0K_F|tG9OAGN9 z8Boa=o%Eojk!p*0^`^&_r+~^?_+$2VcHgQ-!n}W_Go%#()BQHYL8Xo~>m) ze)XC5$A+9HHoM#I6_;KaVzYx&m-3?9ZC+PI4~cvwo*}18XN-BU*@agQUh<9p*1iAk zK~2%J=l(k>tmt;HRWgJaTNXC#l$UR9=`E(QXMa(TpNQ7!qDB1@hjrRU4k_ARf43ms z!^`+n$jPZ)=u^6_?pDFyugBd6WR)H#NOL{h_%R3)_qe--EZz7;n)OJa0V$1V{Pg>M z0(wGAoOaTN^GC|bfqQ@(ctBq4UAn(P8>;5~GUO~8{(d6-d+Kmhu1m!|T1#htrfgb8 zFZTSF|GeiF&RyrIN1XNKwPns-R)hfh&mal_>VHQHt&17Kpy&a1&LDtXEil!RCGWF} zPBBE2?)%Dw9EA*yLgOOI9bZ3S3Gc9!tIV^gAuJ&T3wLQSEcUT)R;)b+ec_nJ8RFs< zB_6n{7}ShYv4lAj06~C{!o0c2d_ZIcLmnf|l9f`vrM%Em zEz1XBjHtaqIY$dCrP1<6F&QFx4bWeX^#0-prCf?QK=78W?`Z1r1Nw~vQ>7?i0#0VU zoK!;<#bq`C=@*YpgbGk5r+F571dyy!%rE8)nsy5_k=pbUI3SYS5JQpvAdu$F;s6w= zH?d@tr9)*#qjW?B6?x|SG8OScc@o&&aE7C-2W9$N!w~>J*emCgpbSlMMkX#7)32Dr zNM@omeQv1{Mw7a_G9q3F+t#e!D+=IAR6?AX2!cCL%&f;hrn`A;-F7oHZy~Ov4@Vrb z@5N8~^8@m;lS=umyKdZgPkP3xI~@suG`Wy7Ik}S+-=oU$?78kZv-=ghn_oBGK&o@o zdFj&nM*n06WC__vh_XzL;0iu9clUSK?hc-FIO|J=FypxFz~z#O&&+g*Bjb9*9)r^< z?w=H6Pbd-v6WYx4T(ew+UrE%={SA+9t$hmtDIC(^HonO%98WCwW~?gfp{|D{vtx@u zUqYO_(}U4vN#%952qv&-2E1j3IKj9NkOuH!s2I@~ptAR?$ihOJML=h%g$BWTe;9vnV3>*Ogyzg+wzcI8%ex(O&XY9vi zbR)Fh1ryfPm3NE)P3R1cEjf^*h){Zy1Vn}&ToaHJ!w~!Vj|e03{|=iy@NotJjgMRg z5GX(hy?+P9`vBqO{y#A#3~aY29V{w))=2O2PD@^@TQQ@5E>;=-b~yO_CX1!`c*KOLAbDQY-a)@MeK>6PaHFIbf;Bq`#Y= zVk6H!zEI9c`W1pgEBWF_smLtHXb`kwQYS!Z8tYK+GsbXyOGoKTD4Zn61cCXM;D0_1yB;zc~r$9x_F$4oyII25zE*+MhzAWh*; z_%YwlEtM#%zkUpzXGZgOhY@?K9FxtYtN2COU?*(K+nb$t$Om6ZyEqx+%_5qNj*E`x z@gJDVoeGE!QHYSGiIr)U2~yGqT91kC^#l*$rF=%GSyOscZi@&z{37~#x@>zb4ps@n z-)g+m9C!8Gp<9y3T7dCUOLo!~+bN0BLc=KI{<-2Bn{(QCM+}8Db@d&7PFfLximyXy zY98Mlt)7`7PX8A4h}-+eWOJi-;gt@`TU_Rq26atdyT0Uk`2)CUO&`P+M_Q=HNkRJM zIwt7pz;C1W7P}_`#mI*!c60O=g2GHrZpkBbZFcecpB)=<}87d}n71c=w zEc|`>FQL~WrnU0rH<_v$s;Q^<^mLV65_RQ@#z?i?F8K(g+%!h+Xsb=nCO6d?)x@O7 zjnP=fKd)Y&y!KdO$cUTg^u3+X+O1wU;m}mMnlq0yDIcyqM5BZ^cSPK6i7pFY;yQY2 zU+-Rhv29$4ImQe3WERFOsHJam|4vf-y)MEewkaBPd|=gbYxedJ1;3L9IbeUjF+&VO zh3-HG$3ez_CE|;`Y4krmXGfNFy_y{RY~{LzV8i3!(3m8M@oUlhHX+Gia1lc=TI%&3 zKXH?2Ikx(B?h8<{II3&0+JCl$shgiJo>Xb|+#_&nu3GvNgRHo2pcKfBB2dhVhvrj# z9-k-Bi*!|gKkFg=t?O`6F#8AV=a-E2Q{lxzjr3YJN-?Xv8AHs65+;rl_nsObRoO~l z;^Ku3Q7X?bT-3A7BcQblj7~`?XDfWKx!KOqN*XPKxCna2q>ci3-*6nNQMK!&mKUne zN5d;b;5B4$DIJpIzr;kU(UxD9k<+$`wLw?+DopMJ*u?U~;Qib_IID6FYQ6udnH8>| zvjr*bWI6sHdj;~KygzC+e!t*Q(k4o&p1ALa9+!b_l;Xn&4}<#P4{ItEi72*xMUF*< z)y{E@vhtGEIKL8l15R`A`!ilwzOu$_;)WU&)VAr7V2u&ouwlv6mXM5T@fU8jIUp2; zf6jg)zQ!Jt@&~vi;p9<{k5x(t_i$%www;gn=jTXu|5R?!3JV0d9Ft%d#0^hfnNjTx z{i@sgd08wjacWOPv3~2a=GGHblbuCBo?!9QeP&C)@wsv(PkwBTiI6Ig>Lbbw*lbNm zx`=F=T~V%Q%HHX55snk(4+i|i!x)+2z|Wan+m##N(GVw@9iYYsRJj2%lJ7y<02~2; z0R5jX>9+v@%!nWTe_xvL)5=9le4vaWC42U98WzB7AUo~$ZxuB#z>v~DFBGSP2m?T2 zLXywJc_p_c5^(@5qObs%jF4+r459?l500^EvSagg>=$UXzDMjT(~XtMAK~-1YUQ_$ zJRhpTA|X%;hyzaC5`bk~gBS3?9ZzgIVaTToB0+N9b30~m9G53n4lG{)A7f6U43LL|YOwF{DT^L~&>vwV zv(!VMA{Qbwa{;crEJXnwunvv^7MPhJJ>D?c`z8-{fH5nO|b zb9J+4ffb_WF?ik=*edJP2vm1&J?VHd@-a2f-8M4jAXoZXw9*?6Rcp(q&#S@R9ObpG zs_)@p^zw}nGnmSg#y$oFw8O@C`UT;?DyvFT@g8WRjtwQaQoX<{nxZu{eMspyW`k zhfx*hLMJeclG1HisgeG8bYueP&JNUV%dFq3Kg#gaO5dX0nxonIM?Ag0DR0rPV-e=Y z6XKU*v+Jp6x7seB`|Mdc`p{K1)Nq8~BgPf|$~)k!w;Iwk5Q&rEx;3Uo3jh0$*ZD7; zH8|bT{cFD!AN+|b`X0rmzt(^;R7QFS(Hc1ze6T~4%wGA05&hzZv^_- zTcwzjRj%uNS>5ZWaAtC-BEJq&h4C>7qV;d#@E6{}NFKYM&10)s_1aV{(j40>CJTWL vE?<7q4GWu!yr@at2OXmwTNe})7$eAD} literal 0 HcmV?d00001 diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen.png b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/images/media-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..a90bf5c565c2fa9ab07e03e32af91fe5e665d1df GIT binary patch literal 27311 zcmb5Vc{tS3`#*f%vtTS^U$Rb=eXE45Q<8nD6tYc3h^&$Qt?Xs5sK}HoNl1#UqlD}` zA!OgOm!03c&-eTMmgjdpe>~S**UXu--sfIk_c`}DC)(Ihi-DG#768DYqkaAo02m~R zW}-nOKXJt~uaTbsV|^3Ny}iA|!^6J*q2ZsS^Ru(->+8RM{o35!+uZ!y*4`s1Ea~eP zRQvVY^74{{t^J3OW$J2L8)I!_8=L(lNe^S=U%kq9iz!&@eEVZ?q^oD(`_x8YZc9qd zNLBKkRG;hly-Q}dlGjsG)>KqB<>i;XyuTS3%B42qJ@TqKj+}cPeFgxhWu5b9P3}UA z>A#*lmuHQ*Nl)75WBL&ND8D9fGbEis=>1R08&w@XzhAU@`M1#$&xMRMTt2Eisn|A( z%}B*}cU&Kg z8Z>xRqL89ZNHK1L9iC9ErW#X>GX-%ITWbGLS^s}^LduT3_w>6*pa5mY9SWOcrqR$i zFT~^|fV88~ko@VP5?K?fK}bTj45T%%P`XplsI8rCb|3;0`@>b&Z_>aD7?ND+vW+pJ z0;EN%YvTysIg;qPWo&50kff)8{$3L=?54HxM9hA$sH1KCBG_4_1*Pg0;DJnnhy^S zv5M=a%x47N0Ac1+pq*jxK6p|Q$qauq0}o5FMJq&NATBYWh*_J zNd8t;bR0B&{5fED)kT!{{uOb(WJT1(17Jof@#f^^q$E!rj;X;vz-U{A1ndm|+|HpX zVRIfx5+w_63wClxJE3fo>@T*pkl)i1#9#I4i4X=uC`D-nb0!O;98lC9YM1YuK=IMZ*-@hND)*{wJN+HJpCbjn288T_q|mzJ2XMKLnE^UG{APb`JaF(uIMm_ zkOQ}?h-!HZI>GpknG88*E_n$sFDM>_n;q(hX9QtZCQc}9C)ndP9laf)&;Q+LDY$+x zCfo)qTRXr6TXnMjL^ohbQH}9-?3CEO%OSg`$N14VxGoGA0JaX5Vo((xcpT0`-4%ja zn&*lD3)2}FI?A*Z=PL%t_*RhMnYJp7`&ZEVYwz-I+Xb@E<^}SzLfwHp;JKfju=oxr z_R$hnzu=*PclYNa%g)t3042lyt~BJn6HK0I%DAxz=$Y?&$YKT1sn^7c?1=ukViCJg zauF&rE0c__$|@ec0)_ea4IBk=GKC_B3+b?H(1w!*=(|8@_?!${z|7BGP;GG#AH*YT zZ2y|^^7w7~Z`dQ+dxH!p6$@Jf;G{Flq;?hRxf8Nb%mVXuM}WH~Y^#=>nybcl$H?0JAa#s5n6t>(sPQj?uO%yyE=T(v(F3B&0QeOl7?Zx^;}zcJB|)<#VfEwr1n;pDmNcIn|F&(Md2B-nW&4`QI>_eq8072}Y6EA;>#pCjiI@ z6rL`8bG|rC3pQO?5fp~kb43G-P=pu818hWVSFE-6uhx^{I8t3p5&fXs5?WTSBS10k zP|z52Qp!@-y#g~Uo6$&nBRhdzsR-B)YGC9_`;K~A@t5sg1$C}{pS8aJxyDWm+;$FK z+2IVmkWI^Y6+{1W_$Vx2mqPRUJ=&I;SV2S3&vGF73pA{TaKcYbsavvY`}{u}5B-UF zhc8JBUfh_L_LAB&eNCy*cSqHU_}~`AW(CM3LrTF0LB7EG>9|*Uuj7|Q3VtfNP|k;po67P zi_XnEjt^etVETKFc6US$RVVgGc@ec|f!_EzDhT1}4q)oU(X@$2D<$?AS6iVpbZ zpUWKV<-!q+S=#KcoV4MjM{{wp!h+11+g&Oht3y1*=f6Z+PKUHMXGvts)06E;V}&K$anymZ24%;Ovt3M$_75L51b z|30|z-XU08?d!-@2I628G#1HmESszCOO@){N4izddM_@@16zF%{EUhA4my|Zji2h9 zCqB*+0-AbHqwPgJZ_E*CN|wFb&->q>#k{7Q@wanoJMk3Pc18F$o7D+3U(PuyjmQ1P z%H@hrs>mm(##1f6srrjW^UuFT#l+?}=0V5QraryZb{GrJf)?m_2p1=>Fc9NjO?{w9 zKw%TcXwix*p&dTbe|EwiFI@-d!d-?jN+g7-YBo2DQqet-Z@>I8b@of_rb9M&)e^&# zhw-7xe6bRN&L1rMA8U-{1Y|uorJ;7qiMTMi5X#+r(UsfnoQ!9>dc!v5SDknG3z0Qj zKr=39EX{X5s@uPK8pB(7iLB=Bp%fj{*Ot$hDlV%3c%9g_(C4!*3#WWb1!-QJb|{K& zbMXr8!@6B(*|SIHevu@^)cpGH>_R|CNx|)>D4Mr6KKn>$)r ztj}!L_9$wl-m?C#SBgwuW}jiK8~D_RQ^*<&;JdW72so5M7bzdAc;{nEo>bhR@9zdh zJTSXhera(JSa}YSxrlB<4CFs75*8uo!*4QF#*FH{Dwh?2{m)m?MreeWmV`k@-9Tv0^Fc(VdECpRvH?FE7pfE(|IqzmA8Wvo zZsn%%E4yWVNZFX_IE=meCeak6i@99oxoBYif|a6su+C11+6?OxW8oK%nCiG-ga+vc zPFxfTJAL4#0L-G(7P|j5iOpk(ZNaBNu6J4LjIQ;Y?+(NvW6Q6V{d7g2d@n!RyM51m z?xgK8bpyaFpYbMr%W-M9sF)e}B zVYrjqGnAItiCHOYG_6jhF#$2cKod)LL>d1lIaOo+|H|1-%=sm_MV*N3cF*qCoDVF`SEYPjgP z$RK`uKVkWfNB1zd>r{q1wJs;qfuWS`GK456Cn3|Y;fGJ;vJBTx`5I2fSQ;6Q5B`3~ zmyGU6eDRT%c=5m+RYprmGD_sAhE#yO9UIVk;JH{O!N9@#O!42Iof%g2^f~aJh%|Tb^IYl~oC8bI3vWz`ubCpid z3$BTC4o=N2foIaRuIcJkWVBCs9bqcp&u=did||XN7G#XfNWc(O7yNF13fHIpF29MM z^w;V?FJ$l1wmu++BY#d?!_Ji*9il1nmTIjJ-ioXHDEH{2InY74x@LA0b%9_0g}VWe z>Q`(s2Z?R3RSx$RP_vh$e!m03DnTLss8`g-{2zt;N&Tx2=b(Hy1ldm-X!R4v8`%wB zv%0r5HwBtCCj~%_J`bWVc^%?I{T`DI2BJOy?|uxC@u>-j4|_F=I{#Ny)jjC7dLrIH zZt>~D>$%NH*o~D^_fml^Om1T+FHn6$?`e2lwZQm8JygQ&=lbHXddw>vS=HQy*N`$t z)41yGU;k8$lVV;B7Uw42Uxc6x`FT7QwS!RZ8{6S)?VT?$p2G#++XvoE9kxO{cGY6H zet&mu&B@FK{9K6A>2`Mt(GgepQ50(}t8#B|uQ!^9KHKNtqVAfp{bU&UlV;CJ85QA+ z7uhjYj<$P!tozCvJk-S1wwWEr-k@NY?YH2y4Jk8RD8zgIy%4BZ!h$T6=ltdS7 zG^=^Ncu_xNnNmiJ;jAR%PGuis@-LYdD-bO;u>3dhcO0<*M~-$9+!cf^g{jXDCD)@} zkHuSdde7`e%b7wO$2heo6M3TQjfQM_JD5O zqAp*xyb6ihgbM>4Z-x=?1E7RALTl-NZGWO8*}6(Bps}1!z44YWZWzntw^RK`s3>G` znpqlU_LaWpJO}*thB`wo4;HJJvW)WE>@1ioY>0&H6_1={)nbR&>>W`F6e^k$Dbwi8 zNx}2Myn;XL*i%0#&FFr*r9~ZJ2tG}r;LJ2edOn+AtXa-6np3l2+fTHUKZ;)lX*p#P z94>Lk5+j2W)o5PjdPqy$)|G>}pmIUb{8|5Vv|Pk(9w^J&Y%@#!?`2J>E-ZmJOo&z! zu=GE}d#5_?D1K#mf-l7paFg7$P0uYEnXKR-QH`3gBN=fBl%0Z1)7tmwbP8~A0BX!k zrxCS6eA8akr#tozTqUW?6j>hSgh(fU(sZ2O5WG(HrK`1!o$?4%MoTQ81dp-;OrjRP ziCAM-ejrLHxt+PBsAo9wNmU&^P=D))SIOzQ!N6Dx)h-JQyYaLIP4Fc96JP&ZAZ(2# znL8WKW=+$VL~|(LdC`1|g|jD1(z~&wMSThBsN;B`{D0I`e^?vFuRyQ=Cf*IbT zj33Di&=FuV4KesM_2;;d_I<(6Z$}x%cbfa;(|M)}b_6uAj;J}^0Rb7^ z7cFli0}r}?6Z((c?CnJtPB$RY7BaHcy!pAl{dSfg~frd4>q5WiUQYN+|QG!;gFd+K72s;Ix zIs1mfD^FmjtlB6F@k%{yvVV6D^<}{2E5bP?{W*)?&Nu(?q8;r%P~^i2w`QI@GL5q+ zYx})kYlL(BLSv>>RK2v|7X5@j^%A!E3U-A?w8;iX=wOGuZ&cq9)R9Shu0m#Rwj_>u zIvETwF2pW8(!I_JXSMg6ycFi=Lcjt?vU_3$SWOpo)EK40J}d@Dl|+3v@K!((H^BI% z`rm$eQ&a5P69{fTMDTBU7r`Z;H+gOjY(OeD1!>6HWBJzkmDaR4_{>Tyry*VV{4T_2 zLmbw+(0LOG_S-;$r!>K*L}6wvPZ|c1mXEY$<4c0j~XRH_EZBjZap6f$i|vKG?@4=H$$1 zDixSQkAiLP2rl)=3rLRdj1uL7 z=i{Lenn{rZ0Y8?1zS#vu4A=i)m6t~^4!QGPDeiqP-k#Yc@!G%F|8`^Z^89BH^x;JW zWM5T42pIkMH;#y4+%te={~s%Z|80>FifGe8DGO}Eb1$|{u~Ls!tF~fzznjv0CxoX_ z?x1+a)FA2kQc-=C_=Yvom%s>J(RF`FNvZNdr3^T$Zl`Xc-R4$=VkyYEudlPh{eHSj zZd6Xw)5Tp+FERjG^*oASrczN6Kqud)8JXF?!gAy$`AFJ88KtZFe5CYQrTYv|llHE# znwDgJ7kn5yxg*8!&uPA?fS$)a&_~Nk`Y4_?yidJ0b*$*C*Ym=uz9uIgU1fS|=#z)J zSi|)SUe2@A17SyqOS2B%LLGJXyXYS80F>g?!Ej9XPPtf1(sR<)mo?Mj@-_V*D0s)n z{Ft1*Pg-IqNBq~Ze*@L7gD|_^PIF=IxXuKAdCxJLX0`shB#n)!BSi8K@q|=;BPGn= z{o%>Zr?NIwdI!mL=NRFGG_Z4hOz=9!bH6}r=v=YXF=z07>@n`PF!lyNIg@ZRmj z-S%SrH-ToMvb22e)wSmtOCCKTK3~auqc`w;T1>}!wjiYaT>`d)Wn;FUmW&Q!RV9eS zjISJ#%b^^t8L8`+H0HWJ7W@Di_5=lF-v9HXlj+>U(y2>BI1G>bj4wcRql! z7gg}^GBLhrSV2d7sUM{cyG$sJQk|mvQnbH6e$6^uE0FD<)sd$pr!>@1oKS+pggDSP z+7X10DM|?HEQNVTtn)y1?>|5MD!2hxsi76)D=yA1J#$IJCcFwSEAji3Wr=|w0O5iJ z(oU=(aAK&U9n(Pcu#Ve*5mlxGP&A0kl?3GRN*qyX$1ARe1|(?juB}~HI}{J`@+k|O zS~Gv5_bhTsZp2*UZ}x3Wn0i)ar@C#RKa1(gr#t}VRv?$5^`0OcEj{YT29fQg( zSe~+8XDNbf^OH9Z+*Z?{-t8`{aPCi%2;JW+DrFlFUeByC{vckS4Zxl}xlpPxW8UF2 z3I#YQm-PGSAWFI|l-q=T1c0d-ARw_Ak_UtYKrl#(35muK0TKoI|C3P!i2tHBNN8uw z<4~DqlL?8aJenw_rUNQyB)9#479&GQf`6q%P}GGTE2Pl{MS0kjiLKzu!3X`3EFj+z z@?LJ(T&P{W4@jDHV-s67GjGqT@Z%`2el0^=M@{b&!4rl!uoo$hA)x7Cfb@q#`lF!) zLI2x7gcbff?~X&NMbm-e~4M4|Vh%zyr{uy+RLAD-8IA&o=Ij8nGutaqb*^Ek1{ z^c{EZm3hAIA2gDtL&`))Uwl!`-=BPi3i+?A#ANN!oi{~Q%iPW@;2ClLtS$ZIz@ zB2fQ0;pm_<|6_kQ#X{3rxlzW}ep|67Qx`nJOM=r2n&%iS(L zTfOQrc7)OuiZyP3-&+gFpq&TVJcc_@f2?>iw|TX75fxS0&Z4*L3f6f9Zj)aMQ2xKeYf)cMdTmca(Jw@e2Z0zu6D-&AHlaLSH9LMnC|FO zRe!eJ{Mp$c-ZUm4$xTOouDRyBw?R*+5*XItmCN?}sFqUuAYw*=E~6cI@>1bAx)^54 zuhwu7UFXhOMH|X|Vx2kyIO4IgA7x}@`a-aTYkk4NK}HZwVee2W(6-Vk|7m{p4cl=L zu3dCd7tum9ISyh`e`$Zeb4MXoR;BFx#L8z-@;oSI>3b=_4E-?dVn}J+Mm2Jd59xy< zlqBrH@!e*v7?hi5eX_nIbd!$!wo?8K_|Weuh5ry$df#~keG`Fm~>ExCET%hh)gJ$@=a;;qk@my zL5gB&Pfjh%9bP=>>9)GFT{q?RCntkd=IL~X%Buh0Ln!bd(hPta25kU>c@hxA3;J(^ z8b0>FtZ9WFQL-WcUO}&(9oV}~X9$&C-lZ?nzi#4SLKK>E^kl(Kwy<;u^yneD@A|aC8QhV(OMZ$2fyhjP{y{K{-|ZJ-N;SUDnFWyQMx@!{dj0yFW^3)xu*!M zJE?N*+&x~xUijLs<0M`UibM^TY?oHn_68nJ}7rnt(#-h^W4H= zp#nd==$hW0+}Jt-RO1$&ZShkRXvV=`)0|iKZ1nQ}C2IBp7=nB2B~Lyh(cXHt5H|Ri zDMVuqz%G}VGtLwP5B*dIi&re#}Z82stID0RF6uF&lD(9LmxvNQ2ka-Rb~;#TGW zzB4yHr0PF%v;97Fi=L{Si;wS7Z0B$gRmUnbIeP_zyA#_z57w%>2i?aa-rTPUqAH?# z8Q+;AALvPOrylY2b8=JT19B&*)}0|Hj0eyU-!!pL-n0*DDU6<%rqu|GbYPo&HRGx~ zm+W&Gui{(|5g(g}Xd1{_#|m2sxvU!>(r{yV#B z=zmjTCUEm`&f1aJNp@pm%eHczuRk={@KJPf&Zs*67QNuqqs(>f_jUU|{Ad3@I?ED+ z`$3&jA|-#FPlwak2Ml#4!;=sIqAm#>19}uk~Ebn&qu#<0pR4z05@obdo-*jLd zaPPx}Tl)cGIp>|>w#Sr7Sl ztiN)IBoDo*cFdKzTKjE$r_DOOAXoYm)xARTUMK2~@*VfnnxM>XD3A5G5rb+_=-J&J z;$ubSa&BgLRFjFi2n@oq9sEouo*m@|n$5lF@YM(CTt9eVVIZtX6ukU@ZEyX>?;zSxMeJZSb_Xj6b)JU7Gg!uQYMZ#UN$B3aS!lSG( z&Yd2d{{38Ae@Je3dR4ikK+~tnZY^cBX{bjtg086{w$h8sRX{e zO*)e9d`rp@(NL^F`J?+wyw>j+pm;SUhyw)YzwO&(Hu0-8?K3-+ zYu)R>sQddOgc60XoeeK}!&<=?&h$2KT>Q%NCxaA4H?b_^p1@MN{et&M`m(uDd{(Rja0}s|MVB2Xwjil9C;KBipL1T&p6;{w1@AF+| zY%!OmY>klZq-s(`HtY9@7-!PFFJkWVOPN9!ju_W+PxuII` zAr^mHl5y%YV`0)+ph^2-Xz5c)nt}y!va5#O1GI%JUN`FJV#uiSx?5I&hYwGzk{b@n z61JD(-`Nipd}hXKr8M8YwfYvV7`MMzmamSs9>nqU5_R9ZnTdU&jcydKO<++?=`9n`}BVjDPMmYHZd__ z=XINV4Hc9pU3_9hOlv-n6%*0CJhr=`8mMu99E>!LAqRc4D#YJgiwSK5it&l#O`TK` zYRYip*=l+3#Re~3-oW{~L2zUcm7C~AH%dj$30@S9{aNkk)hcVTd%eEN{nMv1SpVuPzkQ9Z^$$V93@d$>8y# zK7t&ssBqIkBe0|WX|&J57IM8)y4D|5@@1lr3SBhRd^CF}-v-ma zz~}*%Z>$-eos5oi{@#E+Std<;^{y!;$3oa*mq&58VOM~17*OYzsE)BU8T$Q6U~;ry zY+Nk+MB94HO1e z9ZCFH`qs*$Cg~Yzf3tXea7z_%!7omSG`@6u_F0n|yxQqtFkpIbxEPzQFE1ic#&AZ4 z=OEaS|N6mxyGnNT7hMl6wF0qE*!J_Ui~8J)=l+=UQq*fn8nS?<(Dp?Whm00lJ(9Oj zYy0xp;d|fuTe0){T=5XWkEJo^x#NXW{$<3`vP9scp7eEhbt}nKU}weL;YWp_MH^2cKG2p0Bu=cC-<<1PsuySJg zu+gM2EU)Cmec&ZkV_|J|kCbP>6@QI;Uvt)oU55tV(wRI(3}H`-;4w`O9$gha!Ny<3u}xkV3lK{5Rjki+)U2RNMt zUx*=2F5)e!Uj+>aS(UP201~~(C+4y8mi=^Ic_kMhOeiE(k;LdX&u;x~SP%5r29Vvf zV6NWE^Du%_BFaoL!mJ2Apj#0?uf1PpnUlMgpZ*{k>QGb{hC1(uI2~T}FK@+kYuJ9- z5IaY?6d**HNiJ^ok7Q;8rbQtAMk~k(s06EAX{x@O!mbQZl(pjzejQ#ZL#Io9 zEWu9TP7uH9PY{mjRKtq0e0WJAP**PLd}Qv4(S52~zgqm*xB)oYvsHY1?IlIxm2OTf z(-9Dxx)prp4j<%+eaYBk7Ue~b)vsGx(YX4QERyF=~b1x1@ zHp4}a4}RM9uiH16)8g(x1R-G>t+&QEfLY-HWT~xqwC0jD``;tetJU7=Vv$ex_8))x z@P=b1py11os%gOk#l*rtRw1im>@+Q!D%}PlZ{@vzHr&el{eE|J!7inGzRyu1&7Vs|}WenbJe@PtUIgF$f(sF~84n{{)Sv!}X0UKA;R^V3E^( zdwLl^B_Oh46q9b2u1aCh-t?=W?Kb%tz`|iNl-1aVe^uKQ^5bGI_s$Ied*_>ZyNMws zmt?lre$;`Lv$s+qGQJ*@GVZ}ruv_Zdcp~qOx`5^>l-;8q%YHehQS)~%pA<{K_Blp( zoMZ2ZUUGEhuOHwNtQa0ge^< z@>L`6#ofQ0pRU!rsjme@m3sx$d~^ipVXwS3JOj)tB*K03tH?G}zV!SxX9HKyBsv@M zr+>{-OfvK&b>q|DiB0e|{>YzT0LVCb#ZPUN0EX!HS2NQe9Ft!x4nUU0BAs#ue>d%d z$u;(p2Udw_?S}owBgZyadNu0+`9w)}o!K|OZ(>1(CKmlH)X>Wt7yImET{k{mvb`)~ z*9ozup$FO^`m^eauv*;ZJel94r+{qU&`Tb7&Y~HajQzP65%_~oA)?D&UaqEiuw^_) z?Z70bac9M({llT~8`rm|9ze2l9?7J6yNnC{aS{8^Soog;NJl+=?nUnyh`3X3 zveR@F^c1Mi6{C&g%i?54I#rMBxvlM}_@%TTd_R7$Zkp{2T07_x8duUPHL5j#)1${+ zE=__CqMqvp!vP-+T(YVNyY@V}GW3?)3*1euo{yh>eOPyC%=|93)fFeL&2f*@OLG>L z;e3?vXTYrNGP3Cj^No@%0h9?K&o&M4q6&-$-L_y%``U`a95{DCmn%wRX7e6Bpg(mT zRHmkhZyCir2iy>o8z<-;fzBTTu-gyFCHrcjrS#jwS6rah`Q1%C(LX4;x3ybWZHbnWa45zzUgguqu37wBOyV^esJ$yZK?V2ej<{|%mvfUWcgrikh< zpd2G1uz`8c1A^FmK+Jy)@!>O2SO7gVu%O!_Fl2iG5honox*^JpHShuXS3Goz+J&G8TvgSYfW+_R zf-XWU8c4ptTavLfe}(zrv{(!(0l~hv<85_+KoQx{y_62zAR<()i4RtEEn|p!Ks0H* z6-Ct3d5d0Agc(ds=5L!^=|xKB__Dz5LCCQLXagJq3dQ1&m|D|a&b_gr1$NA!^f##N zCUOvNLkK0dxuXv&ct+XKq+{?0g@NZz%wQ47U-r;iU0p!9Jp}1P@Q2Vc&aoRO02k1# zsW}TutXVoiL=wNQc}9qHV#G3>J~VT*Ai+RlsK51`)D+ z&LXqZr3X}?7ZdyEF(1X~34J#m0AUn73{ik${u8ib(+EZ7_0;Z?A6$CFDoa8;UK?@L zMn$Z+#|%L3c$kk^>5M1NksdO(DUBXkzVG@i(dg0@G%w9cA%c74ELCN=;)*gKHO%K| zih_$r?kcR%C&R&96m2u%Pd) zPR$v>^Z>mGf?rn>-L6FE`T21;1DGks3;4c3b3K^TCQ;%3%?iUbwK3Js1=^#RAKhS_iZn4X&>mXnD}#Bg zN(!1pP4bk1b;}eTu8@+HoKu<8Tv@s5?$yiLL_k zstgR}rpN*&!Hc>`43xYlh}~Y@S53yaXRE3_g!w2(dUH3#x)P233YYHk0%dT9n)2y* z?Y)NUQEdBchdng1e`kfk3@~JFr@BF%Fp*IYY1bSDk38gPoK_DS=vcg0escr44oiX$ z$ccg|XW+SozOPTDfRqRQNvsU+cVIE_X9qnP61Dq1E`%9L!a!6Ze`fiF^F<8Mon_!4 zc~594yv;58~HCvC6%k`V7>W&@eUXbJ1L(7MgI}*op;3l&Rzz76)sr zxs7;|6=E!~uj~iF@(BaW`9BQ7nWQVeqOChyK3%Cu1Go+95a48<0ZV7uA;19B^Pni) z#AKPHI6c-R^uQ4M9pghR%ZLNQ(}6yShKlk|&oAeuE9|O;QkFSU#|)A#pgLM$diYBn zIs`eUFG7zABj)h{BCA7`+h_2`^(X2=o02bw1S?&j9{U3cWOk~$P$O{hdE&xI>tAJv zaIWJr9pShOBYc9IzznqEW1b)~0`<}Q-VN%ak3B^{n`>-vurP+w83RN;lor*~)5nzo0`i)lafDN#h{<de&G2&~p*dHi|7UiKqLM%fTL^_*|>VcRDmqDqbYn{Y2RHQCjhH} zSWsu=oWd)&@mQwh;i=o&Wh&sV{8+k6%@Kft60j^Kks7|7BYM7V8_!-?!1u0Fr{Yn? z>6fV?CM`fvX=6mhsKT?te|%Vknlv7omM#yy-Vlyi-w&REnM^voNln18;^BGE`)?Q_(mpmnQq*{VFP zGZQ`A);Evt-_XTMjteyJ@+|^ zGC%9hsp5l(cfx`YeHEudFh$P`3c!}K99AWOgM8tNkF|G|_o#M`w+Zz2t>7W!n^b!N zh?$5E*+2;R8B%oEwB2grLJChDM5cT&w2`=?e8>nf|;Qjez(bt$1~+ zV4P_`O|2pW{@zGI({mCQZ#?fc9Wc=MiX{NCzO&_Vy@ z9v{VHr@QLo?~MNWWPWuf6yh%!00~2+vGt43+Ef>&qq=^RVr~Wd)Nay#QoEk(N0Y!u zG|-E7v_U*=e#-5KL0KjTEdhVFI&+=(gl+24h`T@$?+c?8Wu7cg>FiyGY9xQB-&HIO z%N?Y>e`o?0rQopB$OMg-Lsn<27RnWRD=UKC^3?ZdKFrGGS*aCTtL>n>Wx>+Lrh%i& z5q%@lbjuXAgXg0a)eun^SosLi*~ zAZ}H?{S0+SMsDCp@~9|HC3tKA;_X}d{C$^q zEE7FY)yhj$x()MIDlzRCBP24t)r-A{KJqQ2&N`HQea+DV}!Svr|>wQ2$c_rrfqat{NT&z+?r$(w|nLw8)TK~9)*Io&O%1H*L} zfyqLJb>Wqo-REGX?+^7GSGWqiQ74$tz&Cvmj}5;mmB|52gU#ohQIuB^o7J^e)LJ|tHo9C204gm?A7tKb_d>^hdRtYcoJdD&l zkrw$j8|ne@Gb)tk_cJi-W3W;of<6ImU{WiaE!;ADbmUA#B^uP<)jyRYmfd!mFc+bW z0hBWQ0W}uv1?Yk9l0iL`%QU{RpTXYUN9Vii{-Hiv;(*!T8=O7^Bdm}+9m7YFK?9EI zl*_=R=d*MUA22^LF8x4~CJrHv2v6*Pj(gh3S0ql05XM<2%HCoh-=wJD3B z?;9SLKph8lRcQBW|03%z$S&dZ!Fq%swek7r$6rc3=KasW+z|QWUnylkMLA&$NU&W{ ze7PKc!*sRg7(jvJ$@#dC1Ki-L;h$qz@;fBtkpB-oSJtO$p-Q}U`?xwjMeOfQ_Of;R zGuPq24ihG%xd$#r^H0&aNL6G#YRP`rdV!HbJ>kvrm~IqJa8kSwdsh7eH1?2{2U)sN z)$zg%hzy;O)eC6U@NaE7kYNSyQ<>r0=cc}gPEDUd7KZM;OpcrwW%%^Jy+A0CHG>Ds zw}%8q4<`>IS@%+n7{wC+Q=n9VJRS+i-e+AzY9Ux`0Kv8N%`5S2E7)S7J}!bHi{++^ z6#&ozO*&68E+XQlfGzcanW0RTILxX(kD27ndN-HvL8FKFNA5Fn+KVhEScE^;K6K#6 z^x+FXNlYEs)%YvR`oS?P;=Eu{-4b~x(N1L zuAsZ|q%aWqHy~1D%xO=LdF~Wka0|L74$HL?LjCD(*^-KH0M>^PVX|%H=oks!kq;9_BG*Tm^ed#Ej@y$?c z7KC_VAWwgcEkDY}f9Uu=C!TD8oVC!;VB0H}QHE#3v)M~&5W-jiEBvIy^a$CGxI~)w zX~E!&Yr{1&*0x(p@)Z$UTVe+Vek9@hi z?SuYaoF{&7tLw+P(vk2K3`uz!L|9cio&q%MYPCikA4b?C;u$$(ufO=~in;rUzZF90 zK~IA%C+TKd@Eko)SMB}hY!nT-TVwefTv!zq%?sz|{SzFIEH$Ow?eD52D0hbLzAWp6 zicpJY^r@^YPoAJ>YjY$EM`xo-!h2eN>UdkiV2KBmM>Jg>Glpu$g`hH z<9V6$Bz?x1Y40DJpqSPT>QRDPAs0dj-!Np^F&^J|8;>{}3l?&%>N%;N@6;WhwVY1F z8c=p5D7)msfpCE*u@ve1TAgR4OdRcP6+!-$-=XbS@7zb}D_EPXh=Xsul*3RQQN@!T z;Kwe7TxcQzV8elN9F-*=FYot(y1mt`dfF9iAAV3b2zicPiHW=51)iV>I1WP;i_q}g z%$5wJNXI20Sf0u%dVBx+Xz2COY)~_L7;M6`mk`nWkj_ZKtZ33%-lmEeD{L!$0MON`|IpprkP(ojq3!(&L zcRXVc3pMD7mw_P?-*N9~=K8^VxX)KxC(58UwJc(EcqVK1%03HwYdagsP@FNA`QpFX z-3>R{KTPBay_fRw7^P!c$llMA@HLY%p_*AaDA*HO<~(C0)*?8Mv&U-JW@ONUh-XM# zYZ?>?FcB{A`VRBLg^6e?Y9g&MX4U33g^9pG2oJhPGkQvipH0}SF(gQ;BjKYX=l-?Y zhCSAer-00Ju`a+11WZT^e0zzdJno&fG1&-{A_j?F0#|4zBUmoI3{5}NB9Rh!!93zn z6gnEL&JJ9l9$v~wU+#upHs`UD;cAAiP>aFTU zm@TeLp9^SU%JnEm1OitCtisZIm6DVIc}7;lNn^U%J_|9Q){qw zf%c$W8aT?YIGv;>rGmZs&$N_tkaI#3nn@b-kYv$e0SB-JWaVB+Jvcj)AQorU)OCc4 z_Am?8GLr>px)Sr$jHbau&J)ze^;?B2X7MWa?!fVg2_Jn`KhIh&RokzN43*jWQhVW8 zVm})p@~#y-+;>ZEM#c-&)1{(eU*Q;@_#I5%=1gVRdUcP$g_j_<0;4isq9~A5(SB?) z@a*1Y+C&5Dp!E6#Er=wx7VHZZi4#4h?A)_>`yt6>@bxUeBUOR+e&g~5C)v>2xx!ZbQF@dWzl`l4d1L96bN<>Fr; zXfFm?pV?ZD-S1Ho^}?@ioSur>T9(A@VI@H?dS=ds4Z(?-1?ualj!o336B(U=tU_&u zzQDmxe2*h)!Run*eam-4jy|hRaF9jrFGRo0r-dtZKtAireMNT>Lf6e%%yvCp5#?H~(t$D{@0sxn*wwt)1~1z9#~5?plRF-Mn9eqR-?SOpL+b;5u%aJ<0{)L!W8P6>dlRPW zUJCH9VZHnDI-yennKmW5aLy01i5}DqVJL0r0cut-@OP@UCbsvt$`^qOc!s58hV}_H zz4j(fPcumepGaS-kz@u#i94r zC-p_YI-zrqlV6jIz;B*T*4dhB#Gkjh{*#d~@(GXsjk=HAgQ)s4kbE>ZwEgE<;=)N6 zwWq;>_5Rdun2sa4cjIlx-p~R`B0G3aHGB^T|ACkmp_t65D-@&aj;KuXCjOvjaxKP_6ehiLI12p%+ef`)kv2G3Tf{-x;R=wA-_$SD+f zADepn(eVMgs9E!-=G9xV(@wL z$R8uAErVp#ojRLA53AZNt@ra(i!mDIF{`6t5#pALa?xP zT*;O4T{;kh&J_aU2QMcqzN!|eZ9{ew$xmupE2gUXmwyRG@QjZ9*^18i+#vh&+%;RE z)idXi43QH$#A$O44`ZIbx@oKzoNoE*N_w`c>GG$yHILq)nT9aNR3ujL4N6_Ls~_EC z3)mZtg!G#Q$aEl8oU})N4g>g>-8p{xy|wn`aS(^RT>Y{pLA}y)5B!hLz5^P||8Mwv z-HYtK$8BY0WN)|1-c(8nMUjz=DC-J^2#L^7+)2pZGu&ksA!J0{(y(XtdawTPd*0_c z@B2LGInQ(Mb3W&Lo$LCp&v$(G=QfJwV4}2GN2hy(d}gBH-l*rR`d!gQh-7%s>#ar$ zGoisRqi?2*vxABpxjx{1?EPnZJHNC$3K;<-Th4SyDou9{Aol?S9W^TBLD2{5tajr7@#i4hbeJ;8%5FUr0vrT(2#5iq6i}(` z2~`7DKG0d8!ldJrJO3~(8gs+$-M2U&kI$fHk}2K@@91~GhAggv&#V69LLY$#SS2P)TTh=5=_g2fcv2fSDl-wPLg3VwkfpEW-QYiVvY;NQh1HP3^> zP4JnO;n+zrr+y%YShMOM?pZ9(*Y8bTn_C{cyz`Sk5lyyHT-hJPsQ0b*R_>p^4Jd}> zQTPqW$+k&N0B`eE-YW+D*i51qJS;2nde7iWL99U=@i~acI=P#0sIz_WRRL8jvdPj$n7#@+>vzJrVNdq-LDCoa-G*Co70@64 z8M;~QqVLW9kT(5W8}7rmwZ4 z;-GdeJQ@Hda0X>a>u}!!y%73_DbE-xR=Y-g3RDdx;iG6!2o4Dv8TzVFMq8i+f##Fw z2qgil?FN5DZ}0gn{PqZvzeD5FLOKYrtT*k`=qp8S+azp;GL!h@d-Xuqd%nh;uKUh! zGk-_lXF2*%tZj>BsQJ#sMo1<<_z0XUc^xoQ15{)w4SEu0#qJoW&<@~g-t`Z-C!6<@ z!mjhG_H(X>LflY+lA~^&4bXU!?iTxcHI|h`qru!~10RT`Wb2=)M${Y$fAFUi7S~eL z)ju3ckNkXnfi+wHe%SVz-;6g>R+!vs=^dEP12YucH>ev$&bpr^qIS9ApJ%;pLHOOO zL$$Ly6>bWEw<#&j_W{4q7Yt{Kh9#T0p_Lhgm#C_)?e;1^p zPF2Vd{&2XL!V3EUA6W>=)9{Y!1nu+Juhe)L!kZ}iOd`UsMY?|iDA3|_weQfHF~h9zF%rhY zk^m$&1|}S42Tt$bUzQZ9*}e&T)u)iXE&i+DfWy~5*AmXa8M>wWBL+UNGO!S1mO-k zg>HflXWvT#i@_hl2T!HFh+`lykkNxIY~xV%RRo)e!x~=N!%pR97e|e~rkA{IK}nWD zXhtzNXGBD+=8P`!so{!eu~a+P*iEb~`tR5Gw)L}FLnvj)aiIMRAz)6XVN8*5pyi@; zlN}eK)}ht}B%)`JQIV@IK_( zDOlJ900HZqi0uDD@RrMcOlDO2JRrY7fm7!nco)S{Q}<&50fl#^gqc*9dacx0BUnj1 zCSZc@?czb@khhk|D82%E@udw-2%9X>DPApc3DR+-C!ieE#BHG>aNPmHzDBjC#Hq!g z?_e<4j<5~IFduPGu{gm?y53OXsQ8ayOK@ybXv@rno4O=3(6L&IATbq8Ou1b$ zPFD+hWw1Yd#FPao2NU+9rLldISPgRKL`U;JE>&3}mif`f-3$Mk!L8N0#VVQ<5!h_) zgsPzpZstbT@3QHJgGmNXH7lAuV@~Ih>vX87OQ=$m7b1z_12m0A;RJFp`XEKu>lw>Y z(K&E%S{Os3_?DjCDb%8iI*axCdrDJ54i}UFhqKE*@EiU*N}H`CJtfmFAO>7{7c$F= zQW^FS2vGgmRw_ieMWwdhcETnIabMtISt+HTzgy(#ciSJMc0g@Y1Oy$bU_s$n)9{7<(JL0{ESetg@O8Qm>crb6 znLxmP=3aih!fhuD4o79Of(e*x=F?6ET5*dqn>~a!M+O|xY@n|^0Ft#hI?|W19LvC8 zTfmWiRis?9yNMQZHNnbQF&+PUid0H5B7bTmin>z#>;39D|E;=~_=%3YZV%k&T9}9j zn#P;YE~Qh)&!JvQxAIH}?hiiJxlT(yI8z(!1H6net))*CuNr

    HM7dage?7s4bd{ zDfV;FlbY!o6v+u|e&SIZs*Ae)^4-&!1_t4aE*CJ+Gyby zxqAFb3lKOfqN$b22`2PL&USj>;FQ}&7(kOJnAsc1+$tgUbmqddTEf|vGuqDL6fUQ^ zZ*1Lhec`kX=Qq@Q7wGF1#*{t(bwkb#EO(qc%Cv?PY4E$$ z`}RYjk2K*13}O%g7mwmonwc2@2ORojtNqFFo0fPA2r(KsM@jA*41 z1@C_bNc>2OF$XYt=&wjp#*j=Q^hn6T);uf3iy}XSA+J^bT0!1#7Jr+#jVY#_wEA1B zl~ZN{0O!T`w}XH6^1s0^`Nf!N?thKqoMDDL5q*KPDS4|)D#IeUQ0uaQ8c5zMGd7H#u5LoG;g>wN% zs$M94fp($Ou+NRnHWsjeCdDq)Zw4@z9=|xa=Cm|7dF73gxW0cZ39P!WMt5OPZ*h~V4Ow=SkP|L$XI%m3{waPyUlL~+hiUek+-S$UB zXFly1*q?O!fiOWx!)9dX19#vX9>QNm7jM-3@n+-3(M0Ag8xI$?scSU{{;tSWOKpn= z$IzWEcBi%T9&Rt1lJ36CFLQp)E~Xt7lr}04^-khG%(ot4*5# z&=BR0pL{q0KNcp8S4BR&NzPP+O-ris7h*Oz+RHpTUiR)rsGf0AOW5rnpvN(wV0Z1U zOdYA4R@eUtIf=o6rT0L>nwhbgA9TFs1aoa+yf&{fq_9%YFF8Xcr;o;_`^IX`ml zPRgYZXy<#2w_nqF_l=f~Kh~LQdRh@)g5*ZnrWDR`6-tU3b509*AH_cJfn4j^#(iq%^13_3!+*m4^Ebfv{29`JRs^ zrnj*0H_t_)jd^vjmA&^~f{WMU8lmz3vP3- zK;A;>#4i5x57E0u+%Lw8_zjtWqn3BL*n?zOH;=6rwMiN^Vr7Z8hq38U<}am23~cwi zI{VAL0j)*fnkUrDOE>l%YS}k*T_)@rHXi;J3b-`uRJK7T0aOr&y3>>jZR=tmkUkn~Kj1cII|1OjM!} zNdUyohF)dv+mt~QhCGzC;u1qRW-{JzNpz(p*Jljn;(wd81m%)(&t^EH`D2`r>~#3C z$Pae6Y!{!OJg-sxxrakOA);ka)^wpMvRM>E@O<3CwtWKB3Zb_h*LIyjtocz{K`)ln zm%Q3b0aHN^{yxA&->ClegkoCJ`jkE}DNs!3`&Hncr>XDR_p-ihZ_o@%FjiL8ruFOf zjpDnwJf>h;BV2Z}H&qHntk8YJHfwD`jZhV8G+FvdG7kkSqHKO|M$8%UpwQw53m<1p zKwb?kX~iBD|I!f zsK}17olig)e-0Br@!`{+S)?Z1tz`Qp+i;Vq{Gn6RY{nI~{TxwKd#70|K2PX9?_1ya zwaMUNxs2fEZq-B&E>&ayenEjXL6F^_m}Bzo)8CUqx%#zaNv3IhS66EZ&8BOvFeGL{ z*$`x0kI%~g*_~pf*BD4m=vi{k4E55&c3W^v<|y?}{Agh#n^D(EIb&^^(4~8gyq)~V z11n}v3;TxCDD55OBwZMx30!|sC^gPNLteQfsQxf&@%8iVkkNqjPUX{62Vvvw_N1YE zbU^OT6TG+Q-NWgqfGE~y5Dh=%rw07^Jlz6bd|SVkjv60t|RYAe$}^ss5_ zn{HF>pE_P>YI>3qVHgRYdUItCA55RtmC`q9^a(D0@Jha7ZeZ4IUi4MVs%4pqHje{6 zxJ*gou%Wyf5DopMRXf@X^Q)78e60A|(|HP|16rIoRw6L0(Z1}Gf01`y7YY=lb?$;g=1sC(lYt#t1>DRqce ze{tjT4u{ypdf;~=U`B^g^&$9B?2l*3oEs_@flX5RwTBoyJ z6Ux>7sAnuS_D^tG*QGaXZO>ck`6-OrYCK#chNu736Dt$4M&ur6H}bRiEalR$r^LN2 zp^}0U7UysO;=P+q0})jZH)(Nzq=8%M!nV37(3%>4-_Y-+sd!XfKXcNa?@=!ss z=$8A(vnag0l#l28H%%r_KY;BqwWEg!&RTF5EPF4HD+L>%#YfX|aI`b+dO%mEDC2EU zg~zq$oeny7)IDx;ilJ{VJ#UGD?5|$^aBQGcSn6rw&WGX1kxU!8a}UK{d2yzccIO|s zq@Cpo7B_O_V)E51L}I-WWD`faKIT6x>R6DwI5PeMM-Vq|TotO9^In|ggO_`{145)A z2Aly?s)q^le(e&IV45G-SmZi4-5ciOx3=u3&lC%!`7LxYYpW=#AH#8)4Ws|c1&;Kx z%7KnHv}ahFxxn!!jI<3I8lpIh2kRX`R*oQ%E^4*aTBoi41X#2VT$p8iO=JKcUGjf$ zon{fte%e5J3~nr)MkoqQPuX45L zG%&GiU9UcL0t@<l>2wz3;zgDq6DD$NP-|k{lrhl-PZ7aVwG!Dy(-A|`^kT1 zLD9{>o+6=hN1S5a#w5_*vUTdb{n|U5)4-sKVLm+thlj|BV_^A$>h)_kj4y6?A>8EU zQBcbr)F#xhV-@9T{92O^c(+?KtBae_;L|4!K*W7F>kca=;ZD`lidZn~RrCO|_&ql8 z3Pg!O64R?_Z`EVS=3zyY+aXThS4d1ihU<4eL;I%)fezCkTRw^0TzPZa$YQj0@AyYK zE@W{^4ip?H0Stiujw^`+LJC`MAOa8oyr&4R9{>Bo0f4{w{%-)!cEn2&;XVEhe3wK# zHGpS7C@(n*;aJ(=76K$%F8J_XGCP_bcP;TwWVReS8N;$kV_J2mW%}JAP0Y60)0U{_&S=w0V&I&XSmw= zkU5OMfn1Kk_Se9iVHE$BceM2Mqf0CP4a*~FK#u2vuN3`QNIqY{dd#X=L0oa@ba;mP zsh?8lnL>P5kdCs(nLDZLWOalS-hPU+NE1G(*mhhwT0G6*WBcIv4!VaTt4BFiEtV%y zD^~V5Eq<*a=)*Xx?kx_|b>TMTes69ALuDm&EM4DwO%_A_&+M=u0kjEBZN;m+jS&Rx zxV6ULv}AX1qW*7OrT) zlV}*~l+so|O@Zz-UD(^V)Y^W;DaeG{}(ZQNRfyt+@|$n+zd14SXq+ytk{ z?G*{aaaY-EObD^uzvloxOteUkiq5)&?AI?>^}lW#DKqT!FBs?aENnUVGaI-4S#G3~ zr64$6a@CqZTX+NBj~c&fkqL>ljpsogd#y|qYJUvs_R5cc z-?;Osd}YT~^3~)RI+Yeb{ZkjdidAv82sOGi&|I5>6uv68*@@tysr2Vt3b+>qR*+~- zSbkdk%Dh2P$Keev>IBhKM+wTW=7tXiOds7|HMag8TJxdlS)PlCU?N8*cAE#$esox} zG=6>8e|t0+vad}26~zB{+qpF}ip@_`EcK*mHPMrgMjFDCAHKxXyfQSMyDXb0St3n+ z_sE9jU88~8l$q*{&rR=o^(mS8p2rZz#(MwJv0sAVe_&4(+XIvrGXo1!CW0VNN){Le zuzkz7B;^1R5jKwwKimKo$Ou>vp%@E81jymMMJQpf*VF?2|82`!QXE2 z)ZD@mDY1kwSx_Ygn2=fs+kkZd1c(Evh5Iia6RC*Wx6dF-aKuA1<6r&!S2h0Q=JTIx zjTt|`lV%BU4i1Z4Cq<%bt2vQTJgmAbI50T$x2X3e#o$ZI-x3YMlnOsoq00eVQ;{+n7xAm!qRY^I2-oiBIrn3@(2zkDP0-cG5htMOl-IKCL$d*VW3l~wb0 zcl39*OpS>!yZ9sRJ{B=fDuqGGDf=3QyBCjsQA{lK%?I2zKqPK`3bz~^$hV7?v2>$K_{!n?La@U? zPhLIF>XF_>VJlZ>xAt=P>)=(L%1L7h^6fW@xiv)((1G9Zh2iH<4VqoyF_Y7gjMHfK zfw+EDIT(BjPw_4En4a$jA8UYFCX$yw3nbVCCV|bu$eLS1e%-J@%#!kPo?l7sxxZAV zTdQo}#c^I$8;LSE>AceWCTZUEl30f@Dr$F*vFLG5XT8J$nR-A*9_;njDx(NYW1DfY zBeq{M+VkpSwl%HPR`OgP^JMwGB=X9Qy*NfbC*)@d=tbZ+mMU`T*Yo~KlN)z!LL+D) zl-x0k1?{Y0#NVVrW%rS|vj%PV$~ujMws+DG4RnAdYGro(oCz;;AB(F@agJXsPJNGy zn9qB0{*taZL>Rwy9Td2PrdJXW>PPkJakOGbZdkt_cMO`)ZX|7BruGZSb~|ARz5P|% zNVe1rJ~^})CP9Bw;X!UqO>WS{{VNt>^QtRN0>HmbPKMoAnGxA-tivAJXF%afYslrX z5#6)C8hgqQ3qk46HhRYJqd=6!Wg&2e)*@=&cqO@B4;0RXzJL}=m|%B5b`)Mg$pGV! zC!?K&DXX#&grDCyN<0RRsNO!~B!#mQyhimzfNn)1BnQ=Ifx{V7Qfaxq2vCz2X7F*G z`(8?fAEuS=86r8>=rhFt_R2YsO@(ef#KWJzUP*&YOlgyy*epf+1z^cWKlu_K1N6l1YU=6hIp(tubfRTXV z7}?iZ)Az9%k1-D%7X$Pl;_ZdyGeFV_mC6J;bYXY{-Ap_%L{`?Kvq95QiY1`oiW)Gb zk-d&WV%(9HULghoX-2rcvyty>wd-}_7VFq`&%GEF>6eND(RHll)Dnx+#(SE_IVES9 zIE0B`s37ET25x5bV&Fj5Zmx?7xSUE&xn<5$Dy6#>x1jF~)@%1nAqPbxqg&E*homQk zpDWtlI9~~?`B-q1s;JU^87gJ#xN*@x8hB+kV+nGo(zs{O)TSKbPN{c$oRMU(RF@L_ zHc_kHi>Z1Y+DStkM|)j_crf=Z=;bLPQUk}XSUMvq@1kVg0OjC)Y;KO|obZUEw8w>e z0`MhPfcmMv3cR8j98l4@)o34uXstvkB=mxHV)G~4*|!ADb)I1Jb8y?81PP6@$}fh8QQbW#lYIota4VaYOI%qn=d_vz(+|4B7JvTd!wXqNg?Iry#+?iU;V`k zsF|?b8F}(~#B*06_ltUz#{qexG19#OWO)C{jv4)m>-Y|T?Z&LcMijgKlXGx-zG!~q zCyfcXSuy0!U!q2aq{APtccyUE4D?+OQtY{9`*GPw?jOPpT3+vP^3#N_^8rogzUVs==7SXEAM zwqk+B!=dhbGpXHnVdfjJJR5#+eqo+s0PcDUuR+GsU*2`TWA~(nN6*zxWUX*r>3N62 zA8OtE=)8zBcx~$s1r$yDqbxeL0w@XE*wSrXz2Vcq&$E`1;8jM)0tA{xpu99pW)oM8 zxWubv8?l0`XsWBh9s-v|Ko#c&I;b@`g&WGN(Xs^1Xv9;dI%W*>X-J_?@8&z6hK|PxO3)f+&LC@7iy=KEIPnCaC)Y68WL zrwPC6!hC;a7qD;Jan9x{Cd5PzvW=%_c`L9C~pCy|5h5*$ZF6~K#!qPFkN z1WuwOoe6I7X%f%X=~S4WW_8!4>6RWr;Y`W`BmUf!Bd&^xXkIjqsF^5&1%f!c%o*{L zpEq$59pNGe1sCCQ5akR+5{L;ISs-%{Dh?tMEQ_Bo99m9Dc#2vE`9njz)fdGN`K^ZhuEz3m_u zd0Rnc8-!>PMA|k8(ISYfgUU9zL3G~iirTR$!ut=`Vg2@$Tljkb0000

    ' ).addClass( 'error' ).text( message ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + } + + /** + * Hide all error messages and fields in error + */ + function hideError() { + messagesContainer.empty(); + addLanguageForm.find( '.error' ).removeClass( 'error field-in-error' ); + } + + /** + * Style the field to indicate where the error is + * + * @param {object} field The jQuery element which is in error + */ + function showFieldInError( field ) { + field.addClass( 'error field-in-error' ); + } + + /** + * Focus on a specific element + * + * @param {object} field The jQuery element which will be focused + */ + function focusOnField( field ) { + field.trigger( 'focus' ); + } + + /** + * Disable a specific button + * + * @param {object} button + */ + function disableButton( button ){ + button.prop( 'disabled', true ); + // Because the button is disabled we need to add the value of the button to ensure it will pass in the request. + addLanguageForm.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append + $( '' ).prop( + { + type: 'hidden', + name: button.prop( 'name' ), + value: button.prop( 'value' ) + } + ) + ); + } + + /** + * Remove error when a new selection is done in languages list. + */ + languagesList.on( + 'selectmenuchange', + function () { + hideError();; + } + ); + /** + * Bind click event on "Add language" button + */ + $( '#add-language' ).on( + 'click', + function ( event ) { + hideError(); + var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex]; + if ( '' !== selectedOption.value && ! languagesMap.has( selectedOption.value ) ) { + addLanguage( + { + locale: selectedOption.value, + text: selectedOption.innerText, + name: $( selectedOption ).data( 'language-name' ), + flagUrl: $( selectedOption ).data( 'flag-html' ) + } + ); + // Show table of languages. + languagesTable.show(); + // Put back the focus on the select language field after clicking on "Add language button". + focusOnField( $( '#lang_list-button' ) ); + } else { + var message = pll_wizard_params.i18n_no_language_selected; + if ( languagesMap.has( selectedOption.value ) ) { + message = pll_wizard_params.i18n_language_already_added; + } + showError( message ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + + } + } + ); + + /** + * Bind submit event on "add_lang" form + */ + addLanguageForm.on( + 'submit', + function ( event ) { + // Verify if there is at least one language. + var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0; + var selectedLanguage = $( '#lang_list' ).val(); + if ( languagesMap.size <= 0 && ! isLanguagesAlreadyDefined ) { + if ( '' === selectedLanguage ) { + showError( pll_wizard_params.i18n_no_language_added ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + } else { + showError( pll_wizard_params.i18n_add_language_needed ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#add-language' ) ); // Put the focus on the "Add language" button. + } + return false; + } + // Verify if the language has been added in the list otherwise display a dialog box to confirm what to do. + if ( '' !== selectedLanguage ) { + // Verify we don't add a duplicate language before opening the dialog box otherwise display an error message. + if ( ! languagesMap.has( selectedLanguage ) ) { + dialog.dialog( 'open' ); + } else { + showError( pll_wizard_params.i18n_language_already_added ); + showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) ); + focusOnField( $( '#lang_list-button' ) ); + } + return false; + } + disableButton( nextStepButton ); + } + ); + + // Is there an error return by PHP ? + var searchParams = new URLSearchParams( document.location.search ); + if ( searchParams.has( 'activate_error' ) ) { + // If the error code exists, display it. + if ( undefined !== pll_wizard_params[ searchParams.get( 'activate_error' ) ] ) { + showError( pll_wizard_params[ searchParams.get( 'activate_error' ) ] ); + } + } + + function confirmDialog( what ) { + switch ( what ) { + case 'yes': + var selectedOption = $( '#lang_list' ).children( ':selected' ); + addLanguage( + { + locale: selectedOption[0].value, + text: selectedOption[0].innerText, + name: $( selectedOption ).data( 'language-name' ), + flagUrl: $( selectedOption ).data( 'flag-html' ) + } + ); + break; + case 'no': + // Empty select form field and submit again the form. + languagesList.val( '' ); + break; + case 'ignore': + } + dialog.dialog( 'close' ); + if ( 'ignore' === what ) { + focusOnField( $( '#lang_list-button' ) ); + } else { + addLanguageForm.submit(); + } + } + + // Initialize dialog box in the case a language is selected but not added in the list. + dialog.dialog( + { + autoOpen: false, + modal: true, + draggable: false, + resizable: false, + title: pll_wizard_params.i18n_dialog_title, + minWidth: 600, + maxWidth: '100%', + open: function ( event, ui ) { + // Change dialog box position for rtl language + if ( $( 'body' ).hasClass( 'rtl' ) ) { + $( this ).parent().css( + { + right: $( this ).parent().css( 'left' ), + left: 'auto' + } + ); + } + // Display language name and flag information in dialog box. + $( this ).find( '#dialog-language' ).text( $( '#lang_list' ).children( ':selected' ).first().text() ); + // language properties come from the select dropdown #lang_list which is built server side and well escaped. + // see template view-wizard-step-languages.php. + $( this ).find( '#dialog-language-flag' ).empty().prepend( $( '#lang_list' ).children( ':selected' ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend + }, + buttons: [ + { + text: pll_wizard_params.i18n_dialog_yes_button, + click: function ( event ) { + confirmDialog( 'yes' ); + } + }, + { + text: pll_wizard_params.i18n_dialog_no_button, + click: function ( event ) { + confirmDialog( 'no' ); + } + }, + { + text: pll_wizard_params.i18n_dialog_ignore_button, + click: function ( event ) { + confirmDialog( 'ignore' ); + } + } + ] + } + ) + } +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/load.php new file mode 100644 index 000000000..0febfd340 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/load.php @@ -0,0 +1,14 @@ +wizard = new PLL_Wizard( $polylang ); +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-page.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-page.php new file mode 100644 index 000000000..30a7eec6a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-page.php @@ -0,0 +1,108 @@ + + +> + + + + + <?php + printf( + /* translators: %s is the plugin name */ + esc_html__( '%s › Setup', 'polylang' ), + esc_html( POLYLANG ) + ); + ?> + + + + steps[ $this->step ]['scripts'] ); ?> + styles, $this->steps[ $this->step ]['styles'] ) ); ?> + + + +

    + + + + +

    +
      + steps as $step_key => $step ) { + $is_completed = array_search( $this->step, array_keys( $this->steps ), true ) > array_search( $step_key, array_keys( $this->steps ), true ); + + if ( $step_key === $this->step ) { + ?> +
    1. + +
    2. + + + +
    3. + +
    4. + +
    +
    +
    step}-step" ); ?>"> + steps[ $this->step ]['view'] ) ) { + call_user_func( $this->steps[ $this->step ]['view'], $this ); + } + ?> + step ) : ?> +

    + +

    + +
    +
    + + + diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-home-page.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-home-page.php new file mode 100644 index 000000000..16f7ac347 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-home-page.php @@ -0,0 +1,135 @@ +model->get_languages_list(); +$default_language = count( $languages ) > 0 ? $this->options['default_lang'] : null; +$home_page_id = get_option( 'page_on_front' ); +$translations = $this->model->post->get_translations( $home_page_id ); +$untranslated_languages = array(); +$home_page = $home_page_id > 0 ? get_post( $home_page_id ) : null; +$home_page_language = $this->model->post->get_language( $home_page_id ); + +foreach ( $languages as $language ) { + if ( ! $this->model->post->get( $home_page_id, $language ) ) { + $untranslated_languages[] = $language; + } +} +?> + + + + + +

    +

    + ' . esc_html( $home_page->post_title ) . '' + ); + ?> +
    + flag . ' ' . esc_html( $home_page_language->name ) . ' ' . esc_html( $home_page_language->locale ) . '' //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ) + ?> +
    + +

    +

    + +

    + + + + + + + + + model->get_language( $lang ); + ?> + + + + + +
    + flag; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ' ' . esc_html( $language->name ) . ' ' . esc_html( $language->locale ) . ' '; + ?> + is_default ) : ?> + + + + + + + +
    + + + + + + + = 1 ) : ?> + + + + + + + + + + + + + + + + + + + +
    + + +
    + flag; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ' ' . esc_html( $lg->name ) . ' ' . esc_html( $lg->locale ) . ' '; + ?> + is_default ) : ?> + + + + + + + +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-languages.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-languages.php new file mode 100644 index 000000000..501fc182f --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-languages.php @@ -0,0 +1,136 @@ +model->get_languages_list(); +$default_language = count( $existing_languages ) > 0 ? $this->options['default_lang'] : null; +$languages_list = array_diff_key( + PLL_Settings::get_predefined_languages(), + wp_list_pluck( $existing_languages, 'locale', 'locale' ) +); +?> +
    +

    + +

    +

    + +

    +

    +
    +
    +
    + +
    + +
    + +
    +
    +
    + + + + + + + + + +
    + + + + + + + + + + + ' . "\n", + esc_attr( $lg->locale ), + esc_html( $lg->name ), + $lg->flag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $lg->is_default ? ' ' . esc_html__( 'Default language', 'polylang' ) . '' : '' + ); + } + ?> + +
    %3$s%2$s - %1$s %4$s
    + +
    +

    + ', + '' + ); + ?> +

    +

    + +

    +
      +
    • + ' . esc_html__( 'Yes', 'polylang' ) . '' + ); + ?> +
    • +
    • + ' . esc_html__( 'No', 'polylang' ) . '' + ); + ?> +
    • +
    • + ' . esc_html__( 'Ignore', 'polylang' ) . '' + ); + ?> +
    • +
    +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-last.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-last.php new file mode 100644 index 000000000..497fe4756 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-last.php @@ -0,0 +1,114 @@ + +

    + +
    +

    +
    +

    + + + +

    +
    +
    + +
      +
    • +
      +

      +

      +

      + +

      +
      +
      +

      + + + +

      +
      +
    • +
    • +
      +

      +

      +

      +
      +
      +

      + + + +

      +
      +
    • + +
    • +
      +

      +

      +

      + +

      +
      +
      +

      + + + +

      +
      +
    • + + +
    • +
      +

      +

      +

      + ' . esc_html__( 'Polylang Business Pack', 'polylang' ) . '' + ); + ?> +

      +
      +
      +

      + + + +

      +
      +
    • + +
    • +
      +

      + + + +

      +
      +
    • +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-licenses.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-licenses.php new file mode 100644 index 000000000..c7db239ff --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-licenses.php @@ -0,0 +1,38 @@ + +

    + + +

    +

    +
    + +

    + +
    +
    + + + get_form_field(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + ?> + +
    +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-media.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-media.php new file mode 100644 index 000000000..cf221b46e --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-media.php @@ -0,0 +1,62 @@ + +

    +

    + + + +

    +

    + +

    +
      +
    • +
      + + + /> + +
      +
      +

      + +

      +
      +
    • +
    • +
      +

      + + + + + +

      +
      +
    • +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-untranslated-contents.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-untranslated-contents.php new file mode 100644 index 000000000..eef8e8e7b --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/view-wizard-step-untranslated-contents.php @@ -0,0 +1,37 @@ +model->get_languages_list(); +?> +

    +

    +
    +
    + +

    +
    + + +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/wizard.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/wizard.php new file mode 100644 index 000000000..a900ca14c --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wizard/wizard.php @@ -0,0 +1,855 @@ +options = &$polylang->options; + $this->model = &$polylang->model; + + // Display Wizard page before any other action to ensure displaying it outside the WordPress admin context. + // Hooked on admin_init with priority 40 to ensure PLL_Wizard_Pro is correctly initialized. + add_action( 'admin_init', array( $this, 'setup_wizard_page' ), 40 ); + // Add Wizard submenu. + add_filter( 'pll_settings_tabs', array( $this, 'settings_tabs' ), 10, 1 ); + // Add filter to select screens where to display the notice. + add_filter( 'pll_can_display_notice', array( $this, 'can_display_notice' ), 10, 2 ); + + // Default steps. + add_filter( 'pll_wizard_steps', array( $this, 'add_step_licenses' ), 100 ); + add_filter( 'pll_wizard_steps', array( $this, 'add_step_languages' ), 200 ); + add_filter( 'pll_wizard_steps', array( $this, 'add_step_media' ), 300 ); + add_filter( 'pll_wizard_steps', array( $this, 'add_step_untranslated_contents' ), 400 ); + add_filter( 'pll_wizard_steps', array( $this, 'add_step_home_page' ), 500 ); + add_filter( 'pll_wizard_steps', array( $this, 'add_step_last' ), 999 ); + } + + /** + * Save an activation transient when Polylang is activating to redirect to the wizard + * + * @since 2.7 + * + * @param bool $network_wide if activated for all sites in the network. + * @return void + */ + public static function start_wizard( $network_wide ) { + $options = get_option( 'polylang' ); + + if ( wp_doing_ajax() || $network_wide || ! empty( $options ) ) { + return; + } + set_transient( 'pll_activation_redirect', 1, 30 ); + } + + /** + * Redirect to the wizard depending on the context + * + * @since 2.7 + * + * @return void + */ + public function redirect_to_wizard() { + if ( get_transient( 'pll_activation_redirect' ) ) { + $do_redirect = true; + if ( ( isset( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ) || isset( $_GET['activate-multi'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + delete_transient( 'pll_activation_redirect' ); + $do_redirect = false; + } + + if ( $do_redirect ) { + wp_safe_redirect( + esc_url_raw( + add_query_arg( + array( + 'page' => 'mlang_wizard', + ), + admin_url( 'admin.php' ) + ) + ) + ); + exit; + } + } + } + + /** + * Add an admin Polylang submenu to access the wizard + * + * @since 2.7 + * + * @param string[] $tabs Submenus list. + * @return string[] Submenus list updated. + */ + public function settings_tabs( $tabs ) { + $tabs['wizard'] = esc_html__( 'Setup', 'polylang' ); + return $tabs; + } + + /** + * Returns true if the media step is displayable, false otherwise. + * + * @since 2.7 + * + * @param PLL_Language[] $languages List of language objects. + * @return bool + */ + public function is_media_step_displayable( $languages ) { + $media = array(); + // If there is no language or only one the media step is displayable. + if ( ! $languages || count( $languages ) < 2 ) { + return true; + } + foreach ( $languages as $language ) { + $media[ $language->slug ] = $this->model->count_posts( + $language, + array( + 'post_type' => array( 'attachment' ), + 'post_status' => 'inherit', + ) + ); + } + return count( array_filter( $media ) ) === 0; + } + + /** + * Check if the licenses step is displayable + * + * @since 2.7 + * + * @return bool + */ + public function is_licenses_step_displayable() { + $licenses = apply_filters( 'pll_settings_licenses', array() ); + return count( $licenses ) > 0; + } + + /** + * Setup the wizard page + * + * @since 2.7 + * + * @return void + */ + public function setup_wizard_page() { + + PLL_Admin_Notices::add_notice( 'wizard', $this->wizard_notice() ); + + $this->redirect_to_wizard(); + if ( ! Polylang::is_wizard() ) { + return; + } + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( esc_html__( 'Sorry, you are not allowed to manage options for this site.', 'polylang' ) ); + } + + // Enqueue scripts and styles especially for the wizard. + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); + + $this->steps = apply_filters( 'pll_wizard_steps', $this->steps ); + $step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification + + $this->step = $step && array_key_exists( $step, $this->steps ) ? $step : current( array_keys( $this->steps ) ); + + $has_languages = $this->model->has_languages(); + + if ( ! $has_languages && ! in_array( $this->step, array( 'licenses', 'languages' ) ) ) { + wp_safe_redirect( esc_url_raw( $this->get_step_link( 'languages' ) ) ); + exit; + } + + if ( $has_languages && $this->model->get_objects_with_no_lang( 1 ) && ! in_array( $this->step, array( 'licenses', 'languages', 'media', 'untranslated-contents' ) ) ) { + wp_safe_redirect( esc_url_raw( $this->get_step_link( 'untranslated-contents' ) ) ); + exit; + } + + // Call the handler of the step for going to the next step. + // Be careful nonce verification with check_admin_referer must be done in each handler. + if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing + call_user_func( $this->steps[ $this->step ]['handler'] ); + } + + $this->display_wizard_page(); + // Ensure nothing is done after including the page. + exit; + } + + /** + * Adds some admin screens where to display the wizard notice + * + * @since 2.7 + * + * @param bool $can_display_notice Whether the notice can be displayed. + * @param string $notice The notice name. + * @return bool + */ + public function can_display_notice( $can_display_notice, $notice ) { + if ( ! $can_display_notice && 'wizard' === $notice ) { + $screen = get_current_screen(); + $can_display_notice = ! empty( $screen ) && in_array( + $screen->base, + array( + 'edit', + 'upload', + 'options-general', + ) + ); + } + return $can_display_notice; + } + + /** + * Return html code of the wizard notice + * + * @since 2.7 + * + * @return string + */ + public function wizard_notice() { + ob_start(); + include __DIR__ . '/html-wizard-notice.php'; + return ob_get_clean(); + } + + /** + * Display the wizard page + * + * @since 2.7 + * + * @return void + */ + public function display_wizard_page() { + set_current_screen( 'pll-wizard' ); + include __DIR__ . '/view-wizard-page.php'; + } + + /** + * Enqueue scripts and styles for the wizard + * + * @since 2.7 + * + * @return void + */ + public function enqueue_scripts() { + wp_enqueue_style( 'polylang_admin', plugins_url( '/css/build/admin' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array(), POLYLANG_VERSION ); + wp_enqueue_style( 'pll-wizard', plugins_url( '/css/build/wizard' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common', 'forms' ), POLYLANG_VERSION ); + + $this->styles = array( 'polylang_admin', 'pll-wizard' ); + } + + /** + * Get the suffix to enqueue non minified files in a Debug context + * + * @since 2.7 + * + * @return string Empty when SCRIPT_DEBUG equal to true + * otherwise .min + */ + public function get_suffix() { + return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + } + + /** + * Get the URL for the step's screen. + * + * @since 2.7 + * + * @param string $step slug (default: current step). + * @return string URL for the step if it exists. + * Empty string on failure. + */ + public function get_step_link( $step = '' ) { + if ( ! $step ) { + $step = $this->step; + } + + $keys = array_keys( $this->steps ); + + $step_index = array_search( $step, $keys, true ); + if ( false === $step_index ) { + return ''; + } + + return add_query_arg( 'step', $keys[ $step_index ], remove_query_arg( 'activate_error' ) ); + } + + /** + * Get the URL for the next step's screen. + * + * @since 2.7 + * + * @param string $step slug (default: current step). + * @return string URL for next step if a next step exists. + * Admin URL if it's the last step. + * Empty string on failure. + */ + public function get_next_step_link( $step = '' ) { + if ( ! $step ) { + $step = $this->step; + } + + $keys = array_keys( $this->steps ); + if ( end( $keys ) === $step ) { + return admin_url(); + } + + $step_index = array_search( $step, $keys, true ); + if ( false === $step_index ) { + return ''; + } + + return add_query_arg( 'step', $keys[ $step_index + 1 ], remove_query_arg( 'activate_error' ) ); + } + + /** + * Add licenses step to the wizard + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_licenses( $steps ) { + // Add ajax action on deactivate button in licenses step. + add_action( 'wp_ajax_pll_deactivate_license', array( $this, 'deactivate_license' ) ); + + // Be careful pll_admin script is enqueued here without dependency except jquery because only code useful for deactivate license button is needed. + // 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(). + wp_enqueue_script( 'pll_admin', plugins_url( '/js/build/admin' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery' ), POLYLANG_VERSION, true ); + wp_localize_script( 'pll_admin', 'pll_admin', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) ); + + if ( $this->is_licenses_step_displayable() ) { + $steps['licenses'] = array( + 'name' => esc_html__( 'Licenses', 'polylang' ), + 'view' => array( $this, 'display_step_licenses' ), + 'handler' => array( $this, 'save_step_licenses' ), + 'scripts' => array( 'pll_admin' ), // Polylang admin script used by deactivate license button. + 'styles' => array(), + ); + } + return $steps; + } + + /** + * Display the languages step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_licenses() { + include __DIR__ . '/view-wizard-step-licenses.php'; + } + + /** + * Execute the languages step + * + * @since 2.7 + * + * @return void + */ + public function save_step_licenses() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + $redirect = $this->get_next_step_link(); + $licenses = apply_filters( 'pll_settings_licenses', array() ); + + foreach ( $licenses as $license ) { + if ( ! empty( $_POST['licenses'][ $license->id ] ) ) { + $updated_license = $license->activate_license( sanitize_key( $_POST['licenses'][ $license->id ] ) ); + if ( ! empty( $updated_license->license_data ) && false === $updated_license->license_data->success ) { + // Stay on this step with an error. + $redirect = add_query_arg( + array( + 'step' => $this->step, + 'activate_error' => 'i18n_license_key_error', + ) + ); + } + } + } + + wp_safe_redirect( esc_url_raw( $redirect ) ); + exit; + } + + /** + * Ajax method to deactivate a license + * + * @since 2.7 + * + * @return void + */ + public function deactivate_license() { + check_ajax_referer( 'pll-wizard', '_pll_nonce' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + if ( ! isset( $_POST['id'] ) ) { + wp_die( 0 ); + } + + $id = substr( sanitize_text_field( wp_unslash( $_POST['id'] ) ), 11 ); + $licenses = apply_filters( 'pll_settings_licenses', array() ); + $license = $licenses[ $id ]; + $license->deactivate_license(); + + wp_send_json( + array( + 'id' => $id, + 'html' => $license->get_form_field(), + ) + ); + } + + /** + * Add languages step to the wizard + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_languages( $steps ) { + wp_deregister_script( 'pll_admin' ); // Deregister after the licenses step enqueue to update jquery-ui-selectmenu dependency. + // The wp-ajax-response and postbox dependencies is useless in wizard steps especially postbox which triggers a javascript error otherwise. + // 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(). + 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 ); + wp_localize_script( 'pll_admin', 'pll_admin', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) ); + wp_register_script( 'pll-wizard-languages', plugins_url( '/js/build/languages-step' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'jquery-ui-dialog' ), POLYLANG_VERSION, true ); + wp_localize_script( + 'pll-wizard-languages', + 'pll_wizard_params', + array( + 'i18n_no_language_selected' => esc_html__( 'You need to select a language to be added.', 'polylang' ), + 'i18n_language_already_added' => esc_html__( 'You already added this language.', 'polylang' ), + 'i18n_no_language_added' => esc_html__( 'You need to add at least one language.', 'polylang' ), + 'i18n_add_language_needed' => esc_html__( 'You selected a language, however, to be able to continue, you need to add it.', 'polylang' ), + 'i18n_pll_add_language' => esc_html__( 'Impossible to add the language.', 'polylang' ), + 'i18n_pll_invalid_locale' => esc_html__( 'Enter a valid WordPress locale', 'polylang' ), + 'i18n_pll_invalid_slug' => esc_html__( 'The language code contains invalid characters', 'polylang' ), + 'i18n_pll_non_unique_slug' => esc_html__( 'The language code must be unique', 'polylang' ), + 'i18n_pll_invalid_name' => esc_html__( 'The language must have a name', 'polylang' ), + 'i18n_pll_invalid_flag' => esc_html__( 'The flag does not exist', 'polylang' ), + 'i18n_dialog_title' => esc_html__( "A language wasn't added.", 'polylang' ), + 'i18n_dialog_yes_button' => esc_html__( 'Yes', 'polylang' ), + 'i18n_dialog_no_button' => esc_html__( 'No', 'polylang' ), + 'i18n_dialog_ignore_button' => esc_html__( 'Ignore', 'polylang' ), + 'i18n_remove_language_icon' => esc_html__( 'Remove this language', 'polylang' ), + ) + ); + wp_enqueue_script( 'pll-wizard-languages' ); + wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/build/selectmenu' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common', 'wp-jquery-ui-dialog' ), POLYLANG_VERSION ); + $steps['languages'] = array( + 'name' => esc_html__( 'Languages', 'polylang' ), + 'view' => array( $this, 'display_step_languages' ), + 'handler' => array( $this, 'save_step_languages' ), + 'scripts' => array( 'pll-wizard-languages', 'pll_admin' ), + 'styles' => array( 'pll-wizard-selectmenu' ), + ); + return $steps; + } + + /** + * Display the languages step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_languages() { + include __DIR__ . '/view-wizard-step-languages.php'; + } + + /** + * Execute the languages step + * + * @since 2.7 + * + * @return void + */ + public function save_step_languages() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + $all_languages = include POLYLANG_DIR . '/settings/languages.php'; + $languages = isset( $_POST['languages'] ) && is_array( $_POST['languages'] ) ? array_map( 'sanitize_locale_name', $_POST['languages'] ) : false; + $saved_languages = array(); + + // If there is no language added or defined. + if ( empty( $languages ) && ! $this->model->has_languages() ) { + // Stay on this step with an error. + wp_safe_redirect( + esc_url_raw( + add_query_arg( + array( + 'step' => $this->step, + 'activate_error' => 'i18n_no_language_added', + ) + ) + ) + ); + exit; + } + + // Otherwise process the languages to add or skip the step if no language has been added. + if ( ! empty( $languages ) ) { + require_once ABSPATH . 'wp-admin/includes/translation-install.php'; + // Remove duplicate values. + $languages = array_unique( $languages ); + // For each language add it in Polylang settings. + foreach ( $languages as $locale ) { + $saved_languages = $all_languages[ $locale ]; + + $saved_languages['slug'] = $saved_languages['code']; + $saved_languages['rtl'] = (int) ( 'rtl' === $saved_languages['dir'] ); + $saved_languages['term_group'] = 0; // Default term_group. + + $language_added = $this->model->add_language( $saved_languages ); + + if ( $language_added instanceof WP_Error && array_key_exists( 'pll_non_unique_slug', $language_added->errors ) ) { + // Get the slug from the locale : lowercase and dash instead of underscore. + $saved_languages['slug'] = strtolower( str_replace( '_', '-', $saved_languages['locale'] ) ); + $language_added = $this->model->add_language( $saved_languages ); + } + + if ( $language_added instanceof WP_Error ) { + // Stay on this step with an error. + $error_keys = array_keys( $language_added->errors ); + wp_safe_redirect( + esc_url_raw( + add_query_arg( + array( + 'step' => $this->step, + 'activate_error' => 'i18n_' . reset( $error_keys ), + ) + ) + ) + ); + exit; + } + + if ( 'en_US' !== $locale && current_user_can( 'install_languages' ) ) { + wp_download_language_pack( $locale ); + } + } + } + wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); + exit; + } + + /** + * Add the media step to the wizard. + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_media( $steps ) { + $languages = $this->model->get_languages_list(); + + if ( $this->is_media_step_displayable( $languages ) ) { + $steps['media'] = array( + 'name' => esc_html__( 'Media', 'polylang' ), + 'view' => array( $this, 'display_step_media' ), + 'handler' => array( $this, 'save_step_media' ), + 'scripts' => array(), + 'styles' => array(), + ); + } + return $steps; + } + + /** + * Display the media step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_media() { + include __DIR__ . '/view-wizard-step-media.php'; + } + + /** + * Execute the media step + * + * @since 2.7 + * + * @return void + */ + public function save_step_media() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + $media_support = isset( $_POST['media_support'] ) ? sanitize_key( $_POST['media_support'] ) === 'yes' : false; + + $this->options['media_support'] = $media_support; + + update_option( 'polylang', $this->options ); + + wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); + exit; + } + + /** + * Add untranslated contents step to the wizard + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_untranslated_contents( $steps ) { + if ( ! $this->model->has_languages() || $this->model->get_objects_with_no_lang( 1 ) ) { + // Even if pll_admin is already enqueued with the same dependencies by the languages step, it is interesting to keep that it's also useful for the untranslated-contents step. + // To be really loaded the script need to be passed to the $steps['untranslated-contents']['scripts'] array below with the same handle than in wp_enqueue_script(). + 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 ); + wp_localize_script( 'pll_admin', 'pll_admin', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) ); + wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/build/selectmenu' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common' ), POLYLANG_VERSION ); + $steps['untranslated-contents'] = array( + 'name' => esc_html__( 'Content', 'polylang' ), + 'view' => array( $this, 'display_step_untranslated_contents' ), + 'handler' => array( $this, 'save_step_untranslated_contents' ), + 'scripts' => array( 'pll_admin' ), + 'styles' => array( 'pll-wizard-selectmenu' ), + ); + } + return $steps; + } + + /** + * Display the untranslated contents step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_untranslated_contents() { + include __DIR__ . '/view-wizard-step-untranslated-contents.php'; + } + + /** + * Execute the untranslated contents step + * + * @since 2.7 + * + * @return void + */ + public function save_step_untranslated_contents() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + $lang = ! empty( $_POST['language'] ) && is_string( $_POST['language'] ) ? sanitize_locale_name( $_POST['language'] ) : false; + + if ( empty( $lang ) ) { + $lang = $this->options['default_lang']; + } + + $language = $this->model->get_language( $lang ); + + if ( $language instanceof PLL_Language ) { + $this->model->set_language_in_mass( $language ); + } + + wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); + exit; + } + + /** + * Add home page step to the wizard + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_home_page( $steps ) { + $languages = $this->model->get_languages_list(); + $home_page_id = get_option( 'page_on_front' ); + + $translations = $this->model->post->get_translations( $home_page_id ); + + if ( $home_page_id > 0 && ( ! $languages || count( $languages ) === 1 || count( $translations ) !== count( $languages ) ) ) { + $steps['home-page'] = array( + 'name' => esc_html__( 'Homepage', 'polylang' ), + 'view' => array( $this, 'display_step_home_page' ), + 'handler' => array( $this, 'save_step_home_page' ), + 'scripts' => array(), + 'styles' => array(), + ); + } + return $steps; + } + + /** + * Display the home page step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_home_page() { + include __DIR__ . '/view-wizard-step-home-page.php'; + } + + /** + * Execute the home page step + * + * @since 2.7 + * + * @return void + */ + public function save_step_home_page() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + $default_language = $this->model->has_languages() ? $this->options['default_lang'] : null; + $home_page = isset( $_POST['home_page'] ) ? sanitize_key( $_POST['home_page'] ) : false; + $home_page_title = isset( $_POST['home_page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['home_page_title'] ) ) : esc_html__( 'Homepage', 'polylang' ); + $home_page_language = isset( $_POST['home_page_language'] ) ? sanitize_key( $_POST['home_page_language'] ) : false; + + $untranslated_languages = isset( $_POST['untranslated_languages'] ) ? array_map( 'sanitize_key', $_POST['untranslated_languages'] ) : array(); + + call_user_func( + apply_filters( 'pll_wizard_create_home_page_translations', array( $this, 'create_home_page_translations' ) ), + $default_language, + $home_page, + $home_page_title, + $home_page_language, + $untranslated_languages + ); + + $this->model->clean_languages_cache(); + + wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); + exit; + } + + /** + * Create home page translations for each language defined. + * + * @since 2.7 + * + * @param string $default_language Slug of the default language; null if no default language is defined. + * @param int $home_page Post ID of the home page if it's defined, false otherwise. + * @param string $home_page_title Home page title if it's defined, 'Homepage' otherwise. + * @param string $home_page_language Slug of the home page if it's defined, false otherwise. + * @param string[] $untranslated_languages Array of languages which needs to have a home page translated. + * @return void + */ + public function create_home_page_translations( $default_language, $home_page, $home_page_title, $home_page_language, $untranslated_languages ) { + $translations = $this->model->post->get_translations( $home_page ); + + foreach ( $untranslated_languages as $language ) { + $language_properties = $this->model->get_language( $language ); + $id = wp_insert_post( + array( + 'post_title' => $home_page_title . ' - ' . $language_properties->name, + 'post_type' => 'page', + 'post_status' => 'publish', + ) + ); + $translations[ $language ] = $id; + pll_set_post_language( $id, $language ); + } + pll_save_post_translations( $translations ); + } + + /** + * Add last step to the wizard + * + * @since 2.7 + * + * @param array $steps List of steps. + * @return array List of steps updated. + */ + public function add_step_last( $steps ) { + $steps['last'] = array( + 'name' => esc_html__( 'Ready!', 'polylang' ), + 'view' => array( $this, 'display_step_last' ), + 'handler' => array( $this, 'save_step_last' ), + 'scripts' => array(), + 'styles' => array(), + ); + return $steps; + } + + /** + * Display the last step form + * + * @since 2.7 + * + * @return void + */ + public function display_step_last() { + // We ran the wizard once. So we can dismiss its notice. + PLL_Admin_Notices::dismiss( 'wizard' ); + include __DIR__ . '/view-wizard-step-last.php'; + } + + /** + * Execute the last step + * + * @since 2.7 + * + * @return void + */ + public function save_step_last() { + check_admin_referer( 'pll-wizard', '_pll_nonce' ); + + wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); + exit; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/load.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/load.php new file mode 100644 index 000000000..0cd81b0a7 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/load.php @@ -0,0 +1,17 @@ +model->has_languages() ) { + if ( ! defined( 'PLL_WPML_COMPAT' ) || PLL_WPML_COMPAT ) { + PLL_WPML_Compat::instance(); // WPML API. + PLL_WPML_Config::instance(); // wpml-config.xml. + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-api.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-api.php new file mode 100644 index 000000000..ac827c620 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-api.php @@ -0,0 +1,495 @@ + not applicable. + add_filter( 'wpml_current_language', 'pll_current_language', 10, 0 ); + add_filter( 'wpml_default_language', 'pll_default_language', 10, 0 ); + // wpml_add_language_selector => not implemented. + // wpml_footer_language_selector => not applicable. + add_action( 'wpml_add_language_form_field', array( $this, 'wpml_add_language_form_field' ) ); + add_filter( 'wpml_language_is_active', array( $this, 'wpml_language_is_active' ), 10, 2 ); + add_filter( 'wpml_is_rtl', array( $this, 'wpml_is_rtl' ) ); + // wpml_language_form_input_field => See wpml_add_language_form_field + // wpml_language_has_switched => See wpml_switch_language + add_filter( 'wpml_element_trid', array( $this, 'wpml_element_trid' ), 10, 3 ); + add_filter( 'wpml_get_element_translations', array( $this, 'wpml_get_element_translations' ), 10, 3 ); + // wpml_language_switcher => not implemented. + // wpml_browser_redirect_language_params => not implemented. + // wpml_enqueue_browser_redirect_language => not applicable. + // wpml_enqueued_browser_redirect_language => not applicable. + // wpml_encode_string => not applicable. + // wpml_decode_string => not applicable. + + /* + * Retrieving Language Information for Content. + */ + add_filter( 'wpml_post_language_details', 'wpml_get_language_information', 10, 2 ); + add_action( 'wpml_switch_language', array( __CLASS__, 'wpml_switch_language' ), 10, 2 ); + add_filter( 'wpml_element_language_code', array( $this, 'wpml_element_language_code' ), 10, 2 ); + // wpml_element_language_details => not applicable. + + /* + * Retrieving Localized Content. + */ + add_filter( 'wpml_home_url', 'pll_home_url', 10, 0 ); + add_filter( 'wpml_element_link', 'icl_link_to_element', 10, 7 ); + add_filter( 'wpml_object_id', 'icl_object_id', 10, 4 ); + add_filter( 'wpml_translate_single_string', array( $this, 'wpml_translate_single_string' ), 10, 4 ); + // wpml_translate_string => not applicable. + // wpml_unfiltered_admin_string => not implemented. + add_filter( 'wpml_permalink', array( $this, 'wpml_permalink' ), 10, 2 ); + // wpml_elements_without_translations => not implemented. + add_filter( 'wpml_get_translated_slug', array( $this, 'wpml_get_translated_slug' ), 10, 3 ); + + /* + * Finding the Translation State of Content. + */ + // wpml_element_translation_type => not implemented. + add_filter( 'wpml_element_has_translations', array( $this, 'wpml_element_has_translations' ), 10, 3 ); + // wpml_master_post_from_duplicate => not applicable. + // wpml_post_duplicates => not applicable. + + /* + * Inserting Content. + */ + // wpml_admin_make_post_duplicates => not applicable. + // wpml_make_post_duplicates => not applicable. + add_action( 'wpml_register_single_string', 'icl_register_string', 10, 3 ); + // wpml_register_string => not applicable. + // wpml_register_string_packages => not applicable. + // wpml_delete_package_action => not applicable. + // wpml_show_package_language_ui => not applicable. + // wpml_set_element_language_details => not implemented. + // wpml_multilingual_options => not applicable. + + /* + * Miscellaneous + */ + // wpml_element_type => not applicable. + // wpml_setting => not applicable. + // wpml_sub_setting => not applicable. + // wpml_editor_cf_to_display => not applicable. + // wpml_tm_save_translation_cf => not implemented. + // wpml_tm_xliff_export_translated_cf => not applicable. + // wpml_tm_xliff_export_original_cf => not applicable. + // wpml_duplicate_generic_string => not applicable. + // wpml_translatable_user_meta_fields => not implemented. + // wpml_cross_domain_language_data => not applicable. + // wpml_get_cross_domain_language_data => not applicable. + // wpml_loaded => not applicable. + // wpml_st_loaded => not applicable. + // wpml_tm_loaded => not applicable. + // wpml_hide_management_column (3.4.1) => not applicable. + // wpml_ls_directories_to_scan => not applicable. + // wpml_ls_model_css_classes => not applicable. + // wpml_ls_model_language_css_classes => not applicable. + // wpml_tf_feedback_open_link => not applicable. + // wpml_sync_custom_field => not implemented. + // wpml_sync_all_custom_fields => not implemented. + // wpml_is_redirected => not implemented. + + /* + * Updating Content + */ + // wpml_set_translation_mode_for_post_type => not implemented. + + /* + * Undocumented + */ + add_filter( 'wpml_is_translated_post_type', array( $this, 'wpml_is_translated_post_type' ), 10, 2 ); + add_filter( 'wpml_is_translated_taxonomy', array( $this, 'wpml_is_translated_taxonomy' ), 10, 2 ); + } + + /** + * Get a list of the languages enabled for a site. + * + * @since 2.0 + * + * @param mixed $null Not used. + * @param array| string $args See arguments of icl_get_languages(). + * @return array Array of arrays per language. + */ + public function wpml_active_languages( $null, $args = '' ) { + return icl_get_languages( $args ); + } + + /** + * In WPML, get a language's native and translated name for display in a custom language switcher + * Since Polylang does not implement the translated name, always returns only the native name, + * so the 3rd, 4th and 5th parameters are not used. + * + * @since 2.2 + * + * @param mixed $null Not used. + * @param string $native_name The language native name. + * @return string + */ + public function wpml_display_language_names( $null, $native_name ) { + return $native_name; + } + + /** + * Returns an HTML hidden input field with name=”lang” and as value the current language. + * + * @since 2.0 + * + * @return void + */ + public function wpml_add_language_form_field() { + $lang = pll_current_language(); + $field = sprintf( '', esc_attr( $lang ) ); + $field = apply_filters( 'wpml_language_form_input_field', $field, $lang ); + echo $field; // phpcs:ignore WordPress.Security.EscapeOutput + } + + /** + * Find out if a specific language is enabled for the site. + * + * @since 2.0 + * + * @param mixed $null Not used. + * @param string $slug Language code. + * @return bool + */ + public function wpml_language_is_active( $null, $slug ) { + $language = PLL()->model->get_language( $slug ); + return ! empty( $language ) && $language->active; + } + + /** + * Find out whether the current language text direction is RTL or not. + * + * @since 2.0 + * + * @return bool + */ + public function wpml_is_rtl() { + return pll_current_language( 'is_rtl' ); + } + + /** + * Returns the id of the translation group of a translated element. + * + * @since 3.4 + * + * @param mixed $empty_value Not used. + * @param int $element_id The id of the item, post id for posts, term_taxonomy_id for terms. + * @param string $element_type Optional. The type of an element. + * @return int + */ + public function wpml_element_trid( $empty_value, $element_id, $element_type = 'post_post' ) { + if ( 0 === strpos( $element_type, 'tax_' ) ) { + $element = get_term_by( 'term_taxonomy_id', $element_id ); + if ( $element instanceof WP_Term ) { + $tr_term = PLL()->model->term->get_object_term( $element->term_id, 'term_translations' ); + } + } + + if ( 0 === strpos( $element_type, 'post_' ) ) { + $tr_term = PLL()->model->post->get_object_term( $element_id, 'post_translations' ); + } + + if ( isset( $tr_term ) && $tr_term instanceof WP_Term ) { + return $tr_term->term_id; + } + + return 0; + } + + /** + * Returns the element translations info using the ID of the translation group. + * + * @since 3.4 + * + * @param mixed $empty_value Not used. + * @param int $trid The ID of the translation group. + * @param string $element_type Optional. The type of an element. + * @return stdClass[] + */ + public function wpml_get_element_translations( $empty_value, $trid, $element_type = 'post_post' ) { + $return = array(); + + if ( 0 === strpos( $element_type, 'tax_' ) ) { + $translations = PLL()->model->term->get_translations_from_term_id( $trid ); + if ( empty( $translations ) ) { + return array(); + } + + $original = min( $translations ); // We suppose that the original is the first term created. + $source_lang = array_search( $original, $translations ); + + $args = array( + 'include' => $translations, + 'hide_empty' => false, + ); + $_terms = get_terms( $args ); + + if ( ! is_array( $_terms ) ) { + return array(); + } + + $terms = array(); + foreach ( $_terms as $term ) { + $terms[ $term->term_id ] = $term; + } + + foreach ( $translations as $lang => $term_id ) { + if ( empty( $terms[ $term_id ] ) ) { + continue; + } + + /* + * It seems that WPML fills the `instances` property with the total number of posts + * related to this term, while `WP_Term::$count` includes only *published* posts. + * We intentionnally accept this difference to avoid extra DB queries. + */ + $return[ $lang ] = (object) array( + 'translation_id' => '0', // We have nothing equivalent. + 'language_code' => $lang, + 'element_id' => (string) $terms[ $term_id ]->term_taxonomy_id, + 'source_language_code' => $source_lang === $lang ? null : $source_lang, + 'element_type' => $element_type, + 'original' => $original === $term_id ? '1' : '0', + 'name' => $terms[ $term_id ]->name, + 'term_id' => (string) $term_id, + 'instances' => (string) $terms[ $term_id ]->count, + ); + } + } + + if ( 0 === strpos( $element_type, 'post_' ) ) { + $translations = PLL()->model->post->get_translations_from_term_id( $trid ); + if ( empty( $translations ) ) { + return array(); + } + + $original = min( $translations ); // We suppose that the original is the first post created. + $source_lang = array_search( $original, $translations ); + + $args = array( + 'post__in' => $translations, + 'no_paging' => true, + 'posts_per_page' => -1, + 'update_post_meta_cache' => false, + 'update_post_term_cache' => false, + 'lang' => '', + ); + $_posts = get_posts( $args ); + + $posts = array(); + foreach ( $_posts as $post ) { + $posts[ $post->ID ] = $post; + } + + foreach ( $translations as $lang => $post_id ) { + if ( empty( $posts[ $post_id ] ) ) { + continue; + } + + $return[ $lang ] = (object) array( + 'translation_id' => '0', // We have nothing equivalent. + 'language_code' => $lang, + 'element_id' => (string) $post_id, + 'source_language_code' => $source_lang === $lang ? null : $source_lang, + 'element_type' => $element_type, + 'original' => $original === $post_id ? '1' : '0', + 'post_title' => $posts[ $post_id ]->post_title, + 'post_status' => $posts[ $post_id ]->post_status, + ); + } + } + + return $return; + } + + /** + * Switches whole site to the given language or restores the language that was set when first calling this function. + * Unlike the WPML original action, it is not possible to set the current language and the cookie to different values. + * + * @since 2.7 + * + * @param null|string $lang Language code to switch into, restores the original language if null. + * @param bool|string $cookie Optionally also switches the cookie. + * @return void + */ + public static function wpml_switch_language( $lang = null, $cookie = false ) { + if ( null === self::$original_language ) { + self::$original_language = PLL()->curlang; + } + + if ( empty( $lang ) ) { + PLL()->curlang = self::$original_language; + } elseif ( 'all' === $lang ) { + PLL()->curlang = null; + } elseif ( in_array( $lang, pll_languages_list() ) ) { + PLL()->curlang = PLL()->model->get_language( $lang ); + } + + if ( $cookie && isset( PLL()->choose_lang ) ) { + PLL()->choose_lang->maybe_setcookie(); + } + + do_action( 'wpml_language_has_switched', $lang, $cookie, self::$original_language ); + } + + /** + * Get the language code for a translatable element. + * + * @since 2.0 + * + * @param mixed $language_code A 2-letter language code. + * @param array $args An array with two keys element_id => post_id or term_taxonomy_id, element_type => post type or taxonomy + * @return string|null + */ + public function wpml_element_language_code( $language_code, $args ) { + $type = $args['element_type']; + $id = $args['element_id']; + + if ( 'post' === $type || pll_is_translated_post_type( $type ) ) { + $language = pll_get_post_language( $id ); + return is_string( $language ) ? $language : null; + } + + if ( 'term' === $type || pll_is_translated_taxonomy( $type ) ) { + $term = get_term_by( 'term_taxonomy_id', $id ); + if ( $term instanceof WP_Term ) { + $id = $term->term_id; + } + $language = pll_get_term_language( $id ); + return is_string( $language ) ? $language : null; + } + + return null; + } + + /** + * Translates a string. + * + * @since 2.0 + * + * @param string $string The string's original value. + * @param string $context The string's registered context. + * @param string $name The string's registered name. + * @param null|string $lang Optional, return the translation in this language, defaults to current language. + * @return string The translated string. + */ + public function wpml_translate_single_string( $string, $context, $name, $lang = null ) { + $has_translation = null; // Passed by reference. + return icl_translate( $context, $name, $string, false, $has_translation, $lang ); + } + + /** + * Converts a permalink to a language specific permalink. + * + * @since 2.2 + * + * @param string $url The url to filter. + * @param null|string $lang Language code, optional, defaults to the current language. + * @return string + */ + public function wpml_permalink( $url, $lang = '' ) { + $lang = PLL()->model->get_language( $lang ); + + if ( empty( $lang ) && ! empty( PLL()->curlang ) ) { + $lang = PLL()->curlang; + } + + return empty( $lang ) ? $url : PLL()->links_model->switch_language_in_link( $url, $lang ); + } + + /** + * Translates a post type slug. + * + * @since 2.2 + * + * @param string $slug Post type slug. + * @param string $post_type Post type name. + * @param string $lang Optional language code (defaults to current language). + * @return string + */ + public function wpml_get_translated_slug( $slug, $post_type, $lang = null ) { + if ( isset( PLL()->translate_slugs ) ) { + if ( empty( $lang ) ) { + $lang = pll_current_language(); + } + + $slug = PLL()->translate_slugs->slugs_model->get_translated_slug( $post_type, $lang ); + } + return $slug; + } + + /** + * Find out whether a post type or a taxonomy term is translated. + * + * @since 2.0 + * + * @param mixed $null Not used. + * @param int $id The post_id or term_id. + * @param string $type The post type or taxonomy. + * @return bool + */ + public function wpml_element_has_translations( $null, $id, $type ) { + if ( 'post' === $type || pll_is_translated_post_type( $type ) ) { + return count( pll_get_post_translations( $id ) ) > 1; + } elseif ( 'term' === $type || pll_is_translated_taxonomy( $type ) ) { + return count( pll_get_term_translations( $id ) ) > 1; + } + + return false; + } + + /** + * Returns true if languages and translations are managed for this post type. + * + * @since 3.4 + * + * @param mixed $value Not used. + * @param string $post_type The post type name. + * @return bool + */ + public function wpml_is_translated_post_type( $value, $post_type ) { + return pll_is_translated_post_type( $post_type ); + } + + /** + * Returns true if languages and translations are managed for this taxonomy. + * + * @since 3.4 + * + * @param mixed $value Not used. + * @param string $taxonomy The taxonomy name. + * @return bool + */ + public function wpml_is_translated_taxonomy( $value, $taxonomy ) { + return pll_is_translated_taxonomy( $taxonomy ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-compat.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-compat.php new file mode 100644 index 000000000..a828d4754 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-compat.php @@ -0,0 +1,193 @@ +api = new PLL_WPML_API(); + + self::$strings = get_option( 'polylang_wpml_strings', array() ); + + if ( ! is_array( self::$strings ) ) { + self::$strings = array(); // In case the serialized option is corrupted. + } + + add_action( 'pll_language_defined', array( $this, 'define_constants' ) ); + add_action( 'pll_no_language_defined', array( $this, 'define_constants' ) ); + add_filter( 'pll_get_strings', array( $this, 'get_strings' ) ); + } + + /** + * Access to the single instance of the class + * + * @since 1.7 + * + * @return PLL_WPML_Compat + */ + public static function instance() { + if ( empty( self::$instance ) ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Defines two WPML constants once the language has been defined + * The compatibility with WPML is not perfect on admin side as the constants are defined + * in 'setup_theme' by Polylang (based on user info) and 'plugins_loaded' by WPML (based on cookie). + * + * @since 0.9.5 + * + * @return void + */ + public function define_constants() { + if ( ! empty( PLL()->curlang ) ) { + if ( ! defined( 'ICL_LANGUAGE_CODE' ) ) { + define( 'ICL_LANGUAGE_CODE', PLL()->curlang->slug ); + } + + if ( ! defined( 'ICL_LANGUAGE_NAME' ) ) { + define( 'ICL_LANGUAGE_NAME', PLL()->curlang->name ); + } + } elseif ( ! PLL() instanceof PLL_Frontend ) { + if ( ! defined( 'ICL_LANGUAGE_CODE' ) ) { + define( 'ICL_LANGUAGE_CODE', 'all' ); + } + + if ( ! defined( 'ICL_LANGUAGE_NAME' ) ) { + define( 'ICL_LANGUAGE_NAME', '' ); + } + } + } + + /** + * Unlike pll_register_string, icl_register_string stores the string in database + * so we need to do the same as some plugins or themes may expect this. + * We use a serialized option to store these strings. + * + * @since 1.0.2 + * + * @param string|string[] $context The group in which the string is registered. + * @param string $name A unique name for the string. + * @param string $string The string to register. + * @return void + */ + public function register_string( $context, $name, $string ) { + if ( ! $string || ! is_scalar( $string ) ) { + return; + } + + /* + * WPML accepts arrays as context and internally converts them to strings. + * See WPML_Register_String_Filter::truncate_name_and_context(). + * This possibility is used by Types. + */ + if ( is_array( $context ) ) { + $name = isset( $context['context'] ) ? $name . $context['context'] : $name; + $context = $context['domain'] ?? ''; + } + + // If a string has already been registered with the same name and context, let's replace it. + $exist_string = $this->get_string_by_context_and_name( $context, $name ); + if ( $exist_string && $exist_string !== $string ) { + $languages = PLL()->model->get_languages_list(); + + // Assign translations of the old string to the new string, except for the default language. + foreach ( $languages as $language ) { + if ( $language->is_default ) { + continue; + } + $mo = new PLL_MO(); + $mo->import_from_db( $language ); + $mo->add_entry( $mo->make_entry( $string, $mo->translate( $exist_string ) ) ); + $mo->export_to_db( $language ); + } + $this->unregister_string( $context, $name ); + } + + // Registers the string if it does not exist yet (multiline as in WPML). + $to_register = array( 'context' => $context, 'name' => $name, 'string' => $string, 'multiline' => true, 'icl' => true ); + if ( ! in_array( $to_register, self::$strings ) ) { + $key = md5( "$context | $name" ); + self::$strings[ $key ] = $to_register; + update_option( 'polylang_wpml_strings', self::$strings ); + } + } + + /** + * Removes a string from the registered strings list + * + * @since 1.0.2 + * + * @param string $context The group in which the string is registered. + * @param string $name A unique name for the string. + * @return void + */ + public function unregister_string( $context, $name ) { + $key = md5( "$context | $name" ); + if ( isset( self::$strings[ $key ] ) ) { + unset( self::$strings[ $key ] ); + update_option( 'polylang_wpml_strings', self::$strings ); + } + } + + /** + * Adds strings registered by icl_register_string to those registered by pll_register_string + * + * @since 1.0.2 + * + * @param array $strings existing registered strings + * @return array registered strings with added strings through WPML API + */ + public function get_strings( $strings ) { + return empty( self::$strings ) ? $strings : array_merge( $strings, self::$strings ); + } + + /** + * Get a registered string by its context and name + * + * @since 2.0 + * + * @param string $context The group in which the string is registered. + * @param string $name A unique name for the string. + * @return bool|string The registered string, false if none was found. + */ + public function get_string_by_context_and_name( $context, $name ) { + $key = md5( "$context | $name" ); + return isset( self::$strings[ $key ] ) ? self::$strings[ $key ]['string'] : false; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-config.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-config.php new file mode 100644 index 000000000..9ba2662d1 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-config.php @@ -0,0 +1,1048 @@ + + */ +class PLL_WPML_Config { + /** + * Singleton instance + * + * @var PLL_WPML_Config|null + */ + protected static $instance; + + /** + * The content of all read xml files. + * + * @var SimpleXMLElement[] + */ + protected $xmls = array(); + + /** + * The list of xml file paths. + * + * @var string[]|null + * + * @phpstan-var array|null + */ + protected $files; + + /** + * List of rules to extract strings to translate from blocks. + * + * @var array + * + * @phpstan-var array{ + * xpath?: array>, + * key?: array> + * }|null + */ + protected $parsing_rules = null; + + /** + * Contains the list of path in `open_basedir`. + * + * @var string[]|null + */ + private $open_basedir_paths; + + /** + * Cache for parsed metas. + * + * @var array + * + * @phpstan-var array + */ + private $parsed_metas = array(); + + /** + * Constructor + * + * @since 1.0 + */ + public function __construct() { + if ( extension_loaded( 'simplexml' ) ) { + $this->init(); + } + } + + /** + * Access to the single instance of the class + * + * @since 1.7 + * + * @return PLL_WPML_Config + */ + public static function instance() { + if ( empty( self::$instance ) ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Finds the wpml-config.xml files to parse and setup filters + * + * @since 1.0 + * + * @return void + */ + public function init() { + $this->xmls = array(); + $files = $this->get_files(); + + if ( empty( $files ) ) { + return; + } + + if ( ! extension_loaded( 'simplexml' ) ) { + return; + } + + // Read all files. + foreach ( $files as $context => $file ) { + $xml = simplexml_load_file( $file ); + if ( false !== $xml ) { + $this->xmls[ $context ] = $xml; + } + } + + if ( empty( $this->xmls ) ) { + return; + } + + add_filter( 'pll_copy_post_metas', array( $this, 'copy_post_metas' ), 20, 2 ); + add_filter( 'pll_copy_term_metas', array( $this, 'copy_term_metas' ), 20, 2 ); + add_filter( 'pll_get_post_types', array( $this, 'translate_types' ), 10, 2 ); + add_filter( 'pll_get_taxonomies', array( $this, 'translate_taxonomies' ), 10, 2 ); + + // Export. + add_filter( 'pll_post_metas_to_export', array( $this, 'post_metas_to_export' ) ); + add_filter( 'pll_term_metas_to_export', array( $this, 'term_metas_to_export' ) ); + add_filter( 'pll_post_meta_encodings', array( $this, 'add_post_meta_encodings' ), 20 ); + add_filter( 'pll_term_meta_encodings', array( $this, 'add_term_meta_encodings' ), 20 ); + add_filter( 'pll_blocks_xpath_rules', array( $this, 'translate_blocks' ) ); + add_filter( 'pll_blocks_rules_for_attributes', array( $this, 'translate_blocks_attributes' ) ); + + foreach ( $this->xmls as $context => $xml ) { + $keys = $xml->xpath( 'admin-texts/key' ); + + if ( ! is_array( $keys ) ) { + continue; + } + + foreach ( $keys as $key ) { + $name = $this->get_field_attribute( $key, 'name' ); + + if ( false === strpos( $name, '*' ) ) { + $this->register_or_translate_option( $context, $name, $key ); + continue; + } + + $pattern = '#^' . str_replace( '*', '(?:.+)', $name ) . '$#'; + $names = preg_grep( $pattern, array_keys( wp_load_alloptions() ) ); + + if ( ! is_array( $names ) ) { + continue; + } + + foreach ( $names as $_name ) { + $this->register_or_translate_option( $context, $_name, $key ); + } + } + } + } + + /** + * Returns all wpml-config.xml files in MU plugins, plugins, theme, child theme, and Polylang custom directory. + * + * @since 3.1 + * + * @return string[] A context identifier as array key, a file path as array value. + * + * @phpstan-return array + */ + public function get_files() { + if ( is_array( $this->files ) ) { + return $this->files; + } + + $this->files = array_merge( + // Plugins. + $this->get_plugin_files(), + // Theme and child theme. + $this->get_theme_files(), + // MU Plugins. + $this->get_mu_plugin_files(), + // Custom. + $this->get_custom_files() + ); + + return $this->files; + } + + /** + * Adds post metas to the list of metas to copy when creating a new translation. + * + * @since 1.0 + * + * @param string[] $metas The list of post metas to copy or synchronize. + * @param bool $sync True for sync, false for copy. + * @return string[] The list of post metas to copy or synchronize. + * + * @phpstan-param array $metas + */ + public function copy_post_metas( $metas, $sync ) { + return $this->filter_metas_to_copy( (array) $metas, 'custom-fields/custom-field', (bool) $sync ); + } + + /** + * Adds term metas to the list of metas to copy when creating a new translation. + * + * @since 2.6 + * + * @param string[] $metas The list of term metas to copy or synchronize. + * @param bool $sync True for sync, false for copy. + * @return string[] The list of term metas to copy or synchronize. + * + * @phpstan-param array $metas + */ + public function copy_term_metas( $metas, $sync ) { + return $this->filter_metas_to_copy( (array) $metas, 'custom-term-fields/custom-term-field', (bool) $sync ); + } + + /** + * Adds post meta keys to export. + * + * @since 3.3 + * @see PLL_Export_Metas + * + * @param array $keys { + * A recursive array containing nested meta sub-keys to translate. + * Ex: array( + * 'meta_to_translate_1' => 1, + * 'meta_to_translate_2' => 1, + * 'meta_to_translate_3' => array( + * 'sub_key_to_translate_1' => 1, + * 'sub_key_to_translate_2' => array( + * 'sub_sub_key_to_translate_1' => 1, + * ), + * ), + * ) + * } + * @return array + * + * @phpstan-param array $keys + * @phpstan-return array + */ + public function post_metas_to_export( $keys ) { + // Add keys that have the `action` attribute set to `translate`. + $keys = $this->add_metas_to_export( (array) $keys, 'custom-fields/custom-field' ); + + // Deal with sub-field translations. + foreach ( $this->xmls as $xml ) { + $fields = $xml->xpath( 'custom-fields-texts/key' ); + + if ( ! is_array( $fields ) ) { + // No 'custom-fields-texts' nodes. + continue; + } + + foreach ( $fields as $field ) { + $name = $this->get_field_attribute( $field, 'name' ); + + if ( '' === $name ) { + // Wrong configuration: empty `name` attribute (meta name). + continue; + } + + if ( ! array_key_exists( $name, $keys ) ) { + // Wrong configuration: the field is not in `custom-fields/custom-field`. + continue; + } + + $keys = $this->xml_to_array( $field, $keys, 1 ); + } + } + + return $keys; + } + + /** + * Adds term meta keys to export. + * Note: sub-key translations are not currently supported by WPML. + * + * @since 3.3 + * @see PLL_Export_Metas + * + * @param array $keys { + * An array containing meta keys to translate. + * Ex: array( + * 'meta_to_translate_1' => 1, + * 'meta_to_translate_2' => 1, + * 'meta_to_translate_3' => 1, + * ) + * } + * @return array + * + * @phpstan-param array $keys + * @phpstan-return array + */ + public function term_metas_to_export( $keys ) { + // Add keys that have the `action` attribute set to `translate`. + return $this->add_metas_to_export( (array) $keys, 'custom-term-fields/custom-term-field' ); + } + + /** + * Specifies the encoding for post metas. + * + * @since 3.6 + * + * @param string[] $metas An array containing meta names as array keys, and their encoding as array values. + * @return string[] + * + * @phpstan-param array $metas + */ + public function add_post_meta_encodings( $metas ) { + return $this->add_metas_encodings( (array) $metas, 'custom-fields/custom-field' ); + } + + /** + * Specifies the encoding for term metas. + * + * @since 3.6 + * + * @param string[] $metas An array containing meta names as array keys, and their encoding as array values. + * @return string[] + * + * @phpstan-param array $metas + */ + public function add_term_meta_encodings( $metas ) { + return $this->add_metas_encodings( (array) $metas, 'custom-term-fields/custom-term-field' ); + } + + /** + * Language and translation management for custom post types. + * + * @since 1.0 + * + * @param string[] $types The list of post type names for which Polylang manages language and translations. + * @param bool $hide True when displaying the list in Polylang settings. + * @return string[] The list of post type names for which Polylang manages language and translations. + */ + public function translate_types( $types, $hide ) { + foreach ( $this->xmls as $xml ) { + $pts = $xml->xpath( 'custom-types/custom-type' ); + + if ( ! is_array( $pts ) ) { + continue; + } + + foreach ( $pts as $pt ) { + $translate = $this->get_field_attribute( $pt, 'translate' ); + + if ( '1' === $translate && ! $hide ) { + $types[ (string) $pt ] = (string) $pt; + } else { + unset( $types[ (string) $pt ] ); // The theme/plugin author decided what to do with the post type so don't allow the user to change this + } + } + } + + return $types; + } + + /** + * Language and translation management for custom taxonomies. + * + * @since 1.0 + * + * @param string[] $taxonomies The list of taxonomy names for which Polylang manages language and translations. + * @param bool $hide True when displaying the list in Polylang settings. + * @return string[] The list of taxonomy names for which Polylang manages language and translations. + */ + public function translate_taxonomies( $taxonomies, $hide ) { + foreach ( $this->xmls as $xml ) { + $taxos = $xml->xpath( 'taxonomies/taxonomy' ); + + if ( ! is_array( $taxos ) ) { + continue; + } + + foreach ( $taxos as $tax ) { + $translate = $this->get_field_attribute( $tax, 'translate' ); + + if ( '1' === $translate && ! $hide ) { + $taxonomies[ (string) $tax ] = (string) $tax; + } else { + unset( $taxonomies[ (string) $tax ] ); // the theme/plugin author decided what to do with the taxonomy so don't allow the user to change this + } + } + } + + return $taxonomies; + } + + /** + * Translation management for strings in blocks content. + * + * @since 3.3 + * + * @param string[][] $parsing_rules Rules as Xpath expressions to evaluate in the blocks content. + * @return string[][] Rules completed with ones from wpml-config file. + * + * @phpstan-param array> $parsing_rules + * @phpstan-return array> + */ + public function translate_blocks( $parsing_rules ) { + return array_merge( $parsing_rules, $this->get_blocks_parsing_rules( 'xpath' ) ); + } + + /** + * Translation management for blocks attributes. + * + * @since 3.3 + * @since 3.6 Format changed from `array` to `array`. + * + * @param array $parsing_rules Rules for blocks attributes to translate. + * @return array Rules completed with ones from wpml-config file. + * + * @phpstan-param array $parsing_rules + * @phpstan-return array + */ + public function translate_blocks_attributes( $parsing_rules ) { + return array_merge( $parsing_rules, $this->get_blocks_parsing_rules( 'key' ) ); + } + + /** + * Returns rules to extract translatable strings from blocks. + * + * @since 3.3 + * + * @param string $rule_tag Tag name to extract. + * @return string[][] The rules. + * + * @phpstan-param 'xpath'|'key' $rule_tag + * @phpstan-return ( + * $rule_tag is 'xpath' ? array> : array> + * ) + */ + protected function get_blocks_parsing_rules( $rule_tag ) { + + if ( null === $this->parsing_rules ) { + $this->parsing_rules = $this->extract_blocks_parsing_rules(); + } + + return isset( $this->parsing_rules[ $rule_tag ] ) ? $this->parsing_rules[ $rule_tag ] : array(); + } + + /** + * Extract all rules from WPML config file to translate strings for blocks. + * + * @since 3.3 + * + * @return string[][][] Rules completed with ones from wpml-config file. + * + * @phpstan-return array{ + * xpath?: array>, + * key?: array> + * } + */ + protected function extract_blocks_parsing_rules() { + $parsing_rules = array(); + + foreach ( $this->xmls as $xml ) { + $blocks = $xml->xpath( 'gutenberg-blocks/gutenberg-block' ); + + if ( ! is_array( $blocks ) ) { + continue; + } + + foreach ( $blocks as $block ) { + $translate = $this->get_field_attribute( $block, 'translate' ); + + if ( '1' !== $translate ) { + continue; + } + + $block_name = $this->get_field_attribute( $block, 'type' ); + + if ( '' === $block_name ) { + continue; + } + + foreach ( $block->children() as $child ) { + $rule = ''; + $child_tag = $child->getName(); + + switch ( $child_tag ) { + case 'xpath': + $rule = trim( (string) $child ); + + if ( '' !== $rule ) { + $parsing_rules['xpath'][ $block_name ][] = $rule; + } + break; + + case 'key': + $rule = $this->get_field_attributes( $child ); + + if ( empty( $rule ) ) { + break; + } + + if ( isset( $parsing_rules['key'][ $block_name ] ) ) { + $parsing_rules['key'][ $block_name ] = $this->array_merge_recursive( $parsing_rules['key'][ $block_name ], $rule ); + } else { + $parsing_rules['key'][ $block_name ] = $rule; + } + break; + } + } + } + } + + return $parsing_rules; + } + + /** + * Merge two arrays recursively. + * Unlike `array_merge_recursive()`, this method doesn't change the type of the values. + * + * @since 3.6 + * + * @param array $array1 Array to merge into. + * @param array $array2 Array to merge. + * @return array + */ + protected function array_merge_recursive( array $array1, array $array2 ): array { + foreach ( $array2 as $key => $value ) { + if ( is_array( $value ) && isset( $array1[ $key ] ) && is_array( $array1[ $key ] ) ) { + $array1[ $key ] = $this->array_merge_recursive( $array1[ $key ], $value ); + } else { + $array1[ $key ] = $value; + } + } + + return $array1; + } + + /** + * Registers or translates the strings for an option + * + * @since 2.8 + * + * @param string $context The group in which the strings will be registered. + * @param string $name Option name. + * @param SimpleXMLElement $key XML node. + * @return void + */ + protected function register_or_translate_option( $context, $name, $key ) { + $option_keys = $this->xml_to_array( $key ); + new PLL_Translate_Option( $name, reset( $option_keys ), array( 'context' => $context ) ); + } + + /** + * Recursively transforms xml nodes to an array, ready for PLL_Translate_Option. + * + * @since 2.9 + * @since 3.3 Type-hinted the parameters `$key` and `$arr`. + * @since 3.3 `$arr` is not passed by reference anymore. + * @since 3.3 Added the parameter `$fill_value`. + * + * @param SimpleXMLElement $key XML node. + * @param array $arr Array of option keys to translate. + * @param mixed $fill_value Value to use when filling entries. Default is true. + * @return array + */ + protected function xml_to_array( SimpleXMLElement $key, array $arr = array(), $fill_value = true ) { + $name = $this->get_field_attribute( $key, 'name' ); + + if ( '' === $name ) { + return $arr; + } + + $children = $key->children(); + + if ( count( $children ) ) { + foreach ( $children as $child ) { + if ( ! isset( $arr[ $name ] ) || ! is_array( $arr[ $name ] ) ) { + $arr[ $name ] = array(); + } + + $arr[ $name ] = $this->xml_to_array( $child, $arr[ $name ], $fill_value ); + } + } else { + $arr[ $name ] = $fill_value; // Multiline as in WPML. + } + + return $arr; + } + + /** + * Get the value of an attribute. + * + * @since 3.3 + * + * @param SimpleXMLElement $field A XML node. + * @param string $attribute_name Node of the attribute. + * @return string + */ + private function get_field_attribute( SimpleXMLElement $field, $attribute_name ) { + $attributes = $field->attributes(); + + if ( empty( $attributes ) || ! isset( $attributes[ $attribute_name ] ) ) { + return ''; + } + + return trim( (string) $attributes[ $attribute_name ] ); + } + + /** + * Gets attributes values recursively. + * + * @since 3.6 + * + * @param SimpleXMLElement $field A XML node. + * @return array An array of attributes. + * + * @phpstan-return array + */ + private function get_field_attributes( SimpleXMLElement $field ): array { + $name = $this->get_field_attribute( $field, 'name' ); + + if ( '' === $name ) { + return array(); + } + + $children = $field->children(); + + if ( 0 === $children->count() ) { + return array( $name => true ); + } + + $sub_attributes = array(); + + foreach ( $children as $child ) { + $sub = $this->get_field_attributes( $child ); + + if ( empty( $sub ) ) { + continue; + } + + $sub_attributes[ $name ] = array_merge( $sub_attributes[ $name ] ?? array(), $sub ); + } + + return $sub_attributes; + } + + /** + * Returns all wpml-config.xml files in MU plugins. + * + * @since 3.3 + * + * @return string[] A context identifier as array key, a file path as array value. + * + * @phpstan-return array + */ + private function get_mu_plugin_files() { + if ( ! is_readable( WPMU_PLUGIN_DIR ) || ! is_dir( WPMU_PLUGIN_DIR ) ) { + return array(); + } + + $files = array(); + + // Search for top level wpml-config.xml file. + $file_path = WPMU_PLUGIN_DIR . '/wpml-config.xml'; + + if ( is_readable( $file_path ) ) { + $files['mu-plugins'] = $file_path; + } + + // Search in proxy loaded MU plugins. + foreach ( new DirectoryIterator( WPMU_PLUGIN_DIR ) as $file_info ) { + if ( ! $this->is_dir( $file_info ) ) { + continue; + } + + $file_path = $file_info->getPathname() . '/wpml-config.xml'; + + if ( is_readable( $file_path ) ) { + $files[ 'mu-plugins/' . $file_info->getFilename() ] = $file_path; + } + } + + return $files; + } + + /** + * Returns all wpml-config.xml files in plugins. + * + * @since 3.3 + * + * @return string[] A context identifier as array key, a file path as array value. + * + * @phpstan-return array + */ + private function get_plugin_files() { + $files = array(); + $plugins = array(); + + if ( is_multisite() ) { + // Don't forget sitewide active plugins thanks to Reactorshop http://wordpress.org/support/topic/polylang-and-yoast-seo-plugin/page/2?replies=38#post-4801829. + $sitewide_plugins = get_site_option( 'active_sitewide_plugins', array() ); + + if ( ! empty( $sitewide_plugins ) && is_array( $sitewide_plugins ) ) { + $plugins = array_keys( $sitewide_plugins ); + } + } + + // By-site plugins. + $active_plugins = get_option( 'active_plugins', array() ); + + if ( ! empty( $active_plugins ) && is_array( $active_plugins ) ) { + $plugins = array_merge( $plugins, $active_plugins ); + } + + $plugin_path = trailingslashit( WP_PLUGIN_DIR ) . '%s/wpml-config.xml'; + + foreach ( $plugins as $plugin ) { + if ( ! is_string( $plugin ) || '' === $plugin ) { + continue; + } + + $file_dir = dirname( $plugin ); + $file_path = sprintf( $plugin_path, $file_dir ); + + if ( is_readable( $file_path ) ) { + $files[ "plugins/{$file_dir}" ] = $file_path; + } + } + + return $files; + } + + /** + * Returns all wpml-config.xml files in theme and child theme. + * + * @since 3.3 + * + * @return string[] A context identifier as array key, a file path as array value. + * + * @phpstan-return array + */ + private function get_theme_files() { + $files = array(); + + // Theme. + $template_path = get_template_directory(); + $file_path = "{$template_path}/wpml-config.xml"; + + if ( is_readable( $file_path ) ) { + $files[ 'themes/' . get_template() ] = $file_path; + } + + // Child theme. + $stylesheet_path = get_stylesheet_directory(); + $file_path = "{$stylesheet_path}/wpml-config.xml"; + + if ( $stylesheet_path !== $template_path && is_readable( $file_path ) ) { + $files[ 'themes/' . get_stylesheet() ] = $file_path; + } + + return $files; + } + + /** + * Returns the wpml-config.xml file in Polylang custom directory. + * + * @since 3.3 + * + * @return string[] A context identifier as array key, a file path as array value. + * + * @phpstan-return array + */ + private function get_custom_files() { + $file_path = PLL_LOCAL_DIR . '/wpml-config.xml'; + + if ( ! is_readable( $file_path ) ) { + return array(); + } + + return array( + 'Polylang' => $file_path, + ); + } + + /** + * Tells if the given "file info" object represents a directory. + * This takes care of not triggering a `open_basedir` restriction error when the file symlinks a file that is not in + * `open_basedir`. + * + * @see https://wordpress.org/support/topic/fatal-error-open_basedir-restricton/ + * + * @since 3.5.1 + * + * @param DirectoryIterator $file_info A "file info" object that we know its path (but maybe not its real path) is + * in `open_basedir`. + * @return bool + */ + private function is_dir( DirectoryIterator $file_info ): bool { + if ( $file_info->isDot() ) { + return false; + } + + if ( $file_info->getPathname() === $file_info->getRealPath() ) { + // Not a symlink: not going to trigger a `open_basedir` restriction error. + return $file_info->isDir(); + } + + /* + * Symlink: make sure the file's real path is in `open_basedir` before checking it is a dir. + * Which means that the `open_basedir` check is done only for symlinked files. + */ + return $this->is_allowed_dir( $file_info->getRealPath() ) && $file_info->isDir(); + } + + /** + * Checks whether access to a given directory is allowed. + * This takes into account the PHP `open_basedir` restrictions, so that Polylang does not try to access directories + * it is not allowed to. + * + * Inspired by `WP_Automatic_Updater::is_allowed_dir()` and `wp-includes/ID3/getid3.php`. + * + * @since 3.5.1 + * + * @param string $dir The directory to check. + * @return bool True if access to the directory is allowed, false otherwise. + */ + private function is_allowed_dir( string $dir ): bool { + $dir = trim( $dir ); + + if ( '' === $dir ) { + return false; + } + + $open_basedir_paths = $this->get_open_basedir_paths(); + + if ( empty( $open_basedir_paths ) ) { + return true; + } + + $dir = $this->normalize_path( $dir ); + + foreach ( $open_basedir_paths as $path ) { + if ( str_starts_with( $dir, $path ) ) { + return true; + } + } + + return false; + } + + /** + * Returns the list of paths in `open_basedir`. The purpose is to compare a formatted path to this list. + * Note: all paths are suffixed by `DIRECTORY_SEPARATOR`, even paths to files. + * + * @since 3.5.1 + * + * @return string[] An array of formatted paths. + */ + private function get_open_basedir_paths(): array { + if ( is_array( $this->open_basedir_paths ) ) { + return $this->open_basedir_paths; + } + + $this->open_basedir_paths = array(); + $open_basedir = ini_get( 'open_basedir' ); // Can be `false` or an empty string. + + if ( empty( $open_basedir ) ) { + return $this->open_basedir_paths; + } + + $open_basedir_list = explode( PATH_SEPARATOR, $open_basedir ); + + foreach ( $open_basedir_list as $basedir ) { + $basedir = trim( $basedir ); + + if ( '' === $basedir ) { + continue; + } + + $this->open_basedir_paths[] = $this->normalize_path( $basedir ); + } + + $this->open_basedir_paths = array_unique( $this->open_basedir_paths ); + + return $this->open_basedir_paths; + } + + /** + * Formats a path for string comparison. + * 1. Slashes and back-slashes are replaced by `DIRECTORY_SEPARATOR`. + * 2. The path is suffixed by `DIRECTORY_SEPARATOR` (even non-directory elements). + * + * @since 3.5.1 + * + * @param string $path A file path. + * @return string + * + * @phpstan-param non-empty-string $path + * @phpstan-return non-empty-string + */ + private function normalize_path( string $path ): string { + $path = str_replace( array( '/', '\\' ), DIRECTORY_SEPARATOR, $path ); + + if ( substr( $path, -1, 1 ) !== DIRECTORY_SEPARATOR ) { + $path .= DIRECTORY_SEPARATOR; + } + + return $path; + } + + /** + * Adds (or removes) meta names to the list of metas to copy or synchronize. + * + * @since 3.6 + * + * @param string[] $metas The list of meta names to copy or synchronize. + * @param string $xpath Xpath to the meta fields in the xml files. + * @param bool $sync Either sync is enabled or not. + * @return string[] + * + * @phpstan-param array $metas + * @phpstan-param non-falsy-string $xpath + */ + private function filter_metas_to_copy( array $metas, string $xpath, bool $sync ): array { + $parsed_metas = $this->parse_xml_metas( $xpath ); + $metas_to_remove = array(); + + foreach ( $parsed_metas as $name => $parsed_meta ) { + if ( 'copy' === $parsed_meta['action'] || ( ! $sync && in_array( $parsed_meta['action'], array( 'translate', 'copy-once' ), true ) ) ) { + $metas[] = $name; + } else { + $metas_to_remove[] = $name; + } + } + + return array_diff( $metas, $metas_to_remove ); + } + + /** + * Adds meta keys to export. + * + * @since 3.6 + * + * @param array $metas { + * An array containing meta keys to translate. + * Ex: array( + * 'meta_to_translate_1' => 1, + * 'meta_to_translate_2' => 1, + * 'meta_to_translate_3' => array( ... ), + * ) + * } + * @param string $xpath Xpath to the meta fields in the xml files. + * @return array + * + * @phpstan-param array $metas + * @phpstan-param non-falsy-string $xpath + * @phpstan-return array + */ + private function add_metas_to_export( array $metas, string $xpath ) { + $fields = $this->parse_xml_metas( $xpath ); + + foreach ( $fields as $name => $field ) { + if ( 'translate' === $field['action'] ) { + $metas[ $name ] = 1; + } + } + + return $metas; + } + + /** + * Adds encoding of metas. + * + * @since 3.6 + * + * @param string[] $metas The list of encodings for each metas. Meta names are array keys, encodings are array values. + * @param string $xpath Xpath to the meta fields in the xml files. + * @return string[] + * + * @phpstan-param array $metas + * @phpstan-param non-falsy-string $xpath + */ + private function add_metas_encodings( array $metas, string $xpath ): array { + $parsed_metas = $this->parse_xml_metas( $xpath ); + + foreach ( $parsed_metas as $name => $parsed_meta ) { + if ( ! empty( $parsed_meta['encoding'] ) ) { + $metas[ $name ] = $parsed_meta['encoding']; + } + } + + return $metas; + } + + /** + * Parses all xml files for metas. + * Results are cached for each `$xpath`. + * + * @since 3.6 + * + * @param string $xpath Xpath to the meta fields in the xml files. + * @return array + * + * @phpstan-param non-falsy-string $xpath + * @phpstan-return ParsedMetas + */ + private function parse_xml_metas( string $xpath ): array { + if ( isset( $this->parsed_metas[ $xpath ] ) ) { + return $this->parsed_metas[ $xpath ]; + } + + $this->parsed_metas[ $xpath ] = array(); + + foreach ( $this->xmls as $xml ) { + $custom_fields = $xml->xpath( $xpath ); + + if ( ! is_array( $custom_fields ) ) { + continue; + } + + foreach ( $custom_fields as $custom_field ) { + $name = (string) $custom_field; + + if ( empty( $name ) ) { + continue; + } + + $data = array( + 'action' => $this->get_field_attribute( $custom_field, 'action' ), + 'encoding' => $this->get_field_attribute( $custom_field, 'encoding' ), + ); + + $data['encoding'] = 'json' === $data['encoding'] ? 'json' : ''; // Only JSON is supported for now. + + $this->parsed_metas[ $xpath ][ $name ] = $data; + } + } + + return $this->parsed_metas[ $xpath ]; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-legacy-api.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-legacy-api.php new file mode 100644 index 000000000..18fba0717 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/modules/wpml/wpml-legacy-api.php @@ -0,0 +1,418 @@ + whether to skip missing translation or not, 0 or 1, defaults to 0 + * orderby => 'id', 'code', 'name', defaults to 'id' + * order => 'ASC' or 'DESC', defaults to 'ASC' + * link_empty_to => link to use when the translation is missing {$lang} is replaced by the language code + * + * List of parameters returned per language: + * + * id => the language id + * active => whether this is the active language or no, 0 or 1 + * native_name => the language name + * missing => whether the translation is missing or not, 0 or 1 + * translated_name => empty, does not exist in Polylang + * language_code => the language code ( slug ) + * country_flag_url => the url of the flag + * url => the url of the translation + * + * @since 1.0 + * + * @param string|array $args optional + * @return array array of arrays per language + */ + function icl_get_languages( $args = '' ) { + $args = wp_parse_args( $args, array( 'skip_missing' => 0, 'orderby' => 'id', 'order' => 'ASC' ) ); + $orderby = ( isset( $args['orderby'] ) && 'code' == $args['orderby'] ) ? 'slug' : ( isset( $args['orderby'] ) && 'name' == $args['orderby'] ? 'name' : 'id' ); + $order = ( ! empty( $args['order'] ) && 'desc' == $args['order'] ) ? 'DESC' : 'ASC'; + + $arr = array(); + + // NB: When 'skip_missing' is false, WPML returns all languages even if there is no content + $languages = PLL()->model->get_languages_list( array( 'hide_empty' => $args['skip_missing'] ) ); + $languages = wp_list_sort( $languages, $orderby, $order ); // Since WP 4.7 + + foreach ( $languages as $lang ) { + // We can find a translation only on frontend once the global $wp_query object has been instantiated + if ( method_exists( PLL()->links, 'get_translation_url' ) && ! empty( $GLOBALS['wp_query'] ) ) { + $url = PLL()->links->get_translation_url( $lang ); + } + + // It seems that WPML does not bother of skip_missing parameter on admin side and before the $wp_query object has been filled + if ( empty( $url ) && ! empty( $args['skip_missing'] ) && ! is_admin() && did_action( 'parse_query' ) ) { + continue; + } + + $arr[ $lang->slug ] = array( + 'id' => $lang->term_id, + 'active' => isset( PLL()->curlang->slug ) && PLL()->curlang->slug == $lang->slug ? 1 : 0, + 'native_name' => $lang->name, + 'missing' => empty( $url ) ? 1 : 0, + 'translated_name' => '', // Does not exist in Polylang + 'language_code' => $lang->slug, + 'country_flag_url' => $lang->get_display_flag_url(), + 'url' => ! empty( $url ) ? $url : + ( empty( $args['link_empty_to'] ) ? PLL()->links->get_home_url( $lang ) : + str_replace( '{$lang}', $lang->slug, $args['link_empty_to'] ) ), + ); + } + + // Apply undocumented WPML filter + $arr = apply_filters( 'icl_ls_languages', $arr ); + + return $arr; + } +} + +if ( ! function_exists( 'icl_link_to_element' ) ) { + /** + * Used for creating language dependent links in themes + * + * @since 1.0 + * @since 2.0 add support for arguments 6 and 7 + * + * @param int $id object id + * @param string $type optional, post type or taxonomy name of the object, defaults to 'post' + * @param string $text optional, the link text. If not specified will produce the name of the element in the current language + * @param array $args optional, an array of arguments to add to the link, defaults to empty + * @param string $anchor optional, the anchor to add to the link, defaults to empty + * @param bool $echo optional, whether to echo the link, defaults to true + * @param bool $return_original_if_missing optional, whether to return a value if the translation is missing + * @return string a language dependent link + */ + function icl_link_to_element( $id, $type = 'post', $text = '', $args = array(), $anchor = '', $echo = true, $return_original_if_missing = true ) { + if ( 'tag' == $type ) { + $type = 'post_tag'; + } + + $pll_type = ( 'post' == $type || pll_is_translated_post_type( $type ) ) ? 'post' : ( 'term' == $type || pll_is_translated_taxonomy( $type ) ? 'term' : false ); + if ( $pll_type && ( $lang = pll_current_language() ) && ( $tr_id = PLL()->model->$pll_type->get_translation( $id, $lang ) ) && ( 'term' === $pll_type || PLL()->model->post->current_user_can_read( $tr_id ) ) ) { + $id = $tr_id; + } elseif ( ! $return_original_if_missing ) { + return ''; + } + + if ( post_type_exists( $type ) ) { + $link = get_permalink( $id ); + if ( empty( $text ) ) { + $text = get_the_title( $id ); + } + } elseif ( taxonomy_exists( $type ) ) { + $link = get_term_link( $id, $type ); + if ( empty( $text ) && ( $term = get_term( $id, $type ) ) && $term instanceof WP_Term ) { + $text = $term->name; + } + } + + if ( empty( $link ) || is_wp_error( $link ) ) { + return ''; + } + + if ( ! empty( $args ) ) { + $link .= ( false === strpos( $link, '?' ) ? '?' : '&' ) . http_build_query( $args ); + } + + if ( ! empty( $anchor ) ) { + $link .= '#' . $anchor; + } + + $link = sprintf( '%s', esc_url( $link ), esc_html( $text ) ); + + if ( $echo ) { + echo $link; // phpcs:ignore WordPress.Security.EscapeOutput + } + + return $link; + } +} + +if ( ! function_exists( 'icl_object_id' ) ) { + /** + * Returns an element’s ID in the current language or in another specified language. + * + * @since 0.9.5 + * + * @param int $element_id Object id. + * @param string $element_type Optional, post type or taxonomy name of the object, defaults to 'post'. + * @param bool $return_original_if_missing Optional, true if Polylang should return the original id if the translation is missing, defaults to false. + * @param string|null $ulanguage_code Optional, language code, defaults to the current language. + * @return int|null The object id of the translation, null if the translation is missing and $return_original_if_missing set to false. + */ + function icl_object_id( $element_id, $element_type = 'post', $return_original_if_missing = false, $ulanguage_code = null ) { + if ( empty( $element_id ) ) { + return null; + } + + $element_id = (int) $element_id; + + if ( 'any' === $element_type ) { + $element_type = get_post_type( $element_id ); + } + + if ( empty( $element_type ) ) { + return null; + } + + if ( empty( $ulanguage_code ) ) { + $ulanguage_code = pll_current_language(); + } + + if ( 'nav_menu' === $element_type ) { + $tr_id = false; + $theme = get_option( 'stylesheet' ); + if ( isset( PLL()->options['nav_menus'][ $theme ] ) ) { + foreach ( PLL()->options['nav_menus'][ $theme ] as $menu ) { + if ( array_search( $element_id, $menu ) && ! empty( $menu[ $ulanguage_code ] ) ) { + $tr_id = $menu[ $ulanguage_code ]; + break; + } + } + } + } elseif ( pll_is_translated_post_type( $element_type ) ) { + $tr_id = PLL()->model->post->get_translation( $element_id, $ulanguage_code ); + } elseif ( pll_is_translated_taxonomy( $element_type ) ) { + $tr_id = PLL()->model->term->get_translation( $element_id, $ulanguage_code ); + } + + if ( ! isset( $tr_id ) ) { + return $element_id; // WPML doesn't honor $return_original_if_missing if the post type or taxonomy is not translated. + } + + if ( empty( $tr_id ) ) { + return $return_original_if_missing ? $element_id : null; + } + + return (int) $tr_id; + } +} + +if ( ! function_exists( 'wpml_object_id_filter' ) ) { + /** + * Undocumented alias of `icl_object_id` introduced in WPML 3.2, used by Yith WooCommerce compare + * + * @since 2.2.4 + * + * @param int $id object id + * @param string $type optional, post type or taxonomy name of the object, defaults to 'post' + * @param bool $return_original_if_missing optional, true if Polylang should return the original id if the translation is missing, defaults to false + * @param string $lang optional, language code, defaults to current language + * @return int|null the object id of the translation, null if the translation is missing and $return_original_if_missing set to false + */ + function wpml_object_id_filter( $id, $type = 'post', $return_original_if_missing = false, $lang = null ) { + return icl_object_id( $id, $type, $return_original_if_missing, $lang ); + } +} + +if ( ! function_exists( 'wpml_get_language_information' ) ) { + /** + * Undocumented function used by the theme Maya + * returns the post language + * + * @see https://wpml.org/forums/topic/canonical-urls-for-wpml-duplicated-posts/#post-52198 for the original WPML code + * + * @since 1.8 + * + * @param null $empty optional, not used + * @param int $post_id optional, post id, defaults to current post + * @return array + */ + function wpml_get_language_information( $empty = null, $post_id = null ) { + if ( empty( $post_id ) ) { + $post_id = get_the_ID(); + } + + // FIXME WPML may return a WP_Error object + return false === ( $lang = PLL()->model->post->get_language( $post_id ) ) ? array() : array( + 'language_code' => $lang->slug, + 'locale' => $lang->locale, + 'text_direction' => (bool) $lang->is_rtl, + 'display_name' => $lang->name, // Seems to be the post language name displayed in the current language, not a feature in Polylang + 'native_name' => $lang->name, + 'different_language' => pll_current_language() !== $lang->slug, + ); + } +} + +if ( ! function_exists( 'icl_register_string' ) ) { + /** + * Registers a string for translation in the "strings translation" panel + * + * The 4th and 5th parameters $allow_empty_value and $source_lang are not used by Polylang. + * + * @since 0.9.3 + * + * @param string $context the group in which the string is registered, defaults to 'polylang' + * @param string $name a unique name for the string + * @param string $string the string to register + * @return void + */ + function icl_register_string( $context, $name, $string ) { + PLL_WPML_Compat::instance()->register_string( $context, $name, $string ); + } +} + +if ( ! function_exists( 'icl_unregister_string' ) ) { + /** + * Removes a string from the "strings translation" panel + * + * @since 1.0.2 + * + * @param string $context the group in which the string is registered, defaults to 'polylang' + * @param string $name a unique name for the string + * @return void + */ + function icl_unregister_string( $context, $name ) { + PLL_WPML_Compat::instance()->unregister_string( $context, $name ); + } +} + +if ( ! function_exists( 'icl_t' ) ) { + /** + * Gets the translated value of a string ( previously registered with icl_register_string or pll_register_string ) + * + * @since 0.9.3 + * @since 1.9.2 argument 3 is optional + * @since 2.0 add support for arguments 4 to 6 + * + * @param string $context the group in which the string is registered + * @param string $name a unique name for the string + * @param string $string the string to translate, optional for strings registered with icl_register_string + * @param bool|null $has_translation optional, not supported in Polylang + * @param bool $bool optional, not used + * @param string|null $lang optional, return the translation in this language, defaults to current language + * @return string the translated string + */ + function icl_t( $context, $name, $string = '', &$has_translation = null, $bool = false, $lang = null ) { + return icl_translate( $context, $name, $string, false, $has_translation, $lang ); + } +} + +if ( ! function_exists( 'icl_translate' ) ) { + /** + * Undocumented function used by NextGen Gallery + * used in PLL_Plugins_Compat for Jetpack with only 3 arguments + * + * @since 1.0.2 + * @since 2.0 add support for arguments 5 and 6, strings are no more automatically registered + * + * @param string $context the group in which the string is registered + * @param string $name a unique name for the string + * @param string $string the string to translate, optional for strings registered with icl_register_string + * @param bool $bool optional, not used + * @param bool|null $has_translation optional, not supported in Polylang + * @param string|null $lang optional, return the translation in this language, defaults to current language + * @return string the translated string + */ + function icl_translate( $context, $name, $string = '', $bool = false, &$has_translation = null, $lang = null ) { + // FIXME WPML can automatically registers the string based on an option + if ( empty( $string ) ) { + $string = PLL_WPML_Compat::instance()->get_string_by_context_and_name( $context, $name ); + } + return empty( $lang ) ? pll__( $string ) : pll_translate_string( $string, $lang ); + } +} + +if ( ! function_exists( 'wpml_get_copied_fields_for_post_edit' ) ) { + /** + * Undocumented function used by Types + * FIXME: tested only with Types + * probably incomplete as Types locks the custom fields for a new post, but not when edited + * This is probably linked to the fact that WPML has always an original post in the default language and not Polylang :) + * + * @since 1.1.2 + * + * @return array + */ + function wpml_get_copied_fields_for_post_edit() { + if ( empty( $_GET['from_post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + return array(); + } + + $arr = array( 'original_post_id' => (int) $_GET['from_post'] ); // phpcs:ignore WordPress.Security.NonceVerification + + // Don't know what WPML does but Polylang does copy all public meta keys by default. + $keys = get_post_custom_keys( $arr['original_post_id'] ); + if ( is_array( $keys ) ) { + foreach ( $keys as $k => $meta_key ) { + if ( is_protected_meta( $meta_key ) ) { + unset( $keys[ $k ] ); + } + } + } + + // Apply our filter and fill the expected output ( see /types/embedded/includes/fields-post.php ) + /** This filter is documented in modules/sync/admin-sync.php */ + $arr['fields'] = array_unique( apply_filters( 'pll_copy_post_metas', empty( $keys ) ? array() : $keys, false ) ); + return $arr; + } +} + +if ( ! function_exists( 'icl_get_default_language' ) ) { + /** + * Undocumented function used by Warp 6 by Yootheme + * + * @since 1.0.5 + * + * @return string default language code + */ + function icl_get_default_language() { + return pll_default_language(); + } +} + +if ( ! function_exists( 'wpml_get_default_language' ) ) { + /** + * Undocumented function reported to be used by Table Rate Shipping for WooCommerce + * + * @see https://wordpress.org/support/topic/add-wpml-compatibility-function + * + * @since 1.8.2 + * + * @return string default language code + */ + function wpml_get_default_language() { + return pll_default_language(); + } +} + +if ( ! function_exists( 'icl_get_current_language' ) ) { + /** + * Undocumented function used by Ultimate Member + * + * @since 2.2.4 + * + * @return string Current language code + */ + function icl_get_current_language() { + return pll_current_language(); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/polylang.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/polylang.php new file mode 100644 index 000000000..ca076099a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/polylang.php @@ -0,0 +1,78 @@ +. + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Don't access directly. +} + +if ( defined( 'POLYLANG_VERSION' ) ) { + // The user is attempting to activate a second plugin instance, typically Polylang and Polylang Pro. + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + require_once ABSPATH . 'wp-includes/pluggable.php'; + if ( is_plugin_active( plugin_basename( __FILE__ ) ) ) { + deactivate_plugins( plugin_basename( __FILE__ ) ); // Deactivate this plugin. + // WP does not allow us to send a custom meaningful message, so just tell the plugin has been deactivated. + wp_safe_redirect( add_query_arg( 'deactivate', 'true', remove_query_arg( 'activate' ) ) ); + exit; + } +} else { + // Go on loading the plugin + define( 'POLYLANG_VERSION', '3.6.5' ); + define( 'PLL_MIN_WP_VERSION', '6.2' ); + define( 'PLL_MIN_PHP_VERSION', '7.0' ); + + define( 'POLYLANG_FILE', __FILE__ ); + define( 'POLYLANG_DIR', __DIR__ ); + + // Whether we are using Polylang or Polylang Pro, get the filename of the plugin in use. + if ( ! defined( 'POLYLANG_ROOT_FILE' ) ) { + define( 'POLYLANG_ROOT_FILE', __FILE__ ); + } + + if ( ! defined( 'POLYLANG_BASENAME' ) ) { + define( 'POLYLANG_BASENAME', plugin_basename( __FILE__ ) ); // Plugin name as known by WP. + require __DIR__ . '/vendor/autoload.php'; + } + + define( 'POLYLANG', ucwords( str_replace( '-', ' ', dirname( POLYLANG_BASENAME ) ) ) ); + + if ( empty( $_GET['deactivate-polylang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + new Polylang(); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.md b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.md new file mode 100644 index 000000000..bcf121ce6 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.md @@ -0,0 +1,29 @@ +# ![Polylang](.github/assets/polylang-logo.svg) [POLYLANG](https://wordpress.org/plugins/polylang/) + +Welcome to the Polylang repository on GitHub. Here you can browse the source, discuss open issues and keep track of the development. + +If you are not a developer, we recommend to [download Polylang](https://wordpress.org/plugins/polylang/) from WordPress directory. + +## [Pre-requisites](#pre-requisites) + +Before starting, make sure that you have the following software installed and working on your computer: + +1. A local [WordPress](https://wordpress.org/support/article/how-to-install-wordpress/) (6.2 or later) instance +2. [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to clone the Polylang repository (or your fork of the Polylang repository). +3. [Node.js](https://nodejs.org/en/download/) which provides [NPM](https://docs.npmjs.com/). They are both required by [Webpack](https://webpack.js.org/guides/getting-started/) that Polylang uses to build and minify CSS and javascript files. We recommend to install Node.js LTS version. +4. [Composer](https://getcomposer.org/doc/00-intro.md) because Polylang uses its autoloader to work and it is required to install development tools such as PHP CodeSniffer that ensures your code follows coding standards. + +## [How to set up Polylang](#how-to-setup-polylang) + +The simplest way is to clone locally this repository and build it directly in your local WordPress instance by following the steps below: + +1. Go to your local WordPress instance wp-content/plugins/ folder:
    +`cd your/local/wordpress/path/wp-content/plugins` +2. Clone there the polylang repository (or your fork) from GitHub:
    +`git clone https://github.com/polylang/polylang.git` +3. Go to your local Polylang clone folder from there: `cd polylang` +4. Run the composer command: `composer build` +5. Activate Polylang as if you had installed it from WordPress.org:
    +See + +**Note**: we recommend for Windows users to use `Git Bash` provided with [Git for Windows](https://git-scm.com/download/win) instead of the command or powershell terminal. diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.txt b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.txt new file mode 100644 index 000000000..7f02bcd00 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/readme.txt @@ -0,0 +1,167 @@ +=== Polylang === +Contributors: Chouby, manooweb, raaaahman, marianne38, sebastienserre, greglone, hugod +Donate link: https://polylang.pro +Tags: multilingual, translate, translation, language, localization +Requires at least: 6.2 +Tested up to: 6.7 +Requires PHP: 7.0 +Stable tag: 3.6.5 +License: GPLv3 or later +License URI: https://www.gnu.org/licenses/gpl-3.0.html + +Go multilingual in a simple and efficient way. Keep writing posts and taxonomy terms as usual while defining their languages all at once. + +== Description == + +With Polylang fully integrated to WordPress and using only its built-in core features (taxonomies), keep steady performances on your site and create a multilingual site featuring from just one extra language to 10 or more depending on your needs. There is no limit in the number of languages added and WordPress’ language packs are automatically downloaded when ready. + += Features = + +Depending on the type of site you have built or are planning to build, a combination of plugins from the list below might be of interest. +All plugins include a wizard allowing to setup them in just a few clicks. + +### Polylang + +Polylang and [Polylang Pro](https://polylang.pro) share the same core providing features such as: + +* Translating posts, pages, media, categories, post tags, custom post types and taxonomies, RSS feeds; RTL scripts are supported. +* The language is either set by the language code in URL, or you can use a different sub-domain or domain per language. +* Automatic copy of categories, post tags and other metas when creating a new post or page translation. +* Translating classic menus and classic widgets. Also accessible with [Site Editor Classic Features](https://wordpress.org/plugins/fse-classic/) in block themes. +* Customizable language switcher available as a classic widget or a classic navigation menu item. +* Compatibility with Yoast SEO. + +### Polylang Pro + +Helps optimizing the time spent translating your site with some very useful extra features such as: + +* Better integration in the new Block Editor. +* Language switcher available as a block. +* Language options available in the widget block editor. +* Template parts translatable in the site editor (FSE). +* Duplicate and/or synchronize content across post translations. +* Improved compatibility with other plugins such as [ACF Pro](https://polylang.pro/doc/working-with-acf-pro/). +* Share the same URL slug for posts or terms across languages. +* [Translate URL slugs](https://polylang.pro/doc/translating-urls-slugs/) for categories, author bases, custom post types and more... +* Machine translation with DeepL. +* Export and import of content in XLIFF format for outsourced professional translation. +* **Access to a Premium Support for personalized assistance.** + +### Polylang for WooCommerce + +[Add-on](https://polylang.pro/downloads/polylang-for-woocommerce/) for the compatibility with WooCommerce which provides features such as: + +* Translating WooCommerce pages (shop, check-out, cart, my account), product categories and global attribute terms directly in the WooCommerce interface. +* Translating WooCommerce e-mails and sending them to customers in their language. +* Products metadata synchronization. +* Compatibility with the native WooCommerce CSV import & export tool. +* Compatibility with popular plugins such as WooCommerce Subscriptions, Product Bundles, WooCommerce Bookings, Shipment Tracking and more. +* Ability to use the WooCommerce REST API (available with Polylang Pro). +* **Access to a Premium Support for personalized assistance.** + +Neither of them will allow to do automated translation. + += Our other free plugins = + +* [WPML to Polylang](https://wordpress.org/plugins/wpml-to-polylang/) allows migrating from WPML to Polylang. +* [DynaMo](https://wordpress.org/plugins/dynamo/) speeds up the translation of WordPress for all non-English sites. +* [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). + += Credits = + +Thanks a lot to all translators who [help translating Polylang](https://translate.wordpress.org/projects/wp-plugins/polylang). +Thanks a lot to [Alex Lopez](http://www.alexlopez.rocks/) for the design of the logo. +Most of the flags included with Polylang are coming from [famfamfam](http://famfamfam.com/) and are public domain. +Wherever third party code has been used, credit has been given in the code’s comments. + +== Installation == + +1. Make sure you are using WordPress 6.2 or later and that your server is running PHP 7.0 or later (same requirement as WordPress itself). +1. If you tried other multilingual plugins, deactivate them before activating Polylang, otherwise, you may get unexpected results! +1. Install and activate the plugin as usual from the 'Plugins' menu in WordPress. +1. The [setup wizard](https://polylang.pro/doc/setup-wizard/) is automatically launched to help you get started more easily with Polylang by configuring the main features. + +== Frequently Asked Questions == + += Where to find help ? = + +* First time users should read [Polylang - Getting started](https://polylang.pro/doc-category/getting-started/), which explains the basics and includes a lot of screenshots. +* Read the [documentation](https://polylang.pro/doc/). It includes a [FAQ](https://polylang.pro/doc-category/faq/) and the [documentation for developers](https://polylang.pro/doc-category/developers/). +* Search the [community support forum](https://wordpress.org/search/). You will probably find your answers here. +* Read the sticky posts in the [community support forum](http://wordpress.org/support/plugin/polylang). +* If you still have a problem, open a new thread in the [community support forum](http://wordpress.org/support/plugin/polylang). +* [Polylang Pro and Polylang for WooCommerce](https://polylang.pro) users have access to our premium support through helpdesk. + += Is Polylang compatible with WooCommerce? = + +* You need [Polylang for WooCommerce](https://polylang.pro/downloads/polylang-for-woocommerce/), premium addon described above, which will make both plugins work together. + +== Screenshots == + +1. The Polylang languages admin panel +2. The Strings translations admin panel +3. Multilingual media library +4. The Edit Post screen with the Languages metabox + +== Changelog == + += 3.6.5 (2024-11-05) = + +* Add compatibility with WP 6.7 +* Pro: Prevent infinite loop when the locale fallbacks reference each other +* Pro: Set canResegment attribute to no in XLIFF files +* Fix empty notice displayed if the plugin upgrade notice is set but empty + += 3.6.4 (2024-07-29) = + +* Pro: Fix infinite loop with WP 6.6 when the locale fallbacks include the main locale of a language +* Pro: Prevent saving the main locale among the locale fallbacks of a language +* Pro: Hide the characters consumption graph when the DeepL cost control is deactivated +* Add Yoast SEO social title and social description to the strings translations +* Fix incorrect page on front and page for posts translations when the option is saved with admin language filter active + += 3.6.3 (2024-06-18) = + +* Pro: Fix locale fallback for translations loaded just in time (requires WP 6.6) +* Allow to pass an array as context to icl_register_string() #1497 +* Fix admin bar search menu in WP 6.6 #1496 +* Fix a regression in the usage of the filter pll_flag #1489 + += 3.6.2 (2024-06-03) = + +* Pro: Fix XLIFF files not correctly imported when exported from older version than 3.6 +* Pro: Fix translated categories not assigned to translated post when using machine translation +* Pro: Fix 'lang' param not applied for secondary queries during a REST request +* Pro: Fix newlines for content edited in classic editor and translated with DeepL +* Pro: Fix a conflict with the Stream plugin on multisite + += 3.6.1 (2024-04-09) = + +* Pro: Fix ACF fields not shown after a post was translated with DeepL +* Remove rewrite when registering the language taxonomy #1457 +* Fix search block not filtered when displayed as button only #1459 +* Fix current language not kept when using switch_to_blog() in multisite #1458 + += 3.6 (2024-03-18) = + +* Requires WP 6.2 as minimum version +* Add compatibility with WP 6.5 +* Pro: Add DeepL machine translation for posts +* Pro: Add export and import in XLIFF 2.0/2.1 formats +* Pro: Improve translator comments in exported PO files +* Pro: Allow to export JSON encoded post and term metas in XLIFF files +* Pro: Allow to export block sub-attributes in XLIFF files +* Pro: Add footer notes block to XLIFF files +* Pro: Single files are now exported directly instead of inside a zip +* Pro: Reworked the language switcher navigation block +* Pro: Fix language switcher navigation block justification not aligned with core settings in overlay menu (requires WP 6.5) +* Pro: Fix a race condition which could lead to display a notice to the wrong user +* Pro: Fix a conflict with ACF when rewrite rules are flushed with WP-CLI on a multisite +* Pro: Fix import of several metas with same sources but different translations +* Add filter `pll_cookie_args` to filter the Polylang cookie arguments #1406 +* Fix wrong translated post types and taxononies after a `switch_to_blog()` #1415 +* Fix a minor performance issue for the page for posts #1412 +* Fix a JS errors after quick edit. Props @mcguffin #1435, #1444 +* Fix a possible warning in view-translations-post.php #1439 + +See [changelog.txt](https://plugins.svn.wordpress.org/polylang/trunk/changelog.txt) for older changelog diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/flags.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/flags.php new file mode 100644 index 000000000..239ac50fb --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/flags.php @@ -0,0 +1,276 @@ + __( 'Andorra', 'polylang' ), + 'ae' => __( 'United Arab Emirates', 'polylang' ), + 'af' => __( 'Afghanistan', 'polylang' ), + 'ag' => __( 'Antigua and Barbuda', 'polylang' ), + 'ai' => __( 'Anguilla', 'polylang' ), + 'al' => __( 'Albania', 'polylang' ), + 'am' => __( 'Armenia', 'polylang' ), + 'an' => __( 'Netherlands Antilles', 'polylang' ), + 'ao' => __( 'Angola', 'polylang' ), + 'ar' => __( 'Argentina', 'polylang' ), + 'arab' => __( 'Arab league', 'polylang' ), + 'as' => __( 'American Samoa', 'polylang' ), + 'at' => __( 'Austria', 'polylang' ), + 'au' => __( 'Australia', 'polylang' ), + 'aw' => __( 'Aruba', 'polylang' ), + 'ax' => __( 'Åland Islands', 'polylang' ), + 'az' => __( 'Azerbaijan', 'polylang' ), + 'ba' => __( 'Bosnia and Herzegovina', 'polylang' ), + 'basque' => __( 'Basque Country', 'polylang' ), + 'bb' => __( 'Barbados', 'polylang' ), + 'bd' => __( 'Bangladesh', 'polylang' ), + 'be' => __( 'Belgium', 'polylang' ), + 'bf' => __( 'Burkina Faso', 'polylang' ), + 'bg' => __( 'Bulgaria', 'polylang' ), + 'bh' => __( 'Bahrain', 'polylang' ), + 'bi' => __( 'Burundi', 'polylang' ), + 'bj' => __( 'Benin', 'polylang' ), + 'bm' => __( 'Bermuda', 'polylang' ), + 'bn' => __( 'Brunei', 'polylang' ), + 'bo' => __( 'Bolivia', 'polylang' ), + 'br' => __( 'Brazil', 'polylang' ), + 'bs' => __( 'Bahamas', 'polylang' ), + 'bt' => __( 'Bhutan', 'polylang' ), + 'bw' => __( 'Botswana', 'polylang' ), + 'by' => __( 'Belarus', 'polylang' ), + 'bz' => __( 'Belize', 'polylang' ), + 'ca' => __( 'Canada', 'polylang' ), + 'catalonia' => __( 'Catalonia', 'polylang' ), + 'cc' => __( 'Cocos', 'polylang' ), + 'cd' => __( 'Democratic Republic of the Congo', 'polylang' ), + 'cf' => __( 'Central African Republic', 'polylang' ), + 'cg' => __( 'Congo', 'polylang' ), + 'ch' => __( 'Switzerland', 'polylang' ), + 'ci' => __( 'Ivory Coast', 'polylang' ), + 'ck' => __( 'Cook Islands', 'polylang' ), + 'cl' => __( 'Chile', 'polylang' ), + 'cm' => __( 'Cameroon', 'polylang' ), + 'cn' => __( 'China', 'polylang' ), + 'co' => __( 'Colombia', 'polylang' ), + 'cr' => __( 'Costa Rica', 'polylang' ), + 'cu' => __( 'Cuba', 'polylang' ), + 'cv' => __( 'Cape Verde', 'polylang' ), + 'cx' => __( 'Christmas Island', 'polylang' ), + 'cy' => __( 'Cyprus', 'polylang' ), + 'cz' => __( 'Czech Republic', 'polylang' ), + 'de' => __( 'Germany', 'polylang' ), + 'dj' => __( 'Djibouti', 'polylang' ), + 'dk' => __( 'Denmark', 'polylang' ), + 'dm' => __( 'Dominica', 'polylang' ), + 'do' => __( 'Dominican Republic', 'polylang' ), + 'dz' => __( 'Algeria', 'polylang' ), + 'ec' => __( 'Ecuador', 'polylang' ), + 'ee' => __( 'Estonia', 'polylang' ), + 'eg' => __( 'Egypt', 'polylang' ), + 'eh' => __( 'Western Sahara', 'polylang' ), + 'england' => __( 'England', 'polylang' ), + 'er' => __( 'Eritrea', 'polylang' ), + 'es' => __( 'Spain', 'polylang' ), + 'esperanto' => __( 'Esperanto', 'polylang' ), + 'et' => __( 'Ethiopia', 'polylang' ), + 'fi' => __( 'Finland', 'polylang' ), + 'fj' => __( 'Fiji', 'polylang' ), + 'fk' => __( 'Falkland Islands', 'polylang' ), + 'fm' => __( 'Micronesia', 'polylang' ), + 'fo' => __( 'Faroe Islands', 'polylang' ), + 'fr' => __( 'France', 'polylang' ), + 'ga' => __( 'Gabon', 'polylang' ), + 'galicia' => __( 'Galicia', 'polylang' ), + 'gb' => __( 'United Kingdom', 'polylang' ), + 'gd' => __( 'Grenada', 'polylang' ), + 'ge' => __( 'Georgia', 'polylang' ), + 'gh' => __( 'Ghana', 'polylang' ), + 'gi' => __( 'Gibraltar', 'polylang' ), + 'gl' => __( 'Greenland', 'polylang' ), + 'gm' => __( 'Gambia', 'polylang' ), + 'gn' => __( 'Guinea', 'polylang' ), + 'gp' => __( 'Guadeloupe', 'polylang' ), + 'gq' => __( 'Equatorial Guinea', 'polylang' ), + 'gr' => __( 'Greece', 'polylang' ), + 'gs' => __( 'South Georgia and the South Sandwich Islands', 'polylang' ), + 'gt' => __( 'Guatemala', 'polylang' ), + 'gu' => __( 'Guam', 'polylang' ), + 'gw' => __( 'Guinea-Bissau', 'polylang' ), + 'gy' => __( 'Guyana', 'polylang' ), + 'hk' => __( 'Hong Kong', 'polylang' ), + 'hm' => __( 'Heard Island and McDonald Islands', 'polylang' ), + 'hn' => __( 'Honduras', 'polylang' ), + 'hr' => __( 'Croatia', 'polylang' ), + 'ht' => __( 'Haiti', 'polylang' ), + 'hu' => __( 'Hungary', 'polylang' ), + 'id' => __( 'Indonesia', 'polylang' ), + 'ie' => __( 'Republic of Ireland', 'polylang' ), + 'il' => __( 'Israel', 'polylang' ), + 'in' => __( 'India', 'polylang' ), + 'io' => __( 'British Indian Ocean Territory', 'polylang' ), + 'iq' => __( 'Iraq', 'polylang' ), + 'ir' => __( 'Iran', 'polylang' ), + 'is' => __( 'Iceland', 'polylang' ), + 'it' => __( 'Italy', 'polylang' ), + 'jm' => __( 'Jamaica', 'polylang' ), + 'jo' => __( 'Jordan', 'polylang' ), + 'jp' => __( 'Japan', 'polylang' ), + 'ke' => __( 'Kenya', 'polylang' ), + 'kg' => __( 'Kyrgyzstan', 'polylang' ), + 'kh' => __( 'Cambodia', 'polylang' ), + 'ki' => __( 'Kiribati', 'polylang' ), + 'km' => __( 'Comoros', 'polylang' ), + 'kn' => __( 'Saint Kitts and Nevis', 'polylang' ), + 'kp' => __( 'North Korea', 'polylang' ), + 'kr' => __( 'South Korea', 'polylang' ), + 'kurdistan' => __( 'Kurdistan', 'polylang' ), + 'kw' => __( 'Kuwait', 'polylang' ), + 'ky' => __( 'Cayman Islands', 'polylang' ), + 'kz' => __( 'Kazakhstan', 'polylang' ), + 'la' => __( 'Laos', 'polylang' ), + 'lb' => __( 'Lebanon', 'polylang' ), + 'lc' => __( 'Saint Lucia', 'polylang' ), + 'li' => __( 'Liechtenstein', 'polylang' ), + 'lk' => __( 'Sri Lanka', 'polylang' ), + 'lr' => __( 'Liberia', 'polylang' ), + 'ls' => __( 'Lesotho', 'polylang' ), + 'lt' => __( 'Lithuania', 'polylang' ), + 'lu' => __( 'Luxembourg', 'polylang' ), + 'lv' => __( 'Latvia', 'polylang' ), + 'ly' => __( 'Libya', 'polylang' ), + 'ma' => __( 'Morocco', 'polylang' ), + 'mc' => __( 'Monaco', 'polylang' ), + 'md' => __( 'Moldova', 'polylang' ), + 'me' => __( 'Montenegro', 'polylang' ), + 'mg' => __( 'Madagascar', 'polylang' ), + 'mh' => __( 'Marshall Islands', 'polylang' ), + 'mk' => __( 'North Macedonia', 'polylang' ), + 'ml' => __( 'Mali', 'polylang' ), + 'mm' => __( 'Myanmar', 'polylang' ), + 'mn' => __( 'Mongolia', 'polylang' ), + 'mo' => __( 'Macao', 'polylang' ), + 'mp' => __( 'Northern Mariana Islands', 'polylang' ), + 'mq' => __( 'Martinique', 'polylang' ), + 'mr' => __( 'Mauritania', 'polylang' ), + 'ms' => __( 'Montserrat', 'polylang' ), + 'mt' => __( 'Malta', 'polylang' ), + 'mu' => __( 'Mauritius', 'polylang' ), + 'mv' => __( 'Maldives', 'polylang' ), + 'mw' => __( 'Malawi', 'polylang' ), + 'mx' => __( 'Mexico', 'polylang' ), + 'my' => __( 'Malaysia', 'polylang' ), + 'mz' => __( 'Mozambique', 'polylang' ), + 'na' => __( 'Namibia', 'polylang' ), + 'nc' => __( 'New Caledonia', 'polylang' ), + 'ne' => __( 'Niger', 'polylang' ), + 'nf' => __( 'Norfolk Island', 'polylang' ), + 'ng' => __( 'Nigeria', 'polylang' ), + 'ni' => __( 'Nicaragua', 'polylang' ), + 'nl' => __( 'Netherlands', 'polylang' ), + 'no' => __( 'Norway', 'polylang' ), + 'np' => __( 'Nepal', 'polylang' ), + 'nr' => __( 'Nauru', 'polylang' ), + 'nu' => __( 'Niue', 'polylang' ), + 'nz' => __( 'New Zealand', 'polylang' ), + 'occitania' => __( 'Occitania', 'polylang' ), + 'om' => __( 'Oman', 'polylang' ), + 'pa' => __( 'Panama', 'polylang' ), + 'pe' => __( 'Peru', 'polylang' ), + 'pf' => __( 'French Polynesia', 'polylang' ), + 'pg' => __( 'Papua New Guinea', 'polylang' ), + 'ph' => __( 'Philippines', 'polylang' ), + 'pk' => __( 'Pakistan', 'polylang' ), + 'pl' => __( 'Poland', 'polylang' ), + 'pm' => __( 'Saint Pierre and Miquelon', 'polylang' ), + 'pn' => __( 'Pitcairn', 'polylang' ), + 'pr' => __( 'Puerto Rico', 'polylang' ), + 'ps' => __( 'Palestinian Territory', 'polylang' ), + 'pt' => __( 'Portugal', 'polylang' ), + 'pw' => __( 'Belau', 'polylang' ), + 'py' => __( 'Paraguay', 'polylang' ), + 'qa' => __( 'Qatar', 'polylang' ), + 'quebec' => __( 'Quebec', 'polylang' ), + 'ro' => __( 'Romania', 'polylang' ), + 'rs' => __( 'Serbia', 'polylang' ), + 'ru' => __( 'Russia', 'polylang' ), + 'rw' => __( 'Rwanda', 'polylang' ), + 'sa' => __( 'Saudi Arabia', 'polylang' ), + 'sb' => __( 'Solomon Islands', 'polylang' ), + 'sc' => __( 'Seychelles', 'polylang' ), + 'scotland' => __( 'Scotland', 'polylang' ), + 'sd' => __( 'Sudan', 'polylang' ), + 'se' => __( 'Sweden', 'polylang' ), + 'sg' => __( 'Singapore', 'polylang' ), + 'sh' => __( 'Saint Helena', 'polylang' ), + 'si' => __( 'Slovenia', 'polylang' ), + 'sk' => __( 'Slovakia', 'polylang' ), + 'sl' => __( 'Sierra Leone', 'polylang' ), + 'sm' => __( 'San Marino', 'polylang' ), + 'sn' => __( 'Senegal', 'polylang' ), + 'so' => __( 'Somalia', 'polylang' ), + 'sr' => __( 'Suriname', 'polylang' ), + 'ss' => __( 'South Sudan', 'polylang' ), + 'st' => __( 'São Tomé and Príncipe', 'polylang' ), + 'sv' => __( 'El Salvador', 'polylang' ), + 'sy' => __( 'Syria', 'polylang' ), + 'sz' => __( 'Swaziland', 'polylang' ), + 'tc' => __( 'Turks and Caicos Islands', 'polylang' ), + 'td' => __( 'Chad', 'polylang' ), + 'tf' => __( 'French Southern Territories', 'polylang' ), + 'tg' => __( 'Togo', 'polylang' ), + 'th' => __( 'Thailand', 'polylang' ), + 'tibet' => __( 'Tibet', 'polylang' ), + 'tj' => __( 'Tajikistan', 'polylang' ), + 'tk' => __( 'Tokelau', 'polylang' ), + 'tl' => __( 'Timor-Leste', 'polylang' ), + 'tm' => __( 'Turkmenistan', 'polylang' ), + 'tn' => __( 'Tunisia', 'polylang' ), + 'to' => __( 'Tonga', 'polylang' ), + 'tr' => __( 'Turkey', 'polylang' ), + 'tt' => __( 'Trinidad and Tobago', 'polylang' ), + 'tv' => __( 'Tuvalu', 'polylang' ), + 'tw' => __( 'Taiwan', 'polylang' ), + 'tz' => __( 'Tanzania', 'polylang' ), + 'ua' => __( 'Ukraine', 'polylang' ), + 'ug' => __( 'Uganda', 'polylang' ), + 'us' => __( 'United States', 'polylang' ), + 'uy' => __( 'Uruguay', 'polylang' ), + 'uz' => __( 'Uzbekistan', 'polylang' ), + 'va' => __( 'Vatican', 'polylang' ), + 'vc' => __( 'Saint Vincent and the Grenadines', 'polylang' ), + 've' => __( 'Venezuela', 'polylang' ), + 'veneto' => __( 'Veneto', 'polylang' ), + 'vg' => __( 'British Virgin Islands', 'polylang' ), + 'vi' => __( 'United States Virgin Islands', 'polylang' ), + 'vn' => __( 'Vietnam', 'polylang' ), + 'vu' => __( 'Vanuatu', 'polylang' ), + 'wales' => __( 'Wales', 'polylang' ), + 'wf' => __( 'Wallis and Futuna', 'polylang' ), + 'ws' => __( 'Western Samoa', 'polylang' ), + 'ye' => __( 'Yemen', 'polylang' ), + 'yt' => __( 'Mayotte', 'polylang' ), + 'za' => __( 'South Africa', 'polylang' ), + 'zm' => __( 'Zambia', 'polylang' ), + 'zw' => __( 'Zimbabwe', 'polylang' ), +); + +/** + * Filter the list of predefined flags + * + * @since 1.8 + * + * @param array $flags + */ +return apply_filters( 'pll_predefined_flags', $flags ); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/languages.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/languages.php new file mode 100644 index 000000000..3b5a7468a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/languages.php @@ -0,0 +1,1292 @@ + ISO 639-1 language code + * [locale] => WordPress locale + * [name] => name + * [dir] => text direction + * [flag] => flag code + * [w3c] => W3C locale + * [facebook] => Facebook locale + * + * Facebook locales without equivalent WordPress locale: + * 'ay_BO' (Aymara) + * 'bp_IN' (Bhojpuri) + * 'ck_US' (Cherokee) + * 'en_IN' (English India) + * 'gx_GR' (Classical Greek) + * 'ig_NG' (Igbo) + * 'ik_US' (Inupiak) + * 'iu_CA' (Inuktitut) + * 'ja_KS' (Japanese Kansai) + * 'ks_IN' (Cachemiri) + * 'lg_UG' (Ganda) + * 'nd_ZW' (Ndebele) + * 'nr_ZA' (Southern Ndebele) + * 'ns_ZA' (Northern Sotho) + * 'ny_MW' (Chewa) + * 'qc_GT' (Quiché) + * 'qu_PE' (Quechua) + * 'se_NO' (Northern Sami) + * 'ss_SZ' (Swazi) + * 'st_ZA' (Southern Sotho) + * 'tl_ST' (Klingon) + * 'tn_BW' (Tswana) + * 'ts_ZA' (Tsonga) + * 've_ZA' (Venda) + * 'wo_SN' (Wolof) + * 'yi_DE' (Yiddish) + * 'zu_ZA' (Zulu) + * 'zz_TR' (Zazaki) + */ +return array( + 'af' => array( + 'code' => 'af', + 'locale' => 'af', + 'name' => 'Afrikaans', + 'dir' => 'ltr', + 'flag' => 'za', + 'facebook' => 'af_ZA', + ), + 'ak' => array( + 'facebook' => 'ak_GH', + ), + 'am' => array( + 'code' => 'am', + 'locale' => 'am', + 'name' => 'አማርኛ', + 'dir' => 'ltr', + 'flag' => 'et', + 'facebook' => 'am_ET', + ), + 'ar' => array( + 'code' => 'ar', + 'locale' => 'ar', + 'name' => 'العربية', + 'dir' => 'rtl', + 'flag' => 'arab', + 'facebook' => 'ar_AR', + 'deepl' => 'AR', + ), + 'arg' => array( + 'code' => 'an', + 'locale' => 'arg', + 'name' => 'Aragonés', + 'dir' => 'ltr', + 'flag' => 'es', + ), + 'arq' => array( + 'facebook' => 'ar_AR', + ), + 'ary' => array( + 'code' => 'ar', + 'locale' => 'ary', + 'name' => 'العربية المغربية', + 'dir' => 'rtl', + 'flag' => 'ma', + 'facebook' => 'ar_AR', + 'deepl' => 'AR', + ), + 'as' => array( + 'code' => 'as', + 'locale' => 'as', + 'name' => 'অসমীয়া', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'as_IN', + ), + 'az' => array( + 'code' => 'az', + 'locale' => 'az', + 'name' => 'Azərbaycan', + 'dir' => 'ltr', + 'flag' => 'az', + 'facebook' => 'az_AZ', + ), + 'azb' => array( + 'code' => 'az', + 'locale' => 'azb', + 'name' => 'گؤنئی آذربایجان', + 'dir' => 'rtl', + 'flag' => 'az', + ), + 'bel' => array( + 'code' => 'be', + 'locale' => 'bel', + 'name' => 'Беларуская мова', + 'dir' => 'ltr', + 'flag' => 'by', + 'w3c' => 'be', + 'facebook' => 'be_BY', + ), + 'bg_BG' => array( + 'code' => 'bg', + 'locale' => 'bg_BG', + 'name' => 'български', + 'dir' => 'ltr', + 'flag' => 'bg', + 'facebook' => 'bg_BG', + 'deepl' => 'BG', + ), + 'bn_BD' => array( + 'code' => 'bn', + 'locale' => 'bn_BD', + 'name' => 'বাংলা', + 'dir' => 'ltr', + 'flag' => 'bd', + 'facebook' => 'bn_IN', + ), + 'bo' => array( + 'code' => 'bo', + 'locale' => 'bo', + 'name' => 'བོད་ཡིག', + 'dir' => 'ltr', + 'flag' => 'tibet', + ), + 'bre' => array( + 'w3c' => 'br', + 'facebook' => 'br_FR', + ), + 'bs_BA' => array( + 'code' => 'bs', + 'locale' => 'bs_BA', + 'name' => 'Bosanski', + 'dir' => 'ltr', + 'flag' => 'ba', + 'facebook' => 'bs_BA', + ), + 'ca' => array( + 'code' => 'ca', + 'locale' => 'ca', + 'name' => 'Català', + 'dir' => 'ltr', + 'flag' => 'catalonia', + 'facebook' => 'ca_ES', + ), + 'ceb' => array( + 'code' => 'ceb', + 'locale' => 'ceb', + 'name' => 'Cebuano', + 'dir' => 'ltr', + 'flag' => 'ph', + 'facebook' => 'cx_PH', + ), + 'ckb' => array( + 'code' => 'ku', + 'locale' => 'ckb', + 'name' => 'کوردی', + 'dir' => 'rtl', + 'flag' => 'kurdistan', + 'facebook' => 'cb_IQ', + ), + 'co' => array( + 'facebook' => 'co_FR', + ), + 'cs_CZ' => array( + 'code' => 'cs', + 'locale' => 'cs_CZ', + 'name' => 'Čeština', + 'dir' => 'ltr', + 'flag' => 'cz', + 'facebook' => 'cs_CZ', + 'deepl' => 'CS', + ), + 'cy' => array( + 'code' => 'cy', + 'locale' => 'cy', + 'name' => 'Cymraeg', + 'dir' => 'ltr', + 'flag' => 'wales', + 'facebook' => 'cy_GB', + ), + 'da_DK' => array( + 'code' => 'da', + 'locale' => 'da_DK', + 'name' => 'Dansk', + 'dir' => 'ltr', + 'flag' => 'dk', + 'facebook' => 'da_DK', + 'deepl' => 'DA', + ), + 'de_AT' => array( + 'code' => 'de', + 'locale' => 'de_AT', + 'name' => 'Deutsch', + 'dir' => 'ltr', + 'flag' => 'at', + 'facebook' => 'de_DE', + 'deepl' => 'DE', + ), + 'de_CH' => array( + 'code' => 'de', + 'locale' => 'de_CH', + 'name' => 'Deutsch', + 'dir' => 'ltr', + 'flag' => 'ch', + 'facebook' => 'de_DE', + 'deepl' => 'DE', + ), + 'de_CH_informal' => array( + 'code' => 'de', + 'locale' => 'de_CH_informal', + 'name' => 'Deutsch', + 'dir' => 'ltr', + 'flag' => 'ch', + 'w3c' => 'de-CH', + 'facebook' => 'de_DE', + 'deepl' => 'DE', + ), + 'de_DE' => array( + 'code' => 'de', + 'locale' => 'de_DE', + 'name' => 'Deutsch', + 'dir' => 'ltr', + 'flag' => 'de', + 'facebook' => 'de_DE', + 'deepl' => 'DE', + ), + 'de_DE_formal' => array( + 'code' => 'de', + 'locale' => 'de_DE_formal', + 'name' => 'Deutsch', + 'dir' => 'ltr', + 'flag' => 'de', + 'w3c' => 'de-DE', + 'facebook' => 'de_DE', + 'deepl' => 'DE', + ), + 'dsb' => array( + 'code' => 'dsb', + 'locale' => 'dsb', + 'name' => 'Dolnoserbšćina', + 'dir' => 'ltr', + 'flag' => 'de', + ), + 'dzo' => array( + 'code' => 'dz', + 'locale' => 'dzo', + 'name' => 'རྫོང་ཁ', + 'dir' => 'ltr', + 'flag' => 'bt', + 'w3c' => 'dz', + ), + 'el' => array( + 'code' => 'el', + 'locale' => 'el', + 'name' => 'Ελληνικά', + 'dir' => 'ltr', + 'flag' => 'gr', + 'facebook' => 'el_GR', + 'deepl' => 'EL', + ), + 'en_AU' => array( + 'code' => 'en', + 'locale' => 'en_AU', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'au', + 'facebook' => 'en_US', + 'deepl' => 'EN-US', + ), + 'en_CA' => array( + 'code' => 'en', + 'locale' => 'en_CA', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'ca', + 'facebook' => 'en_US', + 'deepl' => 'EN-US', + ), + 'en_GB' => array( + 'code' => 'en', + 'locale' => 'en_GB', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'gb', + 'facebook' => 'en_GB', + 'deepl' => 'EN-GB', + ), + 'en_NZ' => array( + 'code' => 'en', + 'locale' => 'en_NZ', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'nz', + 'facebook' => 'en_US', + 'deepl' => 'EN-US', + ), + 'en_US' => array( + 'code' => 'en', + 'locale' => 'en_US', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'us', + 'facebook' => 'en_US', + 'deepl' => 'EN-US', + ), + 'en_ZA' => array( + 'code' => 'en', + 'locale' => 'en_ZA', + 'name' => 'English', + 'dir' => 'ltr', + 'flag' => 'za', + 'facebook' => 'en_US', + 'deepl' => 'EN-US', + ), + 'eo' => array( + 'code' => 'eo', + 'locale' => 'eo', + 'name' => 'Esperanto', + 'dir' => 'ltr', + 'flag' => 'esperanto', + 'facebook' => 'eo_EO', + ), + 'es_AR' => array( + 'code' => 'es', + 'locale' => 'es_AR', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'ar', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_CL' => array( + 'code' => 'es', + 'locale' => 'es_CL', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'cl', + 'facebook' => 'es_CL', + 'deepl' => 'ES', + ), + 'es_CO' => array( + 'code' => 'es', + 'locale' => 'es_CO', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'co', + 'facebook' => 'es_CO', + 'deepl' => 'ES', + ), + 'es_CR' => array( + 'code' => 'es', + 'locale' => 'es_CR', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'cr', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_DO' => array( + 'code' => 'es', + 'locale' => 'es_DO', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'do', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_EC' => array( + 'code' => 'es', + 'locale' => 'es_EC', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'ec', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_ES' => array( + 'code' => 'es', + 'locale' => 'es_ES', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'es', + 'facebook' => 'es_ES', + 'deepl' => 'ES', + ), + 'es_GT' => array( + 'code' => 'es', + 'locale' => 'es_GT', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'gt', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_MX' => array( + 'code' => 'es', + 'locale' => 'es_MX', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'mx', + 'facebook' => 'es_MX', + 'deepl' => 'ES', + ), + 'es_PE' => array( + 'code' => 'es', + 'locale' => 'es_PE', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'pe', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_PR' => array( + 'code' => 'es', + 'locale' => 'es_PR', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'pr', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_UY' => array( + 'code' => 'es', + 'locale' => 'es_UY', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 'uy', + 'facebook' => 'es_LA', + 'deepl' => 'ES', + ), + 'es_VE' => array( + 'code' => 'es', + 'locale' => 'es_VE', + 'name' => 'Español', + 'dir' => 'ltr', + 'flag' => 've', + 'facebook' => 'es_VE', + 'deepl' => 'ES', + ), + 'et' => array( + 'code' => 'et', + 'locale' => 'et', + 'name' => 'Eesti', + 'dir' => 'ltr', + 'flag' => 'ee', + 'facebook' => 'et_EE', + 'deepl' => 'ET', + ), + 'eu' => array( + 'code' => 'eu', + 'locale' => 'eu', + 'name' => 'Euskara', + 'dir' => 'ltr', + 'flag' => 'basque', + 'facebook' => 'eu_ES', + ), + 'fa_AF' => array( + 'code' => 'fa', + 'locale' => 'fa_AF', + 'name' => 'فارسی', + 'dir' => 'rtl', + 'flag' => 'af', + 'facebook' => 'fa_IR', + ), + 'fa_IR' => array( + 'code' => 'fa', + 'locale' => 'fa_IR', + 'name' => 'فارسی', + 'dir' => 'rtl', + 'flag' => 'ir', + 'facebook' => 'fa_IR', + ), + 'fi' => array( + 'code' => 'fi', + 'locale' => 'fi', + 'name' => 'Suomi', + 'dir' => 'ltr', + 'flag' => 'fi', + 'facebook' => 'fi_FI', + 'deepl' => 'FI', + ), + 'fo' => array( + 'code' => 'fo', + 'locale' => 'fo', + 'name' => 'Føroyskt', + 'dir' => 'ltr', + 'flag' => 'fo', + 'facebook' => 'fo_FO', + ), + 'fr_BE' => array( + 'code' => 'fr', + 'locale' => 'fr_BE', + 'name' => 'Français', + 'dir' => 'ltr', + 'flag' => 'be', + 'facebook' => 'fr_FR', + 'deepl' => 'FR', + ), + 'fr_CA' => array( + 'code' => 'fr', + 'locale' => 'fr_CA', + 'name' => 'Français', + 'dir' => 'ltr', + 'flag' => 'quebec', + 'facebook' => 'fr_CA', + 'deepl' => 'FR', + ), + 'fr_FR' => array( + 'code' => 'fr', + 'locale' => 'fr_FR', + 'name' => 'Français', + 'dir' => 'ltr', + 'flag' => 'fr', + 'facebook' => 'fr_FR', + 'deepl' => 'FR', + ), + 'fuc' => array( + 'facebook' => 'ff_NG', + ), + 'fur' => array( + 'code' => 'fur', + 'locale' => 'fur', + 'name' => 'Furlan', + 'dir' => 'ltr', + 'flag' => 'it', + ), + 'fy' => array( + 'code' => 'fy', + 'locale' => 'fy', + 'name' => 'Frysk', + 'dir' => 'ltr', + 'flag' => 'nl', + 'facebook' => 'fy_NL', + ), + 'ga' => array( + 'facebook' => 'ga_IE', + ), + 'gax' => array( + 'facebook' => 'om_ET', + ), + 'gd' => array( + 'code' => 'gd', + 'locale' => 'gd', + 'name' => 'Gàidhlig', + 'dir' => 'ltr', + 'flag' => 'scotland', + ), + 'gl_ES' => array( + 'code' => 'gl', + 'locale' => 'gl_ES', + 'name' => 'Galego', + 'dir' => 'ltr', + 'flag' => 'galicia', + 'facebook' => 'gl_ES', + ), + 'gn' => array( + 'facebook' => 'gn_PY', + ), + 'gu' => array( + 'code' => 'gu', + 'locale' => 'gu', + 'name' => 'ગુજરાતી', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'gu_IN', + ), + 'hat' => array( + 'facebook' => 'ht_HT', + ), + 'hau' => array( + 'facebook' => 'ha_NG', + ), + 'haz' => array( + 'code' => 'haz', + 'locale' => 'haz', + 'name' => 'هزاره گی', + 'dir' => 'rtl', + 'flag' => 'af', + ), + 'he_IL' => array( + 'code' => 'he', + 'locale' => 'he_IL', + 'name' => 'עברית', + 'dir' => 'rtl', + 'flag' => 'il', + 'facebook' => 'he_IL', + ), + 'hi_IN' => array( + 'code' => 'hi', + 'locale' => 'hi_IN', + 'name' => 'हिन्दी', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'hi_IN', + ), + 'hr' => array( + 'code' => 'hr', + 'locale' => 'hr', + 'name' => 'Hrvatski', + 'dir' => 'ltr', + 'flag' => 'hr', + 'facebook' => 'hr_HR', + ), + 'hu_HU' => array( + 'code' => 'hu', + 'locale' => 'hu_HU', + 'name' => 'Magyar', + 'dir' => 'ltr', + 'flag' => 'hu', + 'facebook' => 'hu_HU', + 'deepl' => 'HU', + ), + 'hsb' => array( + 'code' => 'hsb', + 'locale' => 'hsb', + 'name' => 'Hornjoserbšćina', + 'dir' => 'ltr', + 'flag' => 'de', + ), + 'hy' => array( + 'code' => 'hy', + 'locale' => 'hy', + 'name' => 'Հայերեն', + 'dir' => 'ltr', + 'flag' => 'am', + 'facebook' => 'hy_AM', + ), + 'id_ID' => array( + 'code' => 'id', + 'locale' => 'id_ID', + 'name' => 'Bahasa Indonesia', + 'dir' => 'ltr', + 'flag' => 'id', + 'facebook' => 'id_ID', + 'deepl' => 'ID', + ), + 'ido' => array( + 'w3c' => 'io', + ), + 'is_IS' => array( + 'code' => 'is', + 'locale' => 'is_IS', + 'name' => 'Íslenska', + 'dir' => 'ltr', + 'flag' => 'is', + 'facebook' => 'is_IS', + ), + 'it_IT' => array( + 'code' => 'it', + 'locale' => 'it_IT', + 'name' => 'Italiano', + 'dir' => 'ltr', + 'flag' => 'it', + 'facebook' => 'it_IT', + 'deepl' => 'IT', + ), + 'ja' => array( + 'code' => 'ja', + 'locale' => 'ja', + 'name' => '日本語', + 'dir' => 'ltr', + 'flag' => 'jp', + 'facebook' => 'ja_JP', + 'deepl' => 'JA', + ), + 'jv_ID' => array( + 'code' => 'jv', + 'locale' => 'jv_ID', + 'name' => 'Basa Jawa', + 'dir' => 'ltr', + 'flag' => 'id', + 'facebook' => 'jv_ID', + ), + 'ka_GE' => array( + 'code' => 'ka', + 'locale' => 'ka_GE', + 'name' => 'ქართული', + 'dir' => 'ltr', + 'flag' => 'ge', + 'facebook' => 'ka_GE', + ), + 'kab' => array( + 'code' => 'kab', + 'locale' => 'kab', + 'name' => 'Taqbaylit', + 'dir' => 'ltr', + 'flag' => 'dz', + ), + 'kin' => array( + 'w3c' => 'rw', + 'facebook' => 'rw_RW', + ), + 'kir' => array( + 'code' => 'ky', + 'locale' => 'kir', + 'name' => 'Кыргызча', + 'dir' => 'ltr', + 'flag' => 'kg', + ), + 'kk' => array( + 'code' => 'kk', + 'locale' => 'kk', + 'name' => 'Қазақ тілі', + 'dir' => 'ltr', + 'flag' => 'kz', + 'facebook' => 'kk_KZ', + ), + 'km' => array( + 'code' => 'km', + 'locale' => 'km', + 'name' => 'ភាសាខ្មែរ', + 'dir' => 'ltr', + 'flag' => 'kh', + 'facebook' => 'km_KH', + ), + 'kn' => array( + 'code' => 'kn', + 'locale' => 'kn', + 'name' => 'ಕನ್ನಡ', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'kn_IN', + ), + 'ko_KR' => array( + 'code' => 'ko', + 'locale' => 'ko_KR', + 'name' => '한국어', + 'dir' => 'ltr', + 'flag' => 'kr', + 'facebook' => 'ko_KR', + 'deepl' => 'KO', + ), + 'ku' => array( + 'facebook' => 'ku_TR', + ), + 'ky_KY' => array( + 'facebook' => 'ky_KG', + ), + 'la' => array( + 'facebook' => 'la_VA', + ), + 'li' => array( + 'facebook' => 'li_NL', + ), + 'lin' => array( + 'facebook' => 'ln_CD', + ), + 'lo' => array( + 'code' => 'lo', + 'locale' => 'lo', + 'name' => 'ພາສາລາວ', + 'dir' => 'ltr', + 'flag' => 'la', + 'facebook' => 'lo_LA', + ), + 'lt_LT' => array( + 'code' => 'lt', + 'locale' => 'lt_LT', + 'name' => 'Lietuviškai', + 'dir' => 'ltr', + 'flag' => 'lt', + 'facebook' => 'lt_LT', + 'deepl' => 'LT', + ), + 'lv' => array( + 'code' => 'lv', + 'locale' => 'lv', + 'name' => 'Latviešu valoda', + 'dir' => 'ltr', + 'flag' => 'lv', + 'facebook' => 'lv_LV', + 'deepl' => 'LV', + ), + 'mg_MG' => array( + 'facebook' => 'mg_MG', + ), + 'mk_MK' => array( + 'code' => 'mk', + 'locale' => 'mk_MK', + 'name' => 'македонски јазик', + 'dir' => 'ltr', + 'flag' => 'mk', + 'facebook' => 'mk_MK', + ), + 'ml_IN' => array( + 'code' => 'ml', + 'locale' => 'ml_IN', + 'name' => 'മലയാളം', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'ml_IN', + ), + 'mlt' => array( + 'facebook' => 'mt_MT', + ), + 'mn' => array( + 'code' => 'mn', + 'locale' => 'mn', + 'name' => 'Монгол хэл', + 'dir' => 'ltr', + 'flag' => 'mn', + 'facebook' => 'mn_MN', + ), + 'mr' => array( + 'code' => 'mr', + 'locale' => 'mr', + 'name' => 'मराठी', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'mr_IN', + ), + 'mri' => array( + 'w3c' => 'mi', + 'facebook' => 'mi_NZ', + ), + 'ms_MY' => array( + 'code' => 'ms', + 'locale' => 'ms_MY', + 'name' => 'Bahasa Melayu', + 'dir' => 'ltr', + 'flag' => 'my', + 'facebook' => 'ms_MY', + ), + 'my_MM' => array( + 'code' => 'my', + 'locale' => 'my_MM', + 'name' => 'ဗမာစာ', + 'dir' => 'ltr', + 'flag' => 'mm', + 'facebook' => 'my_MM', + ), + 'nb_NO' => array( + 'code' => 'nb', + 'locale' => 'nb_NO', + 'name' => 'Norsk Bokmål', + 'dir' => 'ltr', + 'flag' => 'no', + 'facebook' => 'nb_NO', + 'deepl' => 'NB', + ), + 'ne_NP' => array( + 'code' => 'ne', + 'locale' => 'ne_NP', + 'name' => 'नेपाली', + 'dir' => 'ltr', + 'flag' => 'np', + 'facebook' => 'ne_NP', + ), + 'nl_BE' => array( + 'code' => 'nl', + 'locale' => 'nl_BE', + 'name' => 'Nederlands', + 'dir' => 'ltr', + 'flag' => 'be', + 'facebook' => 'nl_BE', + 'deepl' => 'NL', + ), + 'nl_NL' => array( + 'code' => 'nl', + 'locale' => 'nl_NL', + 'name' => 'Nederlands', + 'dir' => 'ltr', + 'flag' => 'nl', + 'facebook' => 'nl_NL', + 'deepl' => 'NL', + ), + 'nl_NL_formal' => array( + 'code' => 'nl', + 'locale' => 'nl_NL_formal', + 'name' => 'Nederlands', + 'dir' => 'ltr', + 'flag' => 'nl', + 'w3c' => 'nl-NL', + 'facebook' => 'nl_NL', + 'deepl' => 'NL', + ), + 'nn_NO' => array( + 'code' => 'nn', + 'locale' => 'nn_NO', + 'name' => 'Norsk Nynorsk', + 'dir' => 'ltr', + 'flag' => 'no', + 'facebook' => 'nn_NO', + ), + 'oci' => array( + 'code' => 'oc', + 'locale' => 'oci', + 'name' => 'Occitan', + 'dir' => 'ltr', + 'flag' => 'occitania', + 'w3c' => 'oc', + ), + 'ory' => array( + 'facebook' => 'or_IN', + ), + 'pa_IN' => array( + 'code' => 'pa', + 'locale' => 'pa_IN', + 'name' => 'ਪੰਜਾਬੀ', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'pa_IN', + ), + 'pl_PL' => array( + 'code' => 'pl', + 'locale' => 'pl_PL', + 'name' => 'Polski', + 'dir' => 'ltr', + 'flag' => 'pl', + 'facebook' => 'pl_PL', + 'deepl' => 'PL', + ), + 'ps' => array( + 'code' => 'ps', + 'locale' => 'ps', + 'name' => 'پښتو', + 'dir' => 'rtl', + 'flag' => 'af', + 'facebook' => 'ps_AF', + ), + 'pt_AO' => array( + 'code' => 'pt', + 'locale' => 'pt_AO', + 'name' => 'Português', + 'dir' => 'ltr', + 'flag' => 'ao', + 'facebook' => 'pt_PT', + 'deepl' => 'PT-PT', + ), + 'pt_BR' => array( + 'code' => 'pt', + 'locale' => 'pt_BR', + 'name' => 'Português', + 'dir' => 'ltr', + 'flag' => 'br', + 'facebook' => 'pt_BR', + 'deepl' => 'PT-BR', + ), + 'pt_PT' => array( + 'code' => 'pt', + 'locale' => 'pt_PT', + 'name' => 'Português', + 'dir' => 'ltr', + 'flag' => 'pt', + 'facebook' => 'pt_PT', + 'deepl' => 'PT-PT', + ), + 'pt_PT_ao90' => array( + 'code' => 'pt', + 'locale' => 'pt_PT_ao90', + 'name' => 'Português', + 'dir' => 'ltr', + 'flag' => 'pt', + 'facebook' => 'pt_PT', + 'deepl' => 'PT-PT', + ), + 'rhg' => array( + 'code' => 'rhg', + 'locale' => 'rhg', + 'name' => 'Ruáinga', + 'dir' => 'ltr', + 'flag' => 'mm', + ), + 'ro_RO' => array( + 'code' => 'ro', + 'locale' => 'ro_RO', + 'name' => 'Română', + 'dir' => 'ltr', + 'flag' => 'ro', + 'facebook' => 'ro_RO', + 'deepl' => 'RO', + ), + 'roh' => array( + 'w3c' => 'rm', + 'facebook' => 'rm_CH', + ), + 'ru_RU' => array( + 'code' => 'ru', + 'locale' => 'ru_RU', + 'name' => 'Русский', + 'dir' => 'ltr', + 'flag' => 'ru', + 'facebook' => 'ru_RU', + 'deepl' => 'RU', + ), + 'sa_IN' => array( + 'facebook' => 'sa_IN', + ), + 'sah' => array( + 'code' => 'sah', + 'locale' => 'sah', + 'name' => 'Сахалыы', + 'dir' => 'ltr', + 'flag' => 'ru', + ), + 'si_LK' => array( + 'code' => 'si', + 'locale' => 'si_LK', + 'name' => 'සිංහල', + 'dir' => 'ltr', + 'flag' => 'lk', + 'facebook' => 'si_LK', + ), + 'sk_SK' => array( + 'code' => 'sk', + 'locale' => 'sk_SK', + 'name' => 'Slovenčina', + 'dir' => 'ltr', + 'flag' => 'sk', + 'facebook' => 'sk_SK', + 'deepl' => 'SK', + ), + 'skr' => array( + 'code' => 'skr', + 'locale' => 'skr', + 'name' => 'سرائیکی', + 'dir' => 'rtl', + 'flag' => 'pk', + ), + 'sl_SI' => array( + 'code' => 'sl', + 'locale' => 'sl_SI', + 'name' => 'Slovenščina', + 'dir' => 'ltr', + 'flag' => 'si', + 'facebook' => 'sl_SI', + 'deepl' => 'SL', + ), + 'sna' => array( + 'facebook' => 'sn_ZW', + ), + 'snd' => array( + 'code' => 'sd', + 'locale' => 'snd', + 'name' => 'سنڌي', + 'dir' => 'rtl', + 'flag' => 'pk', + ), + 'so_SO' => array( + 'code' => 'so', + 'locale' => 'so_SO', + 'name' => 'Af-Soomaali', + 'dir' => 'ltr', + 'flag' => 'so', + 'facebook' => 'so_SO', + ), + 'sq' => array( + 'code' => 'sq', + 'locale' => 'sq', + 'name' => 'Shqip', + 'dir' => 'ltr', + 'flag' => 'al', + 'facebook' => 'sq_AL', + ), + 'sr_RS' => array( + 'code' => 'sr', + 'locale' => 'sr_RS', + 'name' => 'Српски језик', + 'dir' => 'ltr', + 'flag' => 'rs', + 'facebook' => 'sr_RS', + ), + 'srd' => array( + 'w3c' => 'sc', + 'facebook' => 'sc_IT', + ), + 'su_ID' => array( + 'code' => 'su', + 'locale' => 'su_ID', + 'name' => 'Basa Sunda', + 'dir' => 'ltr', + 'flag' => 'id', + 'facebook' => 'su_ID', + ), + 'sv_SE' => array( + 'code' => 'sv', + 'locale' => 'sv_SE', + 'name' => 'Svenska', + 'dir' => 'ltr', + 'flag' => 'se', + 'facebook' => 'sv_SE', + 'deepl' => 'SV', + ), + 'sw' => array( + 'code' => 'sw', + 'locale' => 'sw', + 'name' => 'Kiswahili', + 'dir' => 'ltr', + 'flag' => 'ke', + 'facebook' => 'sw_KE', + ), + 'syr' => array( + 'facebook' => 'sy_SY', + ), + 'szl' => array( + 'code' => 'szl', + 'locale' => 'szl', + 'name' => 'Ślōnskŏ gŏdka', + 'dir' => 'ltr', + 'flag' => 'pl', + 'facebook' => 'sz_PL', + ), + 'ta_IN' => array( + 'code' => 'ta', + 'locale' => 'ta_IN', + 'name' => 'தமிழ்', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'ta_IN', + ), + 'ta_LK' => array( + 'code' => 'ta', + 'locale' => 'ta_LK', + 'name' => 'தமிழ்', + 'dir' => 'ltr', + 'flag' => 'lk', + 'facebook' => 'ta_IN', + ), + 'tah' => array( + 'code' => 'ty', + 'locale' => 'tah', + 'name' => 'Reo Tahiti', + 'dir' => 'ltr', + 'flag' => 'pf', + ), + 'te' => array( + 'code' => 'te', + 'locale' => 'te', + 'name' => 'తెలుగు', + 'dir' => 'ltr', + 'flag' => 'in', + 'facebook' => 'te_IN', + ), + 'tg' => array( + 'facebook' => 'tg_TJ', + ), + 'th' => array( + 'code' => 'th', + 'locale' => 'th', + 'name' => 'ไทย', + 'dir' => 'ltr', + 'flag' => 'th', + 'facebook' => 'th_TH', + ), + 'tl' => array( + 'code' => 'tl', + 'locale' => 'tl', + 'name' => 'Tagalog', + 'dir' => 'ltr', + 'flag' => 'ph', + 'facebook' => 'tl_PH', + ), + 'tr_TR' => array( + 'code' => 'tr', + 'locale' => 'tr_TR', + 'name' => 'Türkçe', + 'dir' => 'ltr', + 'flag' => 'tr', + 'facebook' => 'tr_TR', + 'deepl' => 'TR', + ), + 'tt_RU' => array( + 'code' => 'tt', + 'locale' => 'tt_RU', + 'name' => 'Татар теле', + 'dir' => 'ltr', + 'flag' => 'ru', + 'facebook' => 'tt_RU', + ), + 'tuk' => array( + 'w3c' => 'tk', + 'facebook' => 'tk_TM', + ), + 'tzm' => array( + 'facebook' => 'tz_MA', + ), + 'ug_CN' => array( + 'code' => 'ug', + 'locale' => 'ug_CN', + 'name' => 'Uyƣurqə', + 'dir' => 'ltr', + 'flag' => 'cn', + ), + 'uk' => array( + 'code' => 'uk', + 'locale' => 'uk', + 'name' => 'Українська', + 'dir' => 'ltr', + 'flag' => 'ua', + 'facebook' => 'uk_UA', + 'deepl' => 'UK', + ), + 'ur' => array( + 'code' => 'ur', + 'locale' => 'ur', + 'name' => 'اردو', + 'dir' => 'rtl', + 'flag' => 'pk', + 'facebook' => 'ur_PK', + ), + 'uz_UZ' => array( + 'code' => 'uz', + 'locale' => 'uz_UZ', + 'name' => 'Oʻzbek', + 'dir' => 'ltr', + 'flag' => 'uz', + 'facebook' => 'uz_UZ', + ), + 'vec' => array( + 'code' => 'vec', + 'locale' => 'vec', + 'name' => 'Vèneto', + 'dir' => 'ltr', + 'flag' => 'veneto', + ), + 'vi' => array( + 'code' => 'vi', + 'locale' => 'vi', + 'name' => 'Tiếng Việt', + 'dir' => 'ltr', + 'flag' => 'vn', + 'facebook' => 'vi_VN', + ), + 'xho' => array( + 'facebook' => 'xh_ZA', + ), + 'yor' => array( + 'facebook' => 'yo_NG', + ), + 'zh_CN' => array( + 'code' => 'zh', + 'locale' => 'zh_CN', + 'name' => '中文 (中国)', + 'dir' => 'ltr', + 'flag' => 'cn', + 'facebook' => 'zh_CN', + 'deepl' => 'ZH', + ), + 'zh_HK' => array( + 'code' => 'zh', + 'locale' => 'zh_HK', + 'name' => '中文 (香港)', + 'dir' => 'ltr', + 'flag' => 'hk', + 'facebook' => 'zh_HK', + 'deepl' => 'ZH', + ), + 'zh_TW' => array( + 'code' => 'zh', + 'locale' => 'zh_TW', + 'name' => '中文 (台灣)', + 'dir' => 'ltr', + 'flag' => 'tw', + 'facebook' => 'zh_TW', + 'deepl' => 'ZH', + ), +); diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-browser.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-browser.php new file mode 100644 index 000000000..80b4e3085 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-browser.php @@ -0,0 +1,107 @@ +is_available()`, which is used before calling the parent's constructor. + $this->options = &$polylang->options; + + parent::__construct( + $polylang, + array( + 'module' => 'browser', + 'title' => __( 'Detect browser language', 'polylang' ), + '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' ), + 'active_option' => $this->is_available() ? 'browser' : 'none', + ) + ); + + if ( ! class_exists( 'PLL_Xdata_Domain', true ) ) { + add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) ); + } + } + + /** + * Tells if the option is available + * + * @since 2.0 + * + * @return bool + */ + protected function is_available() { + return ( 3 > $this->options['force_lang'] ) || class_exists( 'PLL_Xdata_Domain', true ); + } + + /** + * Tells if the module is active + * + * @since 1.8 + * + * @return bool + */ + public function is_active() { + return $this->is_available() ? parent::is_active() : false; + } + + /** + * Displays the javascript to handle dynamically the change in url modifications + * as the preferred browser language is not used when the language is set from different domains + * + * @since 1.8 + * + * @return void + */ + public function print_js() { + wp_enqueue_script( 'jquery' ); + + if ( parent::is_active() && 3 > $this->options['force_lang'] ) { + $func = 'removeClass( "inactive" ).addClass( "active" )'; + $link = sprintf( '%s', $this->action_links['deactivate'] ); + } + else { + $func = 'removeClass( "active" ).addClass( "inactive" )'; + $link = sprintf( '%s', $this->action_links['activate'] ); + } + + $deactivated = sprintf( '%s', $this->action_links['deactivated'] ); + + ?> + + 'cpt', + 'title' => __( 'Custom post types and Taxonomies', 'polylang' ), + 'description' => __( 'Activate languages and translations management for the custom post types and the taxonomies.', 'polylang' ), + ) + ); + + $public_post_types = get_post_types( array( 'public' => true, '_builtin' => false ) ); + /** This filter is documented in include/model.php */ + $this->post_types = array_unique( apply_filters( 'pll_get_post_types', $public_post_types, true ) ); + + /** This filter is documented in include/model.php */ + $programmatically_active_post_types = array_unique( apply_filters( 'pll_get_post_types', array(), false ) ); + $this->disabled_post_types = array_intersect( $programmatically_active_post_types, $this->post_types ); + + $public_taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false ) ); + $public_taxonomies = array_diff( $public_taxonomies, get_taxonomies( array( '_pll' => true ) ) ); + /** This filter is documented in include/model.php */ + $this->taxonomies = array_unique( apply_filters( 'pll_get_taxonomies', $public_taxonomies, true ) ); + + /** This filter is documented in include/model.php */ + $programmatically_active_taxonomies = array_unique( apply_filters( 'pll_get_taxonomies', array(), false ) ); + $this->disabled_taxonomies = array_intersect( $programmatically_active_taxonomies, $this->taxonomies ); + } + + /** + * Tells if the module is active + * + * @since 1.8 + * + * @return bool + */ + public function is_active() { + return ! empty( $this->post_types ) || ! empty( $this->taxonomies ); + } + + /** + * Displays the settings form + * + * @since 1.8 + */ + protected function form() { + if ( ! empty( $this->post_types ) ) {?> +

    +
      + post_types as $post_type ) { + $pt = get_post_type_object( $post_type ); + if ( ! empty( $pt ) ) { + $disabled = in_array( $post_type, $this->disabled_post_types ); + printf( + '
    • ', + esc_attr( $post_type ), + checked( $disabled || in_array( $post_type, $this->options['post_types'], true ), true, false ), + disabled( $disabled, true, false ), + esc_html( + sprintf( + /* translators: 1 is a post type or taxonomy label, 2 is a post type or taxonomy key. */ + _x( '%1$s (%2$s)', 'content type setting choice', 'polylang' ), + $pt->labels->name, + $pt->name + ) + ) + ); + } + } + ?> +
    +

    + taxonomies ) ) { + ?> +

    +
      + taxonomies as $taxonomy ) { + $tax = get_taxonomy( $taxonomy ); + if ( ! empty( $tax ) ) { + $disabled = in_array( $taxonomy, $this->disabled_taxonomies ); + printf( + '
    • ', + esc_attr( $taxonomy ), + checked( $disabled || in_array( $taxonomy, $this->options['taxonomies'], true ), true, false ), + disabled( $disabled, true, false ), + esc_html( + sprintf( + /* translators: 1 is a post type or taxonomy label, 2 is a post type or taxonomy key. */ + _x( '%1$s (%2$s)', 'content type setting choice', 'polylang' ), + $tax->labels->name, + $tax->name + ) + ) + ); + } + } + ?> +
    +

    + 'licenses', + 'title' => __( 'License keys', 'polylang' ), + 'description' => __( 'Manage licenses for Polylang Pro and add-ons.', 'polylang' ), + ) + ); + + $this->buttons['cancel'] = sprintf( '', __( 'Close', 'polylang' ) ); + + $this->items = apply_filters( 'pll_settings_licenses', array() ); + + add_action( 'wp_ajax_pll_deactivate_license', array( $this, 'deactivate_license' ) ); + } + + /** + * Tells if the module is active + * + * @since 1.9 + * + * @return bool + */ + public function is_active() { + return ! empty( $this->items ); + } + + /** + * Displays the settings form + * + * @since 1.9 + */ + protected function form() { + if ( ! empty( $this->items ) ) { ?> + + items as $item ) { + echo $this->get_row( $item ); // phpcs:ignore WordPress.Security.EscapeOutput + } + ?> +
    + get_form_field(); + } + + /** + * Ajax method to save the license keys and activate the licenses at the same time + * Overrides parent's method + * + * @since 1.9 + */ + public function save_options() { + check_ajax_referer( 'pll_options', '_pll_nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + if ( isset( $_POST['module'] ) && $this->module === $_POST['module'] && ! empty( $_POST['licenses'] ) ) { + $x = new WP_Ajax_Response(); + foreach ( $this->items as $item ) { + if ( ! empty( $_POST['licenses'][ $item->id ] ) ) { + $updated_item = $item->activate_license( sanitize_key( $_POST['licenses'][ $item->id ] ) ); + $x->Add( array( 'what' => 'license-update', 'data' => $item->id, 'supplemental' => array( 'html' => $this->get_row( $updated_item ) ) ) ); + } + } + + // Updated message + pll_add_notice( new WP_Error( 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' ) ); + ob_start(); + settings_errors( 'polylang' ); + $x->Add( array( 'what' => 'success', 'data' => ob_get_clean() ) ); + $x->send(); + } + } + + /** + * Ajax method to deactivate a license + * + * @since 1.9 + * + * @return void + */ + public function deactivate_license() { + check_ajax_referer( 'pll_options', '_pll_nonce' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + if ( ! isset( $_POST['id'] ) ) { + wp_die( 0 ); + } + + $id = substr( sanitize_text_field( wp_unslash( $_POST['id'] ) ), 11 ); + wp_send_json( + array( + 'id' => $id, + 'html' => $this->get_row( $this->items[ $id ]->deactivate_license() ), + ) + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-media.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-media.php new file mode 100644 index 000000000..1f7ea6159 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-media.php @@ -0,0 +1,37 @@ + 'media', + 'title' => __( 'Media', 'polylang' ), + 'description' => __( 'Activate languages and translations for media only if you need to translate the text attached to the media: the title, the alternative text, the caption, the description... Note that the file is not duplicated.', 'polylang' ), + 'active_option' => 'media_support', + ) + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-module.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-module.php new file mode 100644 index 000000000..1201559b5 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-module.php @@ -0,0 +1,379 @@ +options = &$polylang->options; + $this->model = &$polylang->model; + $this->links_model = &$polylang->links_model; + + $args = wp_parse_args( + $args, + array( + 'title' => '', + 'description' => '', + 'active_option' => 'none', + ) + ); + + if ( empty( $args['active_option'] ) ) { + // Backward compatibility. + $args['active_option'] = 'none'; + } + + foreach ( $args as $prop => $value ) { + $this->$prop = $value; + } + + // All possible action links, even if not always a link ;-) + $this->action_links = array( + 'configure' => sprintf( + '%s', + esc_attr__( 'Configure this module', 'polylang' ), + '#', + esc_html__( 'Settings', 'polylang' ) + ), + 'deactivate' => sprintf( + '%s', + esc_attr__( 'Deactivate this module', 'polylang' ), + esc_url( wp_nonce_url( '?page=mlang&tab=modules&pll_action=deactivate&noheader=true&module=' . $this->module, 'pll_deactivate' ) ), + esc_html__( 'Deactivate', 'polylang' ) + ), + 'activate' => sprintf( + '%s', + esc_attr__( 'Activate this module', 'polylang' ), + esc_url( wp_nonce_url( '?page=mlang&tab=modules&pll_action=activate&noheader=true&module=' . $this->module, 'pll_activate' ) ), + esc_html__( 'Activate', 'polylang' ) + ), + 'activated' => esc_html__( 'Activated', 'polylang' ), + 'deactivated' => esc_html__( 'Deactivated', 'polylang' ), + ); + + $this->buttons = array( + 'cancel' => sprintf( '', esc_html__( 'Cancel', 'polylang' ) ), + 'save' => sprintf( '', esc_html__( 'Save Changes', 'polylang' ) ), + ); + + // Ajax action to save options. + add_action( 'wp_ajax_pll_save_options', array( $this, 'save_options' ) ); + } + + /** + * Tells if the module is active. + * + * @since 1.8 + * + * @return bool + */ + public function is_active() { + return 'none' === $this->active_option || ( 'preview' !== $this->active_option && ! empty( $this->options[ $this->active_option ] ) ); + } + + /** + * Activates the module. + * + * @since 1.8 + * + * @return void + */ + public function activate() { + if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) { + $this->options[ $this->active_option ] = true; + update_option( 'polylang', $this->options ); + } + } + + /** + * Deactivates the module. + * + * @since 1.8 + * + * @return void + */ + public function deactivate() { + if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) { + $this->options[ $this->active_option ] = false; + update_option( 'polylang', $this->options ); + } + } + + /** + * Protected method to display a configuration form. + * + * @since 1.8 + * + * @return void + */ + protected function form() { + // Child classes can provide a form. + } + + /** + * Public method returning the form if any. + * + * @since 1.8 + * + * @return string + */ + public function get_form() { + if ( ! $this->is_active() ) { + return ''; + } + + // Read the form only once + if ( false === $this->form ) { + ob_start(); + $this->form(); + $this->form = ob_get_clean(); + } + + return $this->form; + } + + /** + * Allows child classes to validate their options before saving. + * + * @since 1.8 + * + * @param array $options Unsanitized options to save. + * @return array Options + */ + protected function update( $options ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + return array(); // It's responsibility of the child class to decide what is saved. + } + + /** + * Ajax method to save the options. + * + * @since 1.8 + * + * @return void + */ + public function save_options() { + check_ajax_referer( 'pll_options', '_pll_nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + + if ( isset( $_POST['module'] ) && $this->module === $_POST['module'] ) { + // It's up to the child class to decide which options are saved, whether there are errors or not + $post = array_diff_key( $_POST, array_flip( array( 'action', 'module', 'pll_ajax_backend', '_pll_nonce' ) ) ); + $options = $this->update( $post ); + $this->options = array_merge( $this->options, $options ); + update_option( 'polylang', $this->options ); + + // Refresh language cache in case home urls have been modified + $this->model->clean_languages_cache(); + + // Refresh rewrite rules in case rewrite, hide_default, post types or taxonomies options have been modified + // Don't use flush_rewrite_rules as we don't have the right links model and permastruct + delete_option( 'rewrite_rules' ); + + + ob_start(); + + if ( empty( get_settings_errors( 'polylang' ) ) ) { + // Send update message + pll_add_notice( new WP_Error( 'settings_updated', __( 'Settings saved.', 'polylang' ), 'success' ) ); + settings_errors( 'polylang' ); + $x = new WP_Ajax_Response( array( 'what' => 'success', 'data' => ob_get_clean() ) ); + $x->send(); + } else { + // Send error messages + settings_errors( 'polylang' ); + $x = new WP_Ajax_Response( array( 'what' => 'error', 'data' => ob_get_clean() ) ); + $x->send(); + } + } + } + + /** + * Get the row actions. + * + * @since 1.8 + * + * @return string[] + */ + protected function get_actions() { + $actions = array(); + + if ( $this->is_active() && $this->get_form() ) { + $actions[] = 'configure'; + } + + if ( 'none' !== $this->active_option && 'preview' !== $this->active_option ) { + $actions[] = $this->is_active() ? 'deactivate' : 'activate'; + } + + if ( empty( $actions ) ) { + $actions[] = $this->is_active() ? 'activated' : 'deactivated'; + } + + return $actions; + } + + /** + * Get the actions links. + * + * @since 1.8 + * + * @return string[] Action links. + */ + public function get_action_links() { + return array_intersect_key( $this->action_links, array_flip( $this->get_actions() ) ); + } + + /** + * Default upgrade message (to Pro version). + * + * @since 1.9 + * + * @return string + */ + protected function default_upgrade_message() { + return sprintf( + '%s %s', + __( 'To enable this feature, you need Polylang Pro.', 'polylang' ), + 'https://polylang.pro', + __( 'Upgrade now.', 'polylang' ) + ); + } + + /** + * Allows child classes to display an upgrade message. + * + * @since 1.9 + * + * @return string + */ + public function get_upgrade_message() { + return 'preview' === $this->active_option ? $this->default_upgrade_message() : ''; + } + + /** + * Get the buttons. + * + * @since 1.9 + * + * @return string[] An array of html fragment for the buttons. + */ + public function get_buttons() { + return $this->buttons; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-url.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-url.php new file mode 100644 index 000000000..784f35eeb --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings-url.php @@ -0,0 +1,332 @@ + 'url', + 'title' => __( 'URL modifications', 'polylang' ), + 'description' => __( 'Decide how your URLs will look like.', 'polylang' ), + ) + ); + + $this->page_on_front = &$polylang->static_pages->page_on_front; + } + + /** + * Displays the fieldset to choose how the language is set + * + * @since 1.8 + * + * @return void + */ + protected function force_lang() { + ?> +

    + +

    + +

    ' . esc_html( home_url( $this->links_model->using_permalinks ? 'en/my-post/' : '?lang=en&p=1' ) ) . ''; ?>

    + +

    ' . esc_html( str_replace( array( '://', 'www.' ), array( '://en.', '' ), home_url( 'my-post/' ) ) ) . ''; ?>

    + + options['force_lang'] ? '' : 'style="display: none;"'; ?>> + model->get_languages_list() as $lg ) { + $url = isset( $this->options['domains'][ $lg->slug ] ) ? $this->options['domains'][ $lg->slug ] : ( $lg->is_default ? $this->links_model->home : '' ); + printf( + '' . + '', + esc_attr( $lg->slug ), + esc_attr( $lg->name ), + esc_url( $url ) + ); + } + ?> +
    + + + + +

    ' . esc_html( home_url( 'en/' ) ) . ''; ?>

    + +

    ' . esc_html( home_url( 'language/en/' ) ) . ''; ?>

    + + +

    + model->post->get_language( $this->page_on_front ); + /** @var PLL_Language $lang */ + $lang = $lang ? $lang : $this->model->get_default_language(); + printf( + /* translators: %1$s example url when the option is active. %2$s example url when the option is not active */ + esc_html__( 'Example: %1$s instead of %2$s', 'polylang' ), + '' . esc_html( $this->links_model->home_url( $lang ) ) . '', + '' . esc_html( _get_page_link( $this->page_on_front ) ) . '' + ); + ?> +

    + +
    +
    + force_lang(); ?> +
    +
    + +
    +
    $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>> + hide_default(); ?> +
    + links_model->using_permalinks ) { + ?> +
    $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>> + rewrite(); ?> +
    + page_on_front ) { + ?> +
    $this->options['force_lang'] ? '' : 'style="display: none;"'; ?>> + redirect_lang(); ?> +
    + +
    + $domain ) { + if ( empty( $domain ) ) { + $lang = $this->model->get_language( $key ); + pll_add_notice( + new WP_Error( + sprintf( 'pll_invalid_domain_%s', $key ), + sprintf( + /* translators: %s is a native language name */ + __( 'Please enter a valid URL for %s.', 'polylang' ), + $lang->name + ) + ) + ); + } + else { + $newoptions['domains'][ $key ] = esc_url_raw( trim( $domain ) ); + } + } + } + + foreach ( array( 'hide_default', 'redirect_lang' ) as $key ) { + $newoptions[ $key ] = isset( $options[ $key ] ) ? 1 : 0; + } + + if ( 3 == $options['force_lang'] ) { + if ( ! class_exists( 'PLL_Xdata_Domain', true ) ) { + $newoptions['browser'] = 0; + } + $newoptions['hide_default'] = 0; + } + + // Check if domains exist + if ( $newoptions['force_lang'] > 1 ) { + $this->check_domains( $newoptions ); + } + + return $newoptions; // Take care to return only validated options + } + + /** + * Check if subdomains or domains are accessible + * + * @since 1.8 + * + * @param array $options new set of options to test + * @return void + */ + protected function check_domains( $options ) { + $options = array_merge( $this->options, $options ); + $model = new PLL_Model( $options ); + $links_model = $model->get_links_model(); + foreach ( $this->model->get_languages_list() as $lang ) { + $url = add_query_arg( 'deactivate-polylang', 1, $links_model->home_url( $lang ) ); + // Don't redefine vip_safe_wp_remote_get() as it has not the same signature as wp_remote_get() + $response = function_exists( 'vip_safe_wp_remote_get' ) ? vip_safe_wp_remote_get( esc_url_raw( $url ) ) : wp_remote_get( esc_url_raw( $url ) ); + $response_code = wp_remote_retrieve_response_code( $response ); + + if ( 200 != $response_code ) { + pll_add_notice( + new WP_Error( + sprintf( 'pll_invalid_domain_%s', $lang->slug ), + sprintf( + /* translators: %s is an url */ + __( 'Polylang was unable to access the %s URL. Please check that the URL is valid.', 'polylang' ), + $url + ) + ) + ); + } + } + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings.php new file mode 100644 index 000000000..fbdb57e3f --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/settings.php @@ -0,0 +1,414 @@ +active_tab = 'mlang' === $_GET['page'] ? 'lang' : substr( sanitize_key( $_GET['page'] ), 6 ); // phpcs:ignore WordPress.Security.NonceVerification + } + + PLL_Admin_Strings::init(); + + add_action( 'admin_init', array( $this, 'register_settings_modules' ) ); + + // Adds screen options and the about box in the languages admin panel. + add_action( 'load-toplevel_page_mlang', array( $this, 'load_page' ) ); + add_action( 'load-languages_page_mlang_strings', array( $this, 'load_page_strings' ) ); + + // Saves the per-page value in screen options. + add_filter( 'set_screen_option_pll_lang_per_page', array( $this, 'set_screen_option' ), 10, 3 ); + add_filter( 'set_screen_option_pll_strings_per_page', array( $this, 'set_screen_option' ), 10, 3 ); + } + + /** + * Initializes the modules + * + * @since 1.8 + * + * @return void + */ + public function register_settings_modules() { + $modules = array(); + + if ( $this->model->has_languages() ) { + $modules = array( + 'PLL_Settings_Url', + 'PLL_Settings_Browser', + 'PLL_Settings_Media', + 'PLL_Settings_CPT', + ); + } + + $modules[] = 'PLL_Settings_Licenses'; + + /** + * Filter the list of setting modules + * + * @since 1.8 + * + * @param array $modules the list of module classes + */ + $modules = apply_filters( 'pll_settings_modules', $modules ); + + foreach ( $modules as $key => $class ) { + $key = is_numeric( $key ) ? strtolower( str_replace( 'PLL_Settings_', '', $class ) ) : $key; + $this->modules[ $key ] = new $class( $this ); + } + } + + /** + * Loads the about metabox + * + * @since 0.8 + * + * @return void + */ + public function metabox_about() { + include __DIR__ . '/view-about.php'; + } + + /** + * Adds screen options and the about box in the languages admin panel + * + * @since 0.9.5 + * + * @return void + */ + public function load_page() { + if ( ! defined( 'PLL_DISPLAY_ABOUT' ) || PLL_DISPLAY_ABOUT ) { + add_meta_box( + 'pll-about-box', + __( 'About Polylang', 'polylang' ), + array( $this, 'metabox_about' ), + 'toplevel_page_mlang', + 'normal' + ); + } + + add_screen_option( + 'per_page', + array( + 'label' => __( 'Languages', 'polylang' ), + 'default' => 10, + 'option' => 'pll_lang_per_page', + ) + ); + + add_action( 'admin_notices', array( $this, 'notice_objects_with_no_lang' ) ); + } + + /** + * Adds screen options in the strings translations admin panel + * + * @since 2.1 + * + * @return void + */ + public function load_page_strings() { + add_screen_option( + 'per_page', + array( + 'label' => __( 'Strings translations', 'polylang' ), + 'default' => 10, + 'option' => 'pll_strings_per_page', + ) + ); + } + + /** + * Saves the number of rows in the languages or strings table set by this user. + * + * @since 0.9.5 + * + * @param mixed $screen_option False or value returned by a previous filter, not used. + * @param string $option The name of the option, not used. + * @param int $value The new value of the option to save. + * @return int The new value of the option. + */ + public function set_screen_option( $screen_option, $option, $value ) { + return (int) $value; + } + + /** + * Manages the user input for the languages pages. + * + * @since 1.9 + * + * @param string $action The action name. + * @return void + */ + public function handle_actions( $action ) { + switch ( $action ) { + case 'add': + check_admin_referer( 'add-lang', '_wpnonce_add-lang' ); + $errors = $this->model->add_language( $_POST ); + + if ( is_wp_error( $errors ) ) { + pll_add_notice( $errors ); + } else { + pll_add_notice( new WP_Error( 'pll_languages_created', __( 'Language added.', 'polylang' ), 'success' ) ); + $locale = sanitize_locale_name( $_POST['locale'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated + + if ( 'en_US' !== $locale && current_user_can( 'install_languages' ) ) { + // Attempts to install the language pack + require_once ABSPATH . 'wp-admin/includes/translation-install.php'; + if ( ! wp_download_language_pack( $locale ) ) { + pll_add_notice( new WP_Error( 'pll_download_mo', __( 'The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang' ), 'warning' ) ); + } + + // Force checking for themes and plugins translations updates + wp_clean_themes_cache(); + wp_clean_plugins_cache(); + } + } + self::redirect(); // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + break; + + case 'delete': + check_admin_referer( 'delete-lang' ); + + if ( ! empty( $_GET['lang'] ) && $this->model->delete_language( (int) $_GET['lang'] ) ) { + pll_add_notice( new WP_Error( 'pll_languages_deleted', __( 'Language deleted.', 'polylang' ), 'success' ) ); + } + + self::redirect(); // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + break; + + case 'update': + check_admin_referer( 'add-lang', '_wpnonce_add-lang' ); + $errors = $this->model->update_language( $_POST ); + + if ( is_wp_error( $errors ) ) { + pll_add_notice( $errors ); + } else { + pll_add_notice( new WP_Error( 'pll_languages_updated', __( 'Language updated.', 'polylang' ), 'success' ) ); + } + + self::redirect(); // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + break; + + case 'default-lang': + check_admin_referer( 'default-lang' ); + + if ( $lang = $this->model->get_language( (int) $_GET['lang'] ) ) { + $this->model->update_default_lang( $lang->slug ); + } + + self::redirect(); // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + break; + + case 'content-default-lang': + check_admin_referer( 'content-default-lang' ); + + $this->model->set_language_in_mass(); + + self::redirect(); // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + break; + + case 'activate': + check_admin_referer( 'pll_activate' ); + if ( isset( $_GET['module'] ) ) { + $module = sanitize_key( $_GET['module'] ); + if ( isset( $this->modules[ $module ] ) ) { + $this->modules[ $module ]->activate(); + } + } + self::redirect(); + break; + + case 'deactivate': + check_admin_referer( 'pll_deactivate' ); + if ( isset( $_GET['module'] ) ) { + $module = sanitize_key( $_GET['module'] ); + if ( isset( $this->modules[ $module ] ) ) { + $this->modules[ $module ]->deactivate(); + } + } + self::redirect(); + break; + + default: + /** + * Fires when a non default action has been sent to Polylang settings + * + * @since 1.8 + */ + do_action( "mlang_action_$action" ); + break; + } + } + + /** + * Displays the 3 tabs pages: languages, strings translations, settings + * Also manages user input for these pages + * + * @since 0.1 + * + * @return void + */ + public function languages_page() { + switch ( $this->active_tab ) { + case 'lang': + // Prepare the list table of languages + $list_table = new PLL_Table_Languages(); + $list_table->prepare_items( $this->model->get_languages_list() ); + break; + + case 'strings': + $string_table = new PLL_Table_String( $this->model->get_languages_list() ); + $string_table->prepare_items(); + break; + } + + // Handle user input + $action = isset( $_REQUEST['pll_action'] ) ? sanitize_key( $_REQUEST['pll_action'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification + if ( 'edit' === $action && ! empty( $_GET['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + // phpcs:ignore WordPress.Security.NonceVerification, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $edit_lang = $this->model->get_language( (int) $_GET['lang'] ); + } else { + $this->handle_actions( $action ); + } + + // Displays the page + include __DIR__ . '/view-languages.php'; + } + + /** + * Enqueues scripts and styles + * + * @return void + */ + public function admin_enqueue_scripts() { + parent::admin_enqueue_scripts(); + + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + 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 ); + wp_localize_script( 'pll_admin', 'pll_admin', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) ); + + wp_enqueue_style( 'pll_selectmenu', plugins_url( '/css/build/selectmenu' . $suffix . '.css', POLYLANG_ROOT_FILE ), array(), POLYLANG_VERSION ); + } + + /** + * Displays a notice when there are objects with no language assigned + * + * @since 1.8 + * + * @return void + */ + public function notice_objects_with_no_lang() { + if ( ! empty( $this->options['default_lang'] ) && $this->model->get_objects_with_no_lang( 1 ) ) { + printf( + '

    %s %s

    ', + esc_html__( 'There are posts, pages, categories or tags without language.', 'polylang' ), + esc_url( wp_nonce_url( '?page=mlang&pll_action=content-default-lang&noheader=true', 'content-default-lang' ) ), + esc_html__( 'You can set them all to the default language.', 'polylang' ) + ); + } + } + + /** + * Redirects to language page ( current active tab ) + * saves error messages in a transient for reuse in redirected page + * + * @since 1.5 + * + * @param array $args query arguments to add to the url + * @return void + */ + public static function redirect( $args = array() ) { + $errors = get_settings_errors( 'polylang' ); + if ( ! empty( $errors ) ) { + set_transient( 'settings_errors', $errors, 30 ); + $args['settings-updated'] = 1; + } + // Remove possible 'pll_action' and 'lang' query args from the referer before redirecting + wp_safe_redirect( add_query_arg( $args, remove_query_arg( array( 'pll_action', 'lang' ), wp_get_referer() ) ) ); + exit; + } + + /** + * Get the list of predefined languages + * + * @since 2.3 + * + * @return string[] { + * @type string $code ISO 639-1 language code. + * @type string $locale WordPress locale. + * @type string $name Native language name. + * @type string $dir Text direction: 'ltr' or 'rtl'. + * @type string $flag Flag code, generally the country code. + * @type string $w3c W3C locale. + * @type string $facebook Facebook locale. + * } + */ + public static function get_predefined_languages() { + require_once ABSPATH . 'wp-admin/includes/translation-install.php'; + + $languages = include __DIR__ . '/languages.php'; + $translations = wp_get_available_translations(); + + // Keep only languages with existing WP language pack + // Unless the transient has expired and we don't have an internet connection to refresh it + if ( ! empty( $translations ) ) { + $translations['en_US'] = ''; // Languages packs don't include en_US + $languages = array_intersect_key( $languages, $translations ); + } + + /** + * Filter the list of predefined languages + * + * @since 1.7.10 + * @since 2.3 The languages arrays use associative keys instead of numerical keys + * @see https://github.com/polylang/polylang/blob/2.8.2/settings/languages.php the list of predefined languages + * + * @param array $languages + */ + $languages = apply_filters( 'pll_predefined_languages', $languages ); + + // Keep only languages with all necessary information + foreach ( $languages as $k => $lang ) { + if ( ! isset( $lang['code'], $lang['locale'], $lang['name'], $lang['dir'], $lang['flag'] ) ) { + unset( $languages[ $k ] ); + } + } + + return $languages; + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-languages.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-languages.php new file mode 100644 index 000000000..c27b5b993 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-languages.php @@ -0,0 +1,277 @@ + 'Languages', // Do not translate ( used for css class ) + 'ajax' => false, + ) + ); + } + + /** + * Generates content for a single row of the table. + * + * @since 1.8 + * + * @param PLL_Language $item The language item. + * @return void + */ + public function single_row( $item ) { + /** + * Filter the list of classes assigned a row in the languages list table + * + * @since 1.8 + * + * @param array $classes The list of class names. + * @param PLL_Language $item The language item. + */ + $classes = apply_filters( 'pll_languages_row_classes', array(), $item ); + echo '' : ' class="' . esc_attr( implode( ' ', $classes ) ) . '">' ); + $this->single_row_columns( $item ); + echo ''; + } + + /** + * Displays the item information in a column ( default case ). + * + * @since 0.1 + * + * @param PLL_Language $item The language item. + * @param string $column_name The column name. + * @return string|int + */ + public function column_default( $item, $column_name ) { + switch ( $column_name ) { + case 'locale': + case 'slug': + return esc_html( $item->$column_name ); + + case 'term_group': + return (int) $item->$column_name; + + case 'count': + return $item->get_tax_prop( 'language', $column_name ); + + default: + return $item->$column_name; // Flag. + } + } + + /** + * Displays the item information in the column 'name' + * Displays the edit and delete action links + * + * @since 0.1 + * + * @param PLL_Language $item The language item. + * @return string + */ + public function column_name( $item ) { + return sprintf( + '%s', + esc_attr__( 'Edit this language', 'polylang' ), + esc_url( admin_url( 'admin.php?page=mlang&pll_action=edit&lang=' . $item->term_id ) ), + esc_html( $item->name ) + ); + } + + /** + * Displays the item information in the default language + * Displays the 'make default' action link + * + * @since 1.8 + * + * @param PLL_Language $item The language item. + * @return string + */ + public function column_default_lang( $item ) { + if ( ! $item->is_default ) { + $s = sprintf( + '
    + %3$s +
    ', + esc_attr__( 'Select as default language', 'polylang' ), + wp_nonce_url( '?page=mlang&pll_action=default-lang&noheader=true&lang=' . $item->term_id, 'default-lang' ), + /* translators: accessibility text, %s is a native language name */ + esc_html( sprintf( __( 'Choose %s as default language', 'polylang' ), $item->name ) ) + ); + + /** + * Filters the default language row action in the languages list table. + * + * @since 1.8 + * + * @param string $s The html markup of the action. + * @param PLL_Language $item The language item. + */ + $s = apply_filters( 'pll_default_lang_row_action', $s, $item ); + } else { + $s = sprintf( + '%1$s', + /* translators: accessibility text */ + esc_html__( 'Default language', 'polylang' ) + ); + } + + return $s; + } + + /** + * Gets the list of columns + * + * @since 0.1 + * + * @return string[] The list of column titles. + */ + public function get_columns() { + return array( + 'name' => esc_html__( 'Full name', 'polylang' ), + 'locale' => esc_html__( 'Locale', 'polylang' ), + 'slug' => esc_html__( 'Code', 'polylang' ), + 'default_lang' => sprintf( '%2$s', esc_attr__( 'Default language', 'polylang' ), esc_html__( 'Default language', 'polylang' ) ), + 'term_group' => esc_html__( 'Order', 'polylang' ), + 'flag' => esc_html__( 'Flag', 'polylang' ), + 'count' => esc_html__( 'Posts', 'polylang' ), + ); + } + + /** + * Gets the list of sortable columns + * + * @since 0.1 + * + * @return array + */ + public function get_sortable_columns() { + return array( + 'name' => array( 'name', true ), // sorted by name by default + 'locale' => array( 'locale', false ), + 'slug' => array( 'slug', false ), + 'term_group' => array( 'term_group', false ), + 'count' => array( 'count', false ), + ); + } + + /** + * Gets the name of the default primary column. + * + * @since 2.1 + * + * @return string Name of the default primary column, in this case, 'name'. + */ + protected function get_default_primary_column_name() { + return 'name'; + } + + /** + * Generates and display row actions links for the list table. + * + * @since 1.8 + * + * @param PLL_Language $item The language item being acted upon. + * @param string $column_name Current column name. + * @param string $primary Primary column name. + * @return string The row actions output. + */ + protected function handle_row_actions( $item, $column_name, $primary ) { + if ( $primary !== $column_name ) { + return ''; + } + + $actions = array( + 'edit' => sprintf( + '%s', + esc_attr__( 'Edit this language', 'polylang' ), + esc_url( admin_url( 'admin.php?page=mlang&pll_action=edit&lang=' . $item->term_id ) ), + esc_html__( 'Edit', 'polylang' ) + ), + 'delete' => sprintf( + '%s', + esc_attr__( 'Delete this language and all its associated data', 'polylang' ), + wp_nonce_url( '?page=mlang&pll_action=delete&noheader=true&lang=' . $item->term_id, 'delete-lang' ), + esc_js( __( 'You are about to permanently delete this language. Are you sure?', 'polylang' ) ), + esc_html__( 'Delete', 'polylang' ) + ), + ); + + /** + * Filters the list of row actions in the languages list table. + * + * @since 1.8 + * + * @param array $actions A list of html markup actions. + * @param PLL_Language $item The language item. + */ + $actions = apply_filters( 'pll_languages_row_actions', $actions, $item ); + + return $this->row_actions( $actions ); + } + + /** + * Sorts language items. + * + * @since 0.1 + * + * @param PLL_Language $a The first language to compare. + * @param PLL_Language $b The second language to compare. + * @return int -1 or 1 if $a is considered to be respectively less than or greater than $b. + */ + protected function usort_reorder( $a, $b ) { + $orderby = ! empty( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'name'; // phpcs:ignore WordPress.Security.NonceVerification + // Determine sort order + if ( is_numeric( $a->$orderby ) ) { + $result = $a->$orderby > $b->$orderby ? 1 : -1; + } else { + $result = strcmp( $a->$orderby, $b->$orderby ); + } + // Send final sort direction to usort. + return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // phpcs:ignore WordPress.Security.NonceVerification + } + + /** + * Prepares the list of languages for display. + * + * @since 0.1 + * + * @param PLL_Language[] $data The list of languages. + * @return void + */ + public function prepare_items( $data = array() ) { + $per_page = $this->get_items_per_page( 'pll_lang_per_page' ); + $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() ); + + usort( $data, array( $this, 'usort_reorder' ) ); + + $total_items = count( $data ); + $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page ); + + $this->set_pagination_args( + array( + 'total_items' => $total_items, + 'per_page' => $per_page, + 'total_pages' => (int) ceil( $total_items / $per_page ), + ) + ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-settings.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-settings.php new file mode 100644 index 000000000..e11a89e6b --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-settings.php @@ -0,0 +1,194 @@ + 'Settings', // Do not translate ( used for css class ) + 'ajax' => false, + ) + ); + } + + /** + * Get the table classes for styling + * + * @since 1.8 + */ + protected function get_table_classes() { + return array( 'wp-list-table', 'widefat', 'plugins', 'pll-settings' ); // get the style of the plugins list table + one specific class + } + + /** + * Displays a single row. + * + * @since 1.8 + * + * @param PLL_Settings_Module $item Settings module item. + * @return void + */ + public function single_row( $item ) { + // Classes to reuse css from the plugins list table + $classes = $item->is_active() ? 'active' : 'inactive'; + if ( $message = $item->get_upgrade_message() ) { + $classes .= ' update'; + } + + // Display the columns + printf( '', esc_attr( $item->module ), esc_attr( $classes ) ); + $this->single_row_columns( $item ); + echo ''; + + // Display an upgrade message if there is any, reusing css from the plugins updates + if ( $message = $item->get_upgrade_message() ) { + printf( + ' + %s + ', + sprintf( '

    %s

    ', $message ) // phpcs:ignore WordPress.Security.EscapeOutput + ); + } + + // The settings if there are + // "inactive" class to reuse css from the plugins list table + if ( $form = $item->get_form() ) { + printf( + ' + + %s + %s +

    + %s +

    + + ', + esc_attr( $item->module ), + esc_html( $item->title ), + $form, // phpcs:ignore + implode( $item->get_buttons() ) // phpcs:ignore + ); + } + } + + /** + * Generates the columns for a single row of the table. + * + * @since 1.8 + * + * @param PLL_Settings_Module $item Settings module item. + * @return void + */ + protected function single_row_columns( $item ) { + $column_info = $this->get_column_info(); + $columns = $column_info[0]; + $primary = $column_info[3]; + + foreach ( array_keys( $columns ) as $column_name ) { + $classes = "$column_name column-$column_name"; + if ( $primary === $column_name ) { + $classes .= ' column-primary'; + } + + if ( 'cb' == $column_name ) { + echo ''; + echo $this->column_cb( $item ); // phpcs:ignore WordPress.Security.EscapeOutput + echo ''; + } else { + printf( '', esc_attr( $classes ) ); + echo $this->column_default( $item, $column_name ); // phpcs:ignore WordPress.Security.EscapeOutput + echo ''; + } + } + } + + /** + * Displays the item information in a column (default case). + * + * @since 1.8 + * + * @param PLL_Settings_Module $item Settings module item. + * @param string $column_name Column name. + * @return string The column name. + */ + protected function column_default( $item, $column_name ) { + if ( 'plugin-title' == $column_name ) { + return sprintf( '%s', esc_html( $item->title ) ) . $this->row_actions( $item->get_action_links(), true /*always visible*/ ); + } + return $item->$column_name; + } + + /** + * Gets the list of columns. + * + * @since 1.8 + * + * @return string[] The list of column titles. + */ + public function get_columns() { + return array( + 'cb' => '', // For the 4px border inherited from plugins when the module is activated + 'plugin-title' => esc_html__( 'Module', 'polylang' ), // plugin-title for styling + 'description' => esc_html__( 'Description', 'polylang' ), + ); + } + + /** + * Gets the name of the primary column. + * + * @since 1.8 + * + * @return string The name of the primary column. + */ + protected function get_primary_column_name() { + return 'plugin-title'; + } + + /** + * Prepares the list of items for displaying + * + * @since 1.8 + * + * @param PLL_Settings_Module[] $items Array of settings module items. + * @return void + */ + public function prepare_items( $items = array() ) { + $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns(), $this->get_primary_column_name() ); + + // Sort rows, lowest priority on top. + usort( + $items, + function ( $a, $b ) { + return $a->priority > $b->priority ? 1 : -1; + } + ); + $this->items = $items; + } + + /** + * Avoids displaying an empty tablenav + * + * @since 2.1 + * + * @param string $which 'top' or 'bottom' + * @return void + */ + protected function display_tablenav( $which ) {} // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-string.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-string.php new file mode 100644 index 000000000..64ef0c1a0 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/table-string.php @@ -0,0 +1,449 @@ + 'Strings translations', // Do not translate ( used for css class ) + 'ajax' => false, + ) + ); + + $this->languages = $languages; + $this->strings = PLL_Admin_Strings::get_strings(); + $this->groups = array_unique( wp_list_pluck( $this->strings, 'context' ) ); + + $this->selected_group = -1; + + if ( ! empty( $_GET['group'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + $group = sanitize_text_field( wp_unslash( $_GET['group'] ) ); // phpcs:ignore WordPress.Security.NonceVerification + if ( in_array( $group, $this->groups ) ) { + $this->selected_group = $group; + } + } + + add_action( 'mlang_action_string-translation', array( $this, 'save_translations' ) ); + } + + /** + * Displays the item information in a column (default case). + * + * @since 0.6 + * + * @param array $item Data related to the current string. + * @param string $column_name The current column name. + * @return string + */ + public function column_default( $item, $column_name ) { + return $item[ $column_name ]; + } + + /** + * Displays the checkbox in first column. + * + * @since 1.1 + * + * @param array $item Data related to the current string. + * @return string + */ + public function column_cb( $item ) { + return sprintf( + '', + esc_attr( $item['row'] ), + /* translators: accessibility text, %s is a string potentially in any language */ + sprintf( __( 'Select %s', 'polylang' ), format_to_edit( $item['string'] ) ), + empty( $item['icl'] ) ? 'disabled' : '' // Only strings registered with WPML API can be removed. + ); + } + + /** + * Displays the string to translate. + * + * @since 1.0 + * + * @param array $item Data related to the current string. + * @return string + */ + public function column_string( $item ) { + return format_to_edit( $item['string'] ); // Don't interpret special chars for the string column. + } + + /** + * Displays the translations to edit. + * + * @since 0.6 + * + * @param array $item Data related to the current string. + * @return string + */ + public function column_translations( $item ) { + $out = ''; + $languages = array(); + + foreach ( $this->languages as $language ) { + $languages[ $language->slug ] = $language->name; + } + + foreach ( $item['translations'] as $key => $translation ) { + $input_type = $item['multiline'] ? + '' : + ''; + $out .= sprintf( + '
    ' . $input_type . '
    ' . "\n", + esc_attr( $key ), + esc_attr( $item['row'] ), + esc_html( $languages[ $key ] ), + format_to_edit( $translation ) // Don't interpret special chars. + ); + } + + return $out; + } + + /** + * Gets the list of columns. + * + * @since 0.6 + * + * @return string[] The list of column titles. + */ + public function get_columns() { + return array( + 'cb' => '', // Checkbox. + 'string' => esc_html__( 'String', 'polylang' ), + 'name' => esc_html__( 'Name', 'polylang' ), + 'context' => esc_html__( 'Group', 'polylang' ), + 'translations' => esc_html__( 'Translations', 'polylang' ), + ); + } + + /** + * Gets the list of sortable columns + * + * @since 0.6 + * + * @return array + */ + public function get_sortable_columns() { + return array( + 'string' => array( 'string', false ), + 'name' => array( 'name', false ), + 'context' => array( 'context', false ), + ); + } + + /** + * Gets the name of the default primary column. + * + * @since 2.1 + * + * @return string Name of the default primary column, in this case, 'string'. + */ + protected function get_default_primary_column_name() { + return 'string'; + } + + /** + * Search for a string in translations. Case insensitive. + * + * @since 2.6 + * + * @param PLL_MO[] $mos An array of PLL_MO objects. + * @param string $s Searched string. + * @return string[] Found strings. + */ + protected function search_in_translations( $mos, $s ) { + $founds = array(); + + foreach ( $mos as $mo ) { + foreach ( wp_list_pluck( $mo->entries, 'translations' ) as $string => $translation ) { + if ( false !== stripos( $translation[0], $s ) ) { + $founds[] = $string; + } + } + } + + return array_unique( $founds ); + } + + /** + * Sorts registered string items. + * + * @since 0.6 + * + * @param array $a The first item to compare. + * @param array $b The second item to compare. + * @return int -1 or 1 if $a is considered to be respectively less than or greater than $b. + */ + protected function usort_reorder( $a, $b ) { + if ( ! empty( $_GET['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification + $orderby = sanitize_key( $_GET['orderby'] ); // phpcs:ignore WordPress.Security.NonceVerification + if ( isset( $a[ $orderby ], $b[ $orderby ] ) ) { + $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // Determine sort order + return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // phpcs:ignore WordPress.Security.NonceVerification + } + } + + return 0; + } + + /** + * Prepares the list of registered strings for display. + * + * @since 0.6 + * + * @return void + */ + public function prepare_items() { + // Is admin language filter active? + if ( $lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true ) ) { + $languages = wp_list_filter( $this->languages, array( 'slug' => $lg ) ); + } else { + $languages = $this->languages; + } + + // Load translations + $mo = array(); + foreach ( $languages as $language ) { + $mo[ $language->slug ] = new PLL_MO(); + $mo[ $language->slug ]->import_from_db( $language ); + } + + $data = $this->strings; + + // Filter by selected group + if ( -1 !== $this->selected_group ) { + $data = wp_list_filter( $data, array( 'context' => $this->selected_group ) ); + } + + // Filter by searched string + $s = empty( $_GET['s'] ) ? '' : wp_unslash( $_GET['s'] ); // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput + + if ( ! empty( $s ) ) { + // Search in translations + $in_translations = $this->search_in_translations( $mo, $s ); + + foreach ( $data as $key => $row ) { + if ( stripos( $row['name'], $s ) === false && stripos( $row['string'], $s ) === false && ! in_array( $row['string'], $in_translations ) ) { + unset( $data[ $key ] ); + } + } + } + + // Sorting + uasort( $data, array( $this, 'usort_reorder' ) ); + + // Paging + $per_page = $this->get_items_per_page( 'pll_strings_per_page' ); + $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() ); + + $total_items = count( $data ); + $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page, true ); + + $this->set_pagination_args( + array( + 'total_items' => $total_items, + 'per_page' => $per_page, + 'total_pages' => (int) ceil( $total_items / $per_page ), + ) + ); + + // Translate strings + // Kept for the end as it is a slow process + foreach ( $languages as $language ) { + foreach ( $this->items as $key => $row ) { + $this->items[ $key ]['translations'][ $language->slug ] = $mo[ $language->slug ]->translate( $row['string'] ); + $this->items[ $key ]['row'] = $key; // Store the row number for convenience + } + } + } + + /** + * Get the list of possible bulk actions. + * + * @since 1.1 + * + * @return string[] Array of bulk actions. + */ + public function get_bulk_actions() { + return array( 'delete' => __( 'Delete', 'polylang' ) ); + } + + /** + * Get the current action selected from the bulk actions dropdown. + * overrides parent function to avoid submit button to trigger bulk actions + * + * @since 1.8 + * + * @return string|false The action name or False if no action was selected + */ + public function current_action() { + return empty( $_POST['submit'] ) ? parent::current_action() : false; // phpcs:ignore WordPress.Security.NonceVerification + } + + /** + * Displays the dropdown list to filter strings per group + * + * @since 1.1 + * + * @param string $which only 'top' is supported + * @return void + */ + public function extra_tablenav( $which ) { + if ( 'top' !== $which ) { + return; + } + + echo '
    '; + printf( + '', + /* translators: accessibility text */ + esc_html__( 'Filter by group', 'polylang' ) + ); + echo '' . "\n"; + + submit_button( __( 'Filter', 'polylang' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); + echo '
    '; + } + + /** + * Saves the strings translations in DB + * Optionally clean the DB + * + * @since 1.9 + * + * @return void + */ + public function save_translations() { + check_admin_referer( 'string-translation', '_wpnonce_string-translation' ); + + if ( ! empty( $_POST['submit'] ) ) { + foreach ( $this->languages as $language ) { + if ( empty( $_POST['translation'][ $language->slug ] ) || ! is_array( $_POST['translation'][ $language->slug ] ) ) { // In case the language filter is active ( thanks to John P. Bloch ) + continue; + } + + $translations = array_map( 'trim', (array) wp_unslash( $_POST['translation'][ $language->slug ] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + $mo = new PLL_MO(); + $mo->import_from_db( $language ); + + foreach ( $translations as $key => $translation ) { + /** + * Filter the string translation before it is saved in DB + * Allows to sanitize strings registered with pll_register_string + * + * @since 1.6 + * @since 2.7 The translation passed to the filter is unslashed. + * + * @param string $translation The string translation. + * @param string $name The name as defined in pll_register_string. + * @param string $context The context as defined in pll_register_string. + */ + $translation = apply_filters( 'pll_sanitize_string_translation', $translation, $this->strings[ $key ]['name'], $this->strings[ $key ]['context'] ); + $mo->add_entry( $mo->make_entry( $this->strings[ $key ]['string'], $translation ) ); + } + + // Clean database ( removes all strings which were registered some day but are no more ) + if ( ! empty( $_POST['clean'] ) ) { + $new_mo = new PLL_MO(); + + foreach ( $this->strings as $string ) { + $new_mo->add_entry( $mo->make_entry( $string['string'], $mo->translate( $string['string'] ) ) ); + } + } + + isset( $new_mo ) ? $new_mo->export_to_db( $language ) : $mo->export_to_db( $language ); + } + + pll_add_notice( new WP_Error( 'pll_strings_translations_updated', __( 'Translations updated.', 'polylang' ), 'success' ) ); + + /** + * Fires after the strings translations are saved in DB + * + * @since 1.2 + */ + do_action( 'pll_save_strings_translations' ); + } + + // Unregisters strings registered through WPML API + if ( $this->current_action() === 'delete' && ! empty( $_POST['strings'] ) && function_exists( 'icl_unregister_string' ) ) { + foreach ( array_map( 'sanitize_key', $_POST['strings'] ) as $key ) { + icl_unregister_string( $this->strings[ $key ]['context'], $this->strings[ $key ]['name'] ); + } + } + + // To refresh the page ( possible thanks to the $_GET['noheader']=true ) + $args = array_intersect_key( $_REQUEST, array_flip( array( 's', 'paged', 'group' ) ) ); + if ( ! empty( $_GET['paged'] ) && ! empty( $_POST['submit'] ) ) { + $args['paged'] = (int) $_GET['paged']; // Don't rely on $_REQUEST['paged'] or $_POST['paged']. See #14 + } + if ( ! empty( $args['s'] ) ) { + $args['s'] = urlencode( $args['s'] ); // Searched string needs to be encoded as it comes from $_POST + } + PLL_Settings::redirect( $args ); + } +} diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-about.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-about.php new file mode 100644 index 000000000..9bad4e9b8 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-about.php @@ -0,0 +1,30 @@ + +

    + ', + '' + ); + if ( ! defined( 'POLYLANG_PRO' ) ) { + echo ' '; + printf( + /* translators: %1$s is link start tag, %2$s is link end tag. */ + esc_html__( 'Support and extra features are available to %1$sPolylang Pro%2$s users.', 'polylang' ), + '', + '' + ); + } + ?> +

    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-languages.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-languages.php new file mode 100644 index 000000000..d7e5e52aa --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-languages.php @@ -0,0 +1,35 @@ + +
    +

    + active_tab ) { + case 'lang': // Languages tab + case 'strings': // String translations tab + case 'settings': // Settings tab + include __DIR__ . '/view-tab-' . $this->active_tab . '.php'; + // Intentional fall-through to upgrade to fire the action below. + + default: + /** + * Fires when loading the active Polylang settings tab + * Allows plugins to add their own tab + * + * @since 1.5.1 + */ + do_action( 'pll_settings_active_tab_' . $this->active_tab ); + break; + } + ?> +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-lang.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-lang.php new file mode 100644 index 000000000..c2fa7ecb4 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-lang.php @@ -0,0 +1,178 @@ + +
    +
    +
    + display(); + ?> +
    + +
    +
    +
    + +
    +
    + +
    +

    + +
    + + + + + + +
    + + +

    +
    + +
    + + ', + ! empty( $edit_lang ) ? esc_attr( $edit_lang->name ) : '' + ); + ?> +

    +
    + +
    + + ', + ! empty( $edit_lang ) ? esc_attr( $edit_lang->locale ) : '' + ); + ?> +

    +
    + +
    + + ', + ! empty( $edit_lang ) ? esc_attr( $edit_lang->slug ) : '' + ); + ?> +

    +
    + +
    + + %s', + checked( ! empty( $edit_lang ) && $edit_lang->is_rtl, false, false ), + esc_html__( 'left to right', 'polylang' ) + ); + printf( + '', + checked( ! empty( $edit_lang ) && $edit_lang->is_rtl, true, false ), + esc_html__( 'right to left', 'polylang' ) + ); + ?> +

    +
    + +
    + + +

    +
    + +
    + + ', + ! empty( $edit_lang ) ? esc_attr( $edit_lang->term_group ) : '' + ); + ?> +

    +
    + +
    +
    +
    +
    +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-settings.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-settings.php new file mode 100644 index 000000000..77571dd44 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-settings.php @@ -0,0 +1,19 @@ + +
    + prepare_items( $this->modules ); + $list_table->display(); + ?> +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-strings.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-strings.php new file mode 100644 index 000000000..f303c8f4a --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/settings/view-tab-strings.php @@ -0,0 +1,33 @@ + +
    +
    + + search_box( __( 'Search translations', 'polylang' ), 'translations' ); + wp_nonce_field( 'string-translation', '_wpnonce_string-translation' ); + $string_table->display(); + printf( '
    ', esc_html__( 'Clean strings translation database', 'polylang' ) ); + ?> +

    + +
    +
    + +
    + +
    diff --git a/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/uninstall.php b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/uninstall.php new file mode 100644 index 000000000..c2367fde9 --- /dev/null +++ b/wp-content/plugins/polylang-pro/vendor/wpsyntex/polylang/uninstall.php @@ -0,0 +1,136 @@ +get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) { + switch_to_blog( $blog_id ); + $this->uninstall(); + } + restore_current_blog(); + } + else { + $this->uninstall(); + } + } + + /** + * Removes ALL plugin data + * only when the relevant option is active + * + * @since 0.5 + */ + public function uninstall() { + global $wpdb; + + do_action( 'pll_uninstall' ); + + // Need to register the taxonomies + $pll_taxonomies = array( 'language', 'term_language', 'post_translations', 'term_translations' ); + foreach ( $pll_taxonomies as $taxonomy ) { + register_taxonomy( $taxonomy, null, array( 'label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false ) ); + } + + $languages = get_terms( array( 'taxonomy' => 'language', 'hide_empty' => false ) ); + + // Delete users options + delete_metadata( 'user', 0, 'pll_filter_content', '', true ); + delete_metadata( 'user', 0, 'pll_dismissed_notices', '', true ); // Legacy meta. + foreach ( $languages as $lang ) { + delete_metadata( 'user', 0, "description_{$lang->slug}", '', true ); + } + + // Delete menu language switchers + $ids = get_posts( + array( + 'post_type' => 'nav_menu_item', + 'numberposts' => -1, + 'nopaging' => true, + 'fields' => 'ids', + 'meta_key' => '_pll_menu_item', + ) + ); + + foreach ( $ids as $id ) { + wp_delete_post( $id, true ); + } + + /* + * Backward compatibility with Polylang < 3.4. + * Delete the legacy strings translations. + */ + register_post_type( 'polylang_mo', array( 'rewrite' => false, 'query_var' => false ) ); + $ids = get_posts( + array( + 'post_type' => 'polylang_mo', + 'post_status' => 'any', + 'numberposts' => -1, + 'nopaging' => true, + 'fields' => 'ids', + ) + ); + foreach ( $ids as $id ) { + wp_delete_post( $id, true ); + } + + // Delete all what is related to languages and translations + $term_ids = array(); + $tt_ids = array(); + + foreach ( get_terms( array( 'taxonomy' => $pll_taxonomies, 'hide_empty' => false ) ) as $term ) { + $term_ids[] = (int) $term->term_id; + $tt_ids[] = (int) $term->term_taxonomy_id; + } + + if ( ! empty( $term_ids ) ) { + $term_ids = array_unique( $term_ids ); + $wpdb->query( "DELETE FROM {$wpdb->terms} WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( "DELETE FROM {$wpdb->term_taxonomy} WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( "DELETE FROM {$wpdb->termmeta} WHERE term_id IN ( " . implode( ',', $term_ids ) . " ) AND meta_key='_pll_strings_translations'" ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + if ( ! empty( $tt_ids ) ) { + $tt_ids = array_unique( $tt_ids ); + $wpdb->query( "DELETE FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + // Delete options + delete_option( 'polylang' ); + delete_option( 'widget_polylang' ); // Automatically created by WP + delete_option( 'polylang_wpml_strings' ); // Strings registered with icl_register_string + delete_option( 'polylang_licenses' ); + delete_option( 'pll_dismissed_notices' ); + + // Delete transients + delete_transient( 'pll_languages_list' ); + } +} + +new PLL_Uninstall();