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

360 lines 12.7 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 // Edit Post
204 if ( isset( $_REQUEST['pll_post_id'] ) && $lang = $this->model->post->get_language( (int) $_REQUEST['pll_post_id'] ) ) {
205 $this->curlang = $lang;
206 } elseif ( 'post.php' === $GLOBALS['pagenow'] && isset( $_GET['post'] ) && is_numeric( $_GET['post'] ) && $lang = $this->model->post->get_language( (int) $_GET['post'] ) ) {
207 $this->curlang = $lang;
208 } elseif ( 'post-new.php' === $GLOBALS['pagenow'] && ( empty( $_GET['post_type'] ) || $this->model->is_translated_post_type( $_GET['post_type'] ) ) ) {
209 $this->curlang = empty( $_GET['new_lang'] ) ? $this->pref_lang : $this->model->get_language( $_GET['new_lang'] );
210 }
211
212 // Edit Term
213 // FIXME 'edit-tags.php' for backward compatibility with WP < 4.5
214 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'] ) ) {
215 $this->curlang = $lang;
216 } elseif ( isset( $_REQUEST['pll_term_id'] ) && $lang = $this->model->term->get_language( (int) $_REQUEST['pll_term_id'] ) ) {
217 $this->curlang = $lang;
218 } elseif ( 'edit-tags.php' === $GLOBALS['pagenow'] && isset( $_GET['taxonomy'] ) && $this->model->is_translated_taxonomy( $_GET['taxonomy'] ) ) {
219 if ( ! empty( $_GET['new_lang'] ) ) {
220 $this->curlang = $this->model->get_language( $_GET['new_lang'] );
221 } elseif ( empty( $this->curlang ) ) {
222 $this->curlang = $this->pref_lang;
223 }
224 }
225
226 // Ajax
227 if ( wp_doing_ajax() && ! empty( $_REQUEST['lang'] ) ) {
228 $this->curlang = $this->model->get_language( $_REQUEST['lang'] );
229 }
230 }
231
232 /**
233 * Defines the backend language and the admin language filter based on user preferences
234 *
235 * @since 1.2.3
236 */
237 public function init_user() {
238 // Backend locale
239 // FIXME: Backward compatibility with WP < 4.7
240 if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
241 add_filter( 'locale', array( $this, 'get_locale' ) );
242 }
243
244 // Language for admin language filter: may be empty
245 // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
246 if ( ! wp_doing_ajax() && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
247 update_user_meta( $user_id, 'pll_filter_content', ( $lang = $this->model->get_language( $_GET['lang'] ) ) ? $lang->slug : '' );
248 }
249
250 $this->filter_lang = $this->model->get_language( get_user_meta( get_current_user_id(), 'pll_filter_content', true ) );
251
252 // Set preferred language for use when saving posts and terms: must not be empty
253 $this->pref_lang = empty( $this->filter_lang ) ? $this->model->get_language( $this->options['default_lang'] ) : $this->filter_lang;
254
255 /**
256 * Filter the preferred language on admin side
257 * The preferred language is used for example to determine the language of a new post
258 *
259 * @since 1.2.3
260 *
261 * @param object $pref_lang preferred language
262 */
263 $this->pref_lang = apply_filters( 'pll_admin_preferred_language', $this->pref_lang );
264
265 $this->set_current_language();
266
267 // Inform that the admin language has been set
268 // Only if the admin language is one of the Polylang defined language
269 // FIXME test get_user_locale for backward compatibility with WP 4.7
270 if ( $curlang = $this->model->get_language( function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale() ) ) {
271 // FIXME: Backward compatibility with WP < 4.7
272 if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
273 $GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
274 }
275
276 /** This action is documented in frontend/choose-lang.php */
277 do_action( 'pll_language_defined', $curlang->slug, $curlang );
278 } else {
279 /** This action is documented in include/class-polylang.php */
280 do_action( 'pll_no_language_defined' ); // to load overridden textdomains
281 }
282 }
283
284 /**
285 * Avoids parsing a tax query when all languages are requested
286 * Fixes https://wordpress.org/support/topic/notice-undefined-offset-0-in-wp-includesqueryphp-on-line-3877 introduced in WP 4.1
287 * @see the suggestion of @boonebgorges, https://core.trac.wordpress.org/ticket/31246
288 *
289 * @since 1.6.5
290 *
291 * @param array $qvars
292 * @return array
293 */
294 public function request( $qvars ) {
295 if ( isset( $qvars['lang'] ) && 'all' === $qvars['lang'] ) {
296 unset( $qvars['lang'] );
297 }
298
299 return $qvars;
300 }
301
302 /**
303 * Get the locale based on user preference
304 * FIXME: Backward compatibility with WP < 4.7
305 *
306 * @since 0.4
307 *
308 * @param string $locale
309 * @return string modified locale
310 */
311 public function get_locale( $locale ) {
312 return ( $loc = get_user_meta( get_current_user_id(), 'locale', 'true' ) ) ? $loc : $locale;
313 }
314
315 /**
316 * Adds the languages list in admin bar for the admin languages filter
317 *
318 * @since 0.9
319 *
320 * @param object $wp_admin_bar
321 */
322 public function admin_bar_menu( $wp_admin_bar ) {
323 $all_item = (object) array(
324 'slug' => 'all',
325 'name' => __( 'Show all languages', 'polylang' ),
326 'flag' => '<span class="ab-icon"></span>',
327 );
328
329 $selected = empty( $this->filter_lang ) ? $all_item : $this->filter_lang;
330
331 $title = sprintf(
332 '<span class="ab-label"%1$s><span class="screen-reader-text">%2$s</span>%3$s</span>',
333 'all' === $selected->slug ? '' : sprintf( ' lang="%s"', esc_attr( $selected->get_locale( 'display' ) ) ),
334 __( 'Filters content by language', 'polylang' ),
335 esc_html( $selected->name )
336 );
337
338 $wp_admin_bar->add_menu( array(
339 'id' => 'languages',
340 'title' => $selected->flag . $title,
341 'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged' ) ) ),
342 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
343 ) );
344
345 foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
346 if ( $selected->slug === $lang->slug ) {
347 continue;
348 }
349
350 $wp_admin_bar->add_menu( array(
351 'parent' => 'languages',
352 'id' => $lang->slug,
353 'title' => $lang->flag . esc_html( $lang->name ),
354 'href' => esc_url( add_query_arg( 'lang', $lang->slug, remove_query_arg( 'paged' ) ) ),
355 'meta' => 'all' === $lang->slug ? array() : array( 'lang' => esc_attr( $lang->get_locale( 'display' ) ) ),
356 ) );
357 }
358 }
359 }
360