PluginProbe
Polylang / 2.5.4
Polylang v2.5.4
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / admin / admin-base.php

admin-base.php in Polylang 2.5.4, at admin/admin-base.php

385 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Base class for both admin
5 *
6 * @since 1.8
7 */
8 class PLL_Admin_Base extends PLL_Base {
9 public $filter_lang, $curlang, $pref_lang;
10
11 /**
12 * Loads the polylang text domain
13 * Setups actions needed on all admin pages
14 *
15 * @since 1.8
16 *
17 * @param object $links_model
18 */
19 public function __construct( &$links_model ) {
20 parent::__construct( $links_model );
21
22 // Plugin i18n, only needed for backend
23 load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ) . '/languages' );
24
25 // Adds the link to the languages panel in the WordPress admin menu
26 add_action( 'admin_menu', array( $this, 'add_menus' ) );
27
28 // Setup js scripts and css styles
29 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30 add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
31
32 add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_controls_enqueue_scripts' ) );
33
34 // Lingotek
35 if ( ! defined( 'POLYLANG_PRO' ) && ( ! defined( 'PLL_LINGOTEK_AD' ) || PLL_LINGOTEK_AD ) ) {
36 require_once POLYLANG_DIR . '/lingotek/lingotek.php';
37 }
38 }
39
40 /**
41 * Setups filters and action needed on all admin pages and on plugins page
42 * Loads the settings pages or the filters base on the request
43 *
44 * @since 1.2
45 */
46 public function init() {
47 if ( ! $this->model->get_languages_list() ) {
48 return;
49 }
50
51 $this->notices = new PLL_Admin_Notices( $this );
52 $this->links = new PLL_Admin_Links( $this ); // FIXME needed here ?
53 $this->static_pages = new PLL_Admin_Static_Pages( $this ); // FIXME needed here ?
54 $this->filters_links = new PLL_Filters_Links( $this ); // FIXME needed here ?
55
56 // Filter admin language for users
57 // We must not call user info before WordPress defines user roles in wp-settings.php
58 add_filter( 'setup_theme', array( $this, 'init_user' ) );
59 add_filter( 'request', array( $this, 'request' ) );
60
61 // Adds the languages in admin bar
62 add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 100 ); // 100 determines the position
63 }
64
65 /**
66 * Adds the link to the languages panel in the WordPress admin menu
67 *
68 * @since 0.1
69 */
70 public function add_menus() {
71 // Prepare the list of tabs
72 $tabs = array( 'lang' => __( 'Languages', 'polylang' ) );
73
74 // Only if at least one language has been created
75 if ( $this->model->get_languages_list() ) {
76 $tabs['strings'] = __( 'Strings translations', 'polylang' );
77 }
78
79 $tabs['settings'] = __( 'Settings', 'polylang' );
80
81 /**
82 * Filter the list of tabs in Polylang settings
83 *
84 * @since 1.5.1
85 *
86 * @param array $tabs list of tab names
87 */
88 $tabs = apply_filters( 'pll_settings_tabs', $tabs );
89
90 foreach ( $tabs as $tab => $title ) {
91 $page = 'lang' === $tab ? 'mlang' : "mlang_$tab";
92 if ( empty( $parent ) ) {
93 $parent = $page;
94 add_menu_page( $title, __( 'Languages', 'polylang' ), 'manage_options', $page, null, 'dashicons-translation' );
95 }
96
97 add_submenu_page( $parent, $title, $title, 'manage_options', $page, array( $this, 'languages_page' ) );
98 }
99 }
100
101 /**
102 * Setup js scripts & css styles ( only on the relevant pages )
103 *
104 * @since 0.6
105 */
106 public function admin_enqueue_scripts() {
107 $screen = get_current_screen();
108 if ( empty( $screen ) ) {
109 return;
110 }
111
112 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
113
114 // For each script:
115 // 0 => the pages on which to load the script
116 // 1 => the scripts it needs to work
117 // 2 => 1 if loaded even if languages have not been defined yet, 0 otherwise
118 // 3 => 1 if loaded in footer
119 // FIXME: check if I can load more scripts in footer
120 $scripts = array(
121 'post' => array( array( 'edit' ), array( 'jquery', 'wp-ajax-response' ), 0, 1 ),
122 'media' => array( array( 'upload' ), array( 'jquery' ), 0, 1 ),
123 'term' => array( array( 'edit-tags', 'term' ), array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), 0, 1 ),
124 'user' => array( array( 'profile', 'user-edit' ), array( 'jquery' ), 0, 0 ),
125 'widgets' => array( array( 'widgets' ), array( 'jquery' ), 0, 0 ),
126 );
127
128 if ( ! empty( $screen->post_type ) && $this->model->is_translated_post_type( $screen->post_type ) ) {
129 $scripts['classic-editor'] = array( array( 'post', 'media', 'async-upload' ), array( 'jquery', 'wp-ajax-response', 'post', 'jquery-ui-autocomplete' ), 0, 1 );
130
131 // Block editor in WP 5.0+
132 if ( method_exists( $screen, 'is_block_editor' ) && $screen->is_block_editor() ) {
133 $scripts['block-editor'] = array( array( 'post' ), array( 'wp-api-fetch' ), 0, 1 );
134 }
135 }
136
137 foreach ( $scripts as $script => $v ) {
138 if ( in_array( $screen->base, $v[0] ) && ( $v[2] || $this->model->get_languages_list() ) ) {
139 wp_enqueue_script( 'pll_' . $script, plugins_url( '/js/' . $script . $suffix . '.js', POLYLANG_FILE ), $v[1], POLYLANG_VERSION, $v[3] );
140 }
141 }
142
143 wp_enqueue_style( 'polylang_admin', plugins_url( '/css/admin' . $suffix . '.css', POLYLANG_FILE ), array(), POLYLANG_VERSION );
144
145 $this->localize_scripts();
146 }
147
148 /**
149 * Enqueue scripts to the WP Customizer.
150 *
151 * @since 2.4.0
152 */
153 public function customize_controls_enqueue_scripts() {
154 if ( $this->model->get_languages_list() ) {
155 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
156 wp_enqueue_script( 'pll_widgets', plugins_url( '/js/widgets' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION, true );
157 $this->localize_scripts();
158 }
159 }
160
161 /**
162 * Localize scripts.
163 *
164 * @since 2.4.0
165 */
166 public function localize_scripts() {
167 if ( wp_script_is( 'pll_widgets', 'enqueued' ) ) {
168 wp_localize_script(
169 'pll_widgets',
170 'pll_widgets',
171 array(
172 'flags' => wp_list_pluck( $this->model->get_languages_list(), 'flag', 'slug' ),
173 )
174 );
175 }
176 }
177
178 /**
179 * Sets pll_ajax_backend on all backend ajax request
180 * The final goal is to detect if an ajax request is made on admin or frontend
181 *
182 * Takes care to various situations:
183 * when the ajax request has no options.data thanks to ScreenfeedFr
184 * see: https://wordpress.org/support/topic/ajaxprefilter-may-not-work-as-expected
185 * when options.data is a json string
186 * see: https://wordpress.org/support/topic/polylang-breaking-third-party-ajax-requests-on-admin-panels
187 * when options.data is an empty string (GET request with the method 'load')
188 * see: https://wordpress.org/support/topic/invalid-url-during-wordpress-new-dashboard-widget-operation
189 *
190 * @since 1.4
191 */
192 public function admin_print_footer_scripts() {
193 global $post_ID, $tag_ID;
194
195 $params = array( 'pll_ajax_backend' => 1 );
196 if ( ! empty( $post_ID ) ) {
197 $params = array_merge( $params, array( 'pll_post_id' => (int) $post_ID ) );
198 }
199
200 if ( ! empty( $tag_ID ) ) {
201 $params = array_merge( $params, array( 'pll_term_id' => (int) $tag_ID ) );
202 }
203
204 $str = http_build_query( $params );
205 $arr = json_encode( $params );
206 ?>
207 <script type="text/javascript">
208 if (typeof jQuery != 'undefined') {
209 (function($){
210 $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
211 if ( -1 != options.url.indexOf( ajaxurl ) || -1 != ajaxurl.indexOf( options.url ) ) {
212 if ( 'undefined' === typeof options.data ) {
213 options.data = ( 'get' === options.type.toLowerCase() ) ? '<?php echo $str; ?>' : <?php echo $arr; ?>;
214 } else {
215 if ( 'string' === typeof options.data ) {
216 if ( '' === options.data && 'get' === options.type.toLowerCase() ) {
217 options.url = options.url+'&<?php echo $str; ?>';
218 } else {
219 try {
220 var o = $.parseJSON(options.data);
221 o = $.extend(o, <?php echo $arr; ?>);
222 options.data = JSON.stringify(o);
223 }
224 catch(e) {
225 options.data = '<?php echo $str; ?>&'+options.data;
226 }
227 }
228 } else {
229 options.data = $.extend(options.data, <?php echo $arr; ?>);
230 }
231 }
232 }
233 });
234 })(jQuery)
235 }
236 </script>
237 <?php
238 }
239
240 /**
241 * Sets the admin current language, used to filter the content
242 *
243 * @since 2.0
244 */
245 public function set_current_language() {
246 $this->curlang = $this->filter_lang;
247
248 // Edit Post
249 if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) {
250 $this->curlang = $lang;
251 } elseif ( 'post.php' === $GLOBALS['pagenow'] && isset( $_GET['post'] ) && is_numeric( $_GET['post'] ) && $lang = $this->model->post->get_language( (int) $_GET['post'] ) ) {
252 $this->curlang = $lang;
253 } elseif ( 'post-new.php' === $GLOBALS['pagenow'] && ( empty( $_GET['post_type'] ) || $this->model->is_translated_post_type( $_GET['post_type'] ) ) ) {
254 $this->curlang = empty( $_GET['new_lang'] ) ? $this->pref_lang : $this->model->get_language( $_GET['new_lang'] );
255 }
256
257 // Edit Term
258 // FIXME 'edit-tags.php' for backward compatibility with WP < 4.5
259 elseif ( in_array( $GLOBALS['pagenow'], array( 'edit-tags.php', 'term.php' ) ) && isset( $_GET['tag_ID'] ) && $lang = $this->model->term->get_language( (int) $_GET['tag_ID'] ) ) {
260 $this->curlang = $lang;
261 } elseif ( isset( $_REQUEST['pll_term_id'] ) && $lang = $this->model->term->get_language( (int) $_REQUEST['pll_term_id'] ) ) {
262 $this->curlang = $lang;
263 } elseif ( 'edit-tags.php' === $GLOBALS['pagenow'] && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( $_GET['taxonomy'] ) ) {
264 if ( ! empty( $_GET['new_lang'] ) ) {
265 $this->curlang = $this->model->get_language( $_GET['new_lang'] );
266 } elseif ( empty( $this->curlang ) ) {
267 $this->curlang = $this->pref_lang;
268 }
269 }
270
271 // Ajax
272 if ( wp_doing_ajax() && ! empty( $_REQUEST['lang'] ) ) {
273 $this->curlang = $this->model->get_language( $_REQUEST['lang'] );
274 }
275 }
276
277 /**
278 * Defines the backend language and the admin language filter based on user preferences
279 *
280 * @since 1.2.3
281 */
282 public function init_user() {
283 // Language for admin language filter: may be empty
284 // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
285 if ( ! wp_doing_ajax() && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
286 update_user_meta( $user_id, 'pll_filter_content', ( $lang = $this->model->get_language( $_GET['lang'] ) ) ? $lang->slug : '' );
287 }
288
289 $this->filter_lang = $this->model->get_language( get_user_meta( get_current_user_id(), 'pll_filter_content', true ) );
290
291 // Set preferred language for use when saving posts and terms: must not be empty
292 $this->pref_lang = empty( $this->filter_lang ) ? $this->model->get_language( $this->options['default_lang'] ) : $this->filter_lang;
293
294 /**
295 * Filter the preferred language on admin side
296 * The preferred language is used for example to determine the language of a new post
297 *
298 * @since 1.2.3
299 *
300 * @param object $pref_lang preferred language
301 */
302 $this->pref_lang = apply_filters( 'pll_admin_preferred_language', $this->pref_lang );
303
304 $this->set_current_language();
305
306 // Inform that the admin language has been set
307 // Only if the admin language is one of the Polylang defined language
308 if ( $curlang = $this->model->get_language( get_user_locale() ) ) {
309 /** This action is documented in frontend/choose-lang.php */
310 do_action( 'pll_language_defined', $curlang->slug, $curlang );
311 } else {
312 /** This action is documented in include/class-polylang.php */
313 do_action( 'pll_no_language_defined' ); // to load overridden textdomains
314 }
315 }
316
317 /**
318 * Avoids parsing a tax query when all languages are requested
319 * Fixes https://wordpress.org/support/topic/notice-undefined-offset-0-in-wp-includesqueryphp-on-line-3877 introduced in WP 4.1
320 *
321 * @see the suggestion of @boonebgorges, https://core.trac.wordpress.org/ticket/31246
322 *
323 * @since 1.6.5
324 *
325 * @param array $qvars
326 * @return array
327 */
328 public function request( $qvars ) {
329 if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
330 unset( $qvars['lang'] );
331 }
332
333 return $qvars;
334 }
335
336 /**
337 * Adds the languages list in admin bar for the admin languages filter
338 *
339 * @since 0.9
340 *
341 * @param object $wp_admin_bar
342 */
343 public function admin_bar_menu( $wp_admin_bar ) {
344 $all_item = (object) array(
345 'slug' => 'all',
346 'name' => __( 'Show all languages', 'polylang' ),
347 'flag' => '<span class="ab-icon"></span>',
348 );
349
350 $selected = empty( $this->filter_lang ) ? $all_item : $this->filter_lang;
351
352 $title = sprintf(
353 '<span class="ab-label"%1$s><span class="screen-reader-text">%2$s</span>%3$s</span>',
354 'all' === $selected->slug ? '' : sprintf( ' lang="%s"', esc_attr( $selected->get_locale( 'display' ) ) ),
355 __( 'Filters content by language', 'polylang' ),
356 esc_html( $selected->name )
357 );
358
359 $wp_admin_bar->add_menu(
360 array(
361 'id' => 'languages',
362 'title' => $selected->flag . $title,
363 'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged' ) ) ),
364 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
365 )
366 );
367
368 foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
369 if ( $selected->slug === $lang->slug ) {
370 continue;
371 }
372
373 $wp_admin_bar->add_menu(
374 array(
375 'parent' => 'languages',
376 'id' => $lang->slug,
377 'title' => $lang->flag . esc_html( $lang->name ),
378 'href' => esc_url( add_query_arg( 'lang', $lang->slug, remove_query_arg( 'paged' ) ) ),
379 'meta' => 'all' === $lang->slug ? array() : array( 'lang' => esc_attr( $lang->get_locale( 'display' ) ) ),
380 )
381 );
382 }
383 }
384 }
385