PluginProbe
Polylang / 2.3.1
Polylang v2.3.1
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.3.1, at admin/admin-base.php

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