PluginProbe
Polylang / 1.5
Polylang v1.5
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
← All changes | admin/admin.php +323 -72 2.81.5 View file →
@@ -1,73 +1,167 @@
1 1 <?php
2 -/**
3 - * @package Polylang
4 - */
5 2
6 -/**
7 - * Admin side controller
3 +/*
4 + * admin side controller
8 5 * accessible in $polylang global object
9 6 *
10 - * Properties:
11 - * options => inherited, reference to Polylang options array
12 - * model => inherited, reference to PLL_Model object
13 - * links_model => inherited, reference to PLL_Links_Model object
14 - * links => inherited, reference to PLL_Admin_Links object
15 - * static_pages => inherited, reference to PLL_Admin_Static_Pages object
16 - * filters_links => inherited, reference to PLL_Filters_Links object
17 - * curlang => inherited, optional, current language used to filter the content (language of the post or term being edited, equal to filter_lang otherwise)
18 - * filter_lang => inherited, optional, current status of the admin languages filter (in the admin bar)
19 - * pref_lang => inherited, preferred language used as default when saving posts or terms
20 - * posts => reference to PLL_CRUD_Posts object
21 - * terms => reference to PLL_CRUD_Terms object
22 - * filters => reference to PLL_Admin_Filters object
23 - * filters_columns => reference to PLL_Admin_Filters_Columns object
24 - * filters_post => reference to PLL_Admin_Filters_Post object
25 - * filters_term => reference to PLL_Admin_filters_Term object
26 - * nav_menu => reference to PLL_Admin_Nav_Menu object
27 - * block_editor => reference to PLL_Admin_Block_Editor object
28 - * classic_editor => reference to PLL_Admin_Classic_Editor object
29 - * filters_media => optional, reference to PLL_Admin_Filters_Media object
7 + * properties:
8 + * options => inherited, reference to Polylang options array
9 + * model => inherited, reference to PLL_Model object
10 + * links_model => inherited, reference to PLL_Links_Model object
11 + * settings_page => optional, reference ot PLL_Settings object
12 + * links => reference to PLL_Links object
13 + * curlang => optional, current language used to filter admin content
14 + * pref_lang => preferred language used as default when saving posts or terms
15 + * filters => reference to PLL_Filters object
16 + * filters_columns => reference to PLL_Admin_Filters_Columns object
17 + * filters_post => reference to PLL_Admin_Filters_Post object
18 + * filters_term => reference to PLL_Admin_filters_Term object
19 + * nav_menu => reference to PLL_Admin_Nav_Menu object
20 + * sync => reference to PLL_Admin_Sync object
21 + * filters_media => optional, reference to PLL_Admin_Filters_Media object
30 22 *
31 23 * @since 1.2
32 24 */
33 -class PLL_Admin extends PLL_Admin_Base {
34 - public $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $filters_media;
25 +class PLL_Admin extends PLL_Base {
26 + public $curlang, $pref_lang;
27 + public $settings_page, $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $sync, $filters_media;
35 28
36 - /**
37 - * Loads the polylang text domain
38 - * Setups filters and action needed on all admin pages and on plugins page
29 + /*
30 + * loads the polylang text domain
31 + * setups filters and action needed on all admin pages and on plugins page
39 32 *
40 33 * @since 1.2
41 34 *
42 35 * @param object $links_model
43 36 */
44 - public function __construct( &$links_model ) {
45 - parent::__construct( $links_model );
37 + public function __construct(&$links_model) {
38 + parent::__construct($links_model);
46 39
47 - // Adds a 'settings' link in the plugins table
48 - add_filter( 'plugin_action_links_' . POLYLANG_BASENAME, array( $this, 'plugin_action_links' ) );
49 - add_action( 'in_plugin_update_message-' . POLYLANG_BASENAME, array( $this, 'plugin_update_message' ), 10, 2 );
40 + // plugin i18n, only needed for backend
41 + load_plugin_textdomain('polylang', false, basename(POLYLANG_DIR).'/languages');
42 +
43 + // adds the link to the languages panel in the wordpress admin menu
44 + add_action('admin_menu', array(&$this, 'add_menus'));
45 +
46 + // setup js scripts and css styles
47 + add_action('admin_enqueue_scripts', array(&$this, 'admin_enqueue_scripts'));
48 + add_action('admin_print_footer_scripts', array(&$this, 'admin_print_footer_scripts'));
49 +
50 + // adds a 'settings' link in the plugins table
51 + add_filter('plugin_action_links_' . POLYLANG_BASENAME, array(&$this, 'plugin_action_links'));
52 + add_action('in_plugin_update_message-' . POLYLANG_BASENAME, array(&$this, 'plugin_update_message'), 10, 2);
50 53 }
51 54
52 - /**
53 - * Setups filters and action needed on all admin pages and on plugins page
54 - * Loads the settings pages or the filters base on the request
55 + /*
56 + * setups filters and action needed on all admin pages and on plugins page
57 + * loads the settings pages or the filters base on the request
55 58 *
56 59 * @since 1.2
60 + *
61 + * @param object $links_model
57 62 */
58 63 public function init() {
59 - parent::init();
64 + if (PLL_SETTINGS)
65 + $this->settings_page = new PLL_Settings($this);
60 66
61 - // Setup filters for admin pages
62 - // Priority 5 to make sure filters are there before customize_register is fired
63 - if ( $this->model->get_languages_list() ) {
64 - add_action( 'wp_loaded', array( $this, 'add_filters' ), 5 );
67 + if (!$this->model->get_languages_list())
68 + return;
69 +
70 + $this->links = new PLL_Links($this);
71 +
72 + // filter admin language for users
73 + // we must not call user info before WordPress defines user roles in wp-settings.php
74 + add_filter('setup_theme', array(&$this, 'init_user'));
75 +
76 + // adds the languages in admin bar
77 + add_action('admin_bar_menu', array(&$this, 'admin_bar_menu'), 100); // 100 determines the position
78 +
79 + // setup filters for admin pages
80 + if (!PLL_SETTINGS)
81 + add_action('wp_loaded', array(&$this, 'add_filters'));
82 + }
83 +
84 + /*
85 + * adds the link to the languages panel in the wordpress admin menu
86 + *
87 + * @since 0.1
88 + */
89 + public function add_menus() {
90 + add_submenu_page('options-general.php', $title = __('Languages', 'polylang'), $title, 'manage_options', 'mlang',
91 + PLL_SETTINGS ? array($this->settings_page, 'languages_page') : create_function('', ''));
92 + }
93 +
94 + /*
95 + * setup js scripts & css styles (only on the relevant pages)
96 + *
97 + * @since 0.6
98 + */
99 + public function admin_enqueue_scripts() {
100 + $screen = get_current_screen();
101 + $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
102 +
103 + // for each script:
104 + // 0 => the pages on which to load the script
105 + // 1 => the scripts it needs to work
106 + // 2 => 1 if loaded even if languages have not been defined yet, 0 otherwise
107 + // 3 => 1 if loaded in footer
108 + // FIXME: check if I can load more scripts in footer
109 + $scripts = array(
110 + 'admin' => array( array('settings_page_mlang'), array('jquery', 'wp-ajax-response', 'postbox'), 1 , 0),
111 + 'post' => array( array('post', 'media', 'async-upload', 'edit'), array('jquery', 'wp-ajax-response', 'inline-edit-post', 'post', 'jquery-ui-autocomplete'), 0 , 0),
112 + 'term' => array( array('edit-tags'), array('jquery', 'wp-ajax-response', 'jquery-ui-autocomplete'), 0, 1),
113 + 'user' => array( array('profile', 'user-edit'), array('jquery'), 0 , 0),
114 + );
115 +
116 + foreach ($scripts as $script => $v)
117 + if (in_array($screen->base, $v[0]) && ($v[2] || $this->model->get_languages_list()))
118 + wp_enqueue_script('pll_'.$script, POLYLANG_URL .'/js/'.$script.$suffix.'.js', $v[1], POLYLANG_VERSION, $v[3]);
119 +
120 + wp_enqueue_style('polylang_admin', POLYLANG_URL .'/css/admin'.$suffix.'.css', array(), POLYLANG_VERSION);
121 +
122 + // backward compatibility WP < 3.8
123 + // don't load this for old versions
124 + if (version_compare($GLOBALS['wp_version'], '3.8alpha' , '>='))
125 + wp_enqueue_style('polylang_admin_mobi', POLYLANG_URL .'/css/admin-mobi'.$suffix.'.css', array(), POLYLANG_VERSION);
126 + }
127 +
128 + /*
129 + * sets pll_ajax_backend on all backend ajax request
130 + *
131 + * @since 1.4
132 + */
133 + public function admin_print_footer_scripts() {
134 + global $post_ID;
135 + $params = array('pll_ajax_backend' => 1);
136 + if (!empty($post_ID))
137 + $params = array_merge($params, array('pll_post_id' => $post_ID));
138 +
139 + $str = $arr = '';
140 + foreach ($params as $k => $v) {
141 + $str .= $k . '=' . $v . '&';
142 + $arr .= (empty($arr) ? '' : ', ') . $k . ': ' . $v;
65 143 }
144 +?>
145 +<script type="text/javascript">
146 + if (typeof jQuery != 'undefined') {
147 + (function($){
148 + $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
149 + if (typeof options.data == 'string') {
150 + options.data = '<?php echo $str;?>'+options.data;
151 + }
152 + else {
153 + options.data = $.extend(options.data, {<?php echo $arr;?>});
154 + }
155 + });
156 + })(jQuery)
66 157 }
158 +</script><?php
67 159
68 - /**
69 - * Adds a 'settings' link in the plugins table
160 + }
161 +
162 + /*
163 + * adds a 'settings' link in the plugins table
70 164 *
71 165 * @since 0.1
72 166 *
73 167 * @param array $links list of links associated to the plugin
@@ -72,53 +166,210 @@
72 166 *
73 167 * @param array $links list of links associated to the plugin
74 168 * @return array modified list of links
75 169 */
76 - public function plugin_action_links( $links ) {
77 - array_unshift( $links, '<a href="admin.php?page=mlang">' . __( 'Settings', 'polylang' ) . '</a>' );
170 + public function plugin_action_links($links) {
171 + array_unshift($links, '<a href="admin.php?page=mlang">' . __('Settings', 'polylang') . '</a>');
78 172 return $links;
79 173 }
80 174
81 - /**
82 - * Adds the upgrade notice in plugins table
175 + /*
176 + * adds the upgrade notice in plugins table
83 177 *
84 178 * @since 1.1.6
85 179 *
86 - * @param array $plugin_data Not used
87 - * @param object $r Plugin update data
180 + * @param array $plugin_data not used
181 + * @param object $r plugin update data
88 182 */
89 - public function plugin_update_message( $plugin_data, $r ) {
90 - if ( isset( $r->upgrade_notice ) ) {
91 - printf( '<p style="margin: 3px 0 0 0; border-top: 1px solid #ddd; padding-top: 3px">%s</p>', esc_html( $r->upgrade_notice ) );
183 + function plugin_update_message($plugin_data, $r) {
184 + if (isset($r->upgrade_notice))
185 + printf('<p style="margin: 3px 0 0 0; border-top: 1px solid #ddd; padding-top: 3px">%s</p>', $r->upgrade_notice);
186 + }
187 +
188 + /*
189 + * defines the backend language and the admin language filter based on user preferences
190 + *
191 + * @since 1.2.3
192 + */
193 + public function init_user() {
194 + // backend locale
195 + add_filter('locale', array(&$this, 'get_locale'));
196 +
197 + // language for admin language filter: may be empty
198 + // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
199 + if (!defined('DOING_AJAX') && !empty($_GET['lang']) && !is_numeric($_GET['lang']) && current_user_can('edit_user', $user_id = get_current_user_id()))
200 + update_user_meta($user_id, 'pll_filter_content', ($lang = $this->model->get_language($_GET['lang'])) ? $lang->slug : '');
201 +
202 + $this->curlang = $this->model->get_language(get_user_meta(get_current_user_id(), 'pll_filter_content', true));
203 +
204 + // set preferred language for use when saving posts and terms: must not be empty
205 + $this->pref_lang = empty($this->curlang) ? $this->model->get_language($this->options['default_lang']) : $this->curlang;
206 + $this->pref_lang = apply_filters('pll_admin_preferred_language', $this->pref_lang);
207 +
208 + // inform that the admin language has been set
209 + // only if the admin language is one of the Polylang defined language
210 + if ($curlang = $this->model->get_language(get_locale())) {
211 + $GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
212 + do_action('pll_language_defined', $curlang->slug, $curlang);
92 213 }
214 + else
215 + do_action('pll_no_language_defined'); // to load overriden textdomains
93 216 }
94 217
95 - /**
96 - * Setup filters for admin pages
218 + /*
219 + * get the locale based on user preference
97 220 *
221 + * @since 0.4
222 + *
223 + * @param string $locale
224 + * @return string modified locale
225 + */
226 + public function get_locale($locale) {
227 + return ($loc = get_user_meta(get_current_user_id(), 'user_lang', 'true')) ? $loc : $locale;
228 + }
229 +
230 + /*
231 + * setup filters for admin pages
232 + *
98 233 * @since 1.2
99 - * @since 2.7 instantiate a PLL_Bulk_Translate instance.
100 234 */
101 235 public function add_filters() {
102 - // All these are separated just for convenience and maintainability
103 - $classes = array( 'Filters', 'Filters_Columns', 'Filters_Post', 'Filters_Term', 'Nav_Menu', 'Classic_Editor', 'Block_Editor' );
236 + // all these are separated just for convenience and maintainability
237 + $classes = array('Filters', 'Filters_Columns', 'Filters_Post', 'Filters_Term', 'Nav_Menu', 'Sync');
104 238
105 - // Don't load media filters if option is disabled or if user has no right
106 - if ( $this->options['media_support'] && ( $obj = get_post_type_object( 'attachment' ) ) && ( current_user_can( $obj->cap->edit_posts ) || current_user_can( $obj->cap->create_posts ) ) ) {
239 + // don't load media filters if option is disabled or if user has no right
240 + if ($this->options['media_support'] && ($obj = get_post_type_object('attachment')) && current_user_can($obj->cap->edit_posts) && current_user_can($obj->cap->create_posts))
107 241 $classes[] = 'Filters_Media';
242 +
243 + foreach ($classes as $class) {
244 + $obj = strtolower($class);
245 + $class = apply_filters('pll_' . $obj, 'PLL_Admin_' . $class);
246 + $this->$obj = new $class($this);
108 247 }
248 + }
109 249
110 - foreach ( $classes as $class ) {
111 - $obj = strtolower( $class );
250 + /*
251 + * adds the languages list in admin bar for the admin languages filter
252 + *
253 + * @since 0.9
254 + *
255 + * @param object $wp_admin_bar
256 + */
257 + public function admin_bar_menu($wp_admin_bar) {
258 + $url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
112 259
113 - /**
114 - * Filter the class to instantiate when loading admin filters
115 - *
116 - * @since 1.5
117 - *
118 - * @param string $class class name
119 - */
120 - $class = apply_filters( 'pll_' . $obj, 'PLL_Admin_' . $class );
121 - $this->$obj = new $class( $this );
260 + $all_item = (object) array(
261 + 'slug' => 'all',
262 + 'name' => __('Show all languages', 'polylang'),
263 + 'flag' => '<span class="ab-icon"></span>'
264 + );
265 +
266 + $selected = empty($this->curlang) ? $all_item : $this->curlang;
267 +
268 + $wp_admin_bar->add_menu(array(
269 + 'id' => 'languages',
270 + 'title' => $selected->flag . '<span class="ab-label">'. esc_html($selected->name) . '</span>',
271 + 'meta' => array('title' => __('Filters content by language', 'polylang')),
272 + ));
273 +
274 + foreach (array_merge(array($all_item), $this->model->get_languages_list()) as $lang) {
275 + if ($selected->slug == $lang->slug)
276 + continue;
277 +
278 + $img = empty($lang->flag) ? '' : (false !== strpos($lang->flag, 'img') ? $lang->flag . '&nbsp;' : $lang->flag);
279 +
280 + $wp_admin_bar->add_menu(array(
281 + 'parent' => 'languages',
282 + 'id' => $lang->slug,
283 + 'title' => $lang->flag . esc_html($lang->name),
284 + 'href' => esc_url(add_query_arg('lang', $lang->slug, remove_query_arg('paged',$url))),
285 + ));
122 286 }
287 + }
288 + /*
289 + * downloads mofiles from http://svn.automattic.com/wordpress-i18n/
290 + * FIXME is it the best class for this?
291 + * FIXME use language packs API coming with WP 3.7 instead (does not seem to work fully yet)
292 + *
293 + * @since 0.6
294 + *
295 + * @param string $locale locale to download
296 + * @param bool $upgrade optional true if this is an upgrade, false if this is the first download, defaults to false
297 + * @return bool true on success, false otherwise
298 + */
299 + static public function download_mo($locale, $upgrade = false) {
300 + global $wp_version;
301 + $mofile = WP_LANG_DIR."/$locale.mo";
302 +
303 + // does file exists ?
304 + if ((file_exists($mofile) && !$upgrade) || $locale == 'en_US')
305 + return true;
306 +
307 + // does language directory exists ?
308 + if (!is_dir(WP_LANG_DIR)) {
309 + if (!@mkdir(WP_LANG_DIR))
310 + return false;
311 + }
312 +
313 + // will first look in tags/ (most languages) then in branches/ (only Greek ?)
314 + $base = 'http://svn.automattic.com/wordpress-i18n/'.$locale;
315 + $bases = array($base.'/tags/', $base.'/branches/');
316 +
317 + foreach ($bases as $base) {
318 + // get all the versions available in the subdirectory
319 + $resp = wp_remote_get($base);
320 + if (is_wp_error($resp) || 200 != $resp['response']['code'])
321 + continue;
322 +
323 + preg_match_all('#>([0-9\.]+)\/#', $resp['body'], $matches);
324 + if (empty($matches[1]))
325 + continue;
326 +
327 + rsort($matches[1]); // sort from newest to oldest
328 + $versions = $matches[1];
329 +
330 + $newest = $upgrade ? $upgrade : $wp_version;
331 + foreach ($versions as $key=>$version) {
332 + // will not try to download a too recent mofile
333 + if (version_compare($version, $newest, '>'))
334 + unset($versions[$key]);
335 + // will not download an older version if we are upgrading
336 + if ($upgrade && version_compare($version, $wp_version, '<='))
337 + unset($versions[$key]);
338 + }
339 +
340 + $versions = array_splice($versions, 0, 5); // reduce the number of versions to test to 5
341 + $args = array('timeout' => 30, 'stream' => true);
342 +
343 + // try to download the file
344 + foreach ($versions as $version) {
345 + $resp = wp_remote_get($base."$version/messages/$locale.mo", $args + array('filename' => $mofile));
346 + if (is_wp_error($resp) || 200 != $resp['response']['code']) {
347 + unlink($mofile); // otherwise we download a gzipped 404 page
348 + continue;
349 + }
350 + // try to download ms and continents-cities files if exist (will not return false if failed)
351 + // with new files introduced in WP 3.4
352 + foreach (array('ms', 'continents-cities', 'admin', 'admin-network') as $file) {
353 + $resp = wp_remote_get($base."$version/messages/$file-$locale.mo", $args + array('filename' => WP_LANG_DIR."/$file-$locale.mo"));
354 + if (is_wp_error($resp) || 200 != $resp['response']['code'])
355 + unlink(WP_LANG_DIR."/$file-$locale.mo");
356 + }
357 + // try to download theme files if exist (will not return false if failed)
358 + // FIXME not updated when the theme is updated outside a core update
359 + foreach (array('twentyten', 'twentyeleven', 'twentytwelve', 'twentythirteen', 'twentyfourteen') as $theme) {
360 + if (!is_dir($theme_dir = get_theme_root()."/$theme/languages"))
361 + continue; // the theme is not present
362 +
363 + $resp = wp_remote_get($base."$version/messages/$theme/$locale.mo", $args + array('filename' => "$theme_dir/$locale.mo"));
364 + if (is_wp_error($resp) || 200 != $resp['response']['code'])
365 + unlink("$theme_dir/$locale.mo");
366 + }
367 + return true;
368 + }
369 + }
370 +
371 + // we did not succeeded to download a file :(
372 + add_settings_error('general', 'pll_download_mo', __('The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang'));
373 + return false;
123 374 }
124 375 }