PluginProbe
Polylang / 0.6
Polylang v0.6
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 / include / admin.php

admin.php in Polylang 0.6, at include/admin.php

484 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once(PLL_INC.'/admin-filters.php');
4 require_once(PLL_INC.'/list-table.php');
5
6 // setups the Polylang admin panel and calls for other admin related classes
7 class Polylang_Admin extends Polylang_Base {
8 function __construct() {
9 new Polylang_Admin_Filters();
10
11 // adds a 'settings' link in the plugins table
12 $plugin_file = basename(POLYLANG_DIR).'/polylang.php';
13 add_filter('plugin_action_links_'.$plugin_file, array(&$this, 'plugin_action_links'));
14
15 // adds the link to the languages panel in the wordpress admin menu
16 add_action('admin_menu', array(&$this, 'add_menus'));
17
18 // ugrades languages files after a core upgrade (timing is important)
19 // FIXME private action ? is there a better way to do this ?
20 add_action( '_core_updated_successfully', array(&$this, 'upgrade_languages'), 1); // since WP 3.3
21 }
22
23 // adds a 'settings' link in the plugins table
24 function plugin_action_links($links) {
25 $settings_link = '<a href="admin.php?page=mlang">' . __('Settings') . '</a>';
26 array_unshift( $links, $settings_link );
27 return $links;
28 }
29
30 // adds the link to the languages panel in the wordpress admin menu
31 function add_menus() {
32 add_submenu_page('options-general.php', __('Languages', 'polylang'), __('Languages', 'polylang'), 'manage_options', 'mlang', array(&$this, 'languages_page'));
33 }
34
35 // used to update the translation when a language slug has been modified
36 function update_translations($type, $ids, $old_slug) {
37 foreach ($ids as $id) {
38 $tr = get_metadata($type, $id, '_translations', true);
39 if($tr) {
40 $tr = unserialize($tr);
41 $tr[$_POST['slug']] = $tr[$old_slug];
42 unset($tr[$old_slug]);
43 update_metadata($type, $id, '_translations', serialize($tr));
44 }
45 }
46 }
47
48 // used to delete the translation when a language is deleted
49 function delete_translations($type, $ids, $old_slug) {
50 foreach ($ids as $id) {
51 $tr = get_metadata($type, $id, '_translations', true);
52 if($tr) {
53 $tr = unserialize($tr);
54 unset($tr[$old_slug]);
55 update_metadata($type, $id, '_translations', serialize($tr));
56 }
57 }
58 }
59
60 // the languages panel
61 function languages_page() {
62 global $wp_rewrite;
63 $options = get_option('polylang');
64 $listlanguages = $this->get_languages_list();
65
66 // for nav menus form
67 $locations = get_registered_nav_menus();
68 $menus = wp_get_nav_menus();
69 $menu_lang = get_option('polylang_nav_menus');
70
71 // for widgets
72 $widget_lang = get_option('polylang_widgets');
73
74 $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
75
76 switch ($action) {
77 case 'add':
78 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
79 $error = $this->validate_lang();
80
81 if ($error == 0) {
82 wp_insert_term($_POST['name'],'language',array('slug'=>$_POST['slug'], 'description'=>$_POST['description'], 'term_group'=>$_POST['term_group']));
83 $wp_rewrite->flush_rules(); // refresh rewrite rules
84
85 if (!isset($options['default_lang'])) { // if this is the first language created, set it as default language
86 $options['default_lang'] = $_POST['slug'];
87 update_option('polylang', $options);
88 }
89 if (!$this->download_mo($_POST['description']))
90 $error = 5;
91 }
92
93 wp_redirect('admin.php?page=mlang'. ($error ? '&error='.$error : '') ); // to refresh the page (possible thanks to the $_GET['noheader']=true)
94 exit;
95 break;
96
97 case 'delete':
98 check_admin_referer('delete-lang');
99
100 if (isset($_GET['lang']) && $_GET['lang']) {
101 $lang_id = (int) $_GET['lang'];
102 $lang = $this->get_language($lang_id);
103 $lang_slug = $lang->slug;
104
105 // update the language slug in posts meta
106 $posts = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'meta_key'=>'_translations', 'post_type'=>'any', 'post_status'=>'any'));
107 $this->delete_translations('post', $posts, $lang_slug);
108
109 // update the language slug in categories & post tags meta
110 $terms= get_terms(get_taxonomies(array('show_ui'=>true)), array('get'=>'all', 'fields'=>'ids'));
111 $this->delete_translations('term', $terms, $lang_slug);
112
113 // FIXME should find something more efficient (with a sql query ?)
114 foreach ($terms as $id) {
115 if ($this->get_term_language($id)->term_id == $lang_id)
116 $this->delete_term_language($id); // delete language of this term
117 }
118
119 // delete menus locations
120 foreach ($locations as $location => $description)
121 unset($menu_lang[$location][$lang_slug]);
122 update_option('polylang_nav_menus', $menu_lang);
123
124 // delete language option in widgets
125 foreach ($widget_lang as $key=>$lang) {
126 if ($lang == $lang_slug)
127 unset ($widget_lang[$key]);
128 }
129 update_option('polylang_widgets', $widget_lang);
130
131 // delete the string translations
132 delete_option('polylang_mo'.$lang_id);
133
134 // delete the language itself
135 wp_delete_term($lang_id, 'language');
136 $wp_rewrite->flush_rules(); // refresh rewrite rules
137
138 // oops ! we deleted the default language...
139 if ($options['default_lang'] == $lang_slug) {
140 if (!empty($listlanguages))
141 $options['default_lang'] = reset($this->get_languages_list())->slug; // arbitrary choice...
142 else
143 unset($options['default_lang']);
144 update_option('polylang', $options);
145 }
146 }
147 wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
148 exit;
149 break;
150
151 case 'edit':
152 if (isset($_GET['lang']) && $_GET['lang'])
153 $edit_lang = $this->get_language((int) $_GET['lang']);
154 break;
155
156 case 'update':
157 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
158 $lang_id = (int) $_POST['lang_id'];
159 $lang = $this->get_language($lang_id);
160 $error = $this->validate_lang($lang);
161
162 if ($error == 0) {
163 // Update links to this language in posts and terms in case the slug has been modified
164 $old_slug = $lang->slug;
165
166 if ($old_slug != $_POST['slug']) {
167 // update the language slug in posts meta
168 $posts = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'meta_key'=>'_translations', 'post_type'=>'any', 'post_status'=>'any'));
169 $this->update_translations('post', $posts, $old_slug);
170
171 // update the language slug in categories & post tags meta
172 $terms = get_terms(get_taxonomies(array('show_ui'=>true)), array('get'=>'all', 'fields'=>'ids'));
173 $this->update_translations('term', $terms, $old_slug);
174
175 // update menus locations
176 foreach ($locations as $location => $description) {
177 if (isset($menu_lang[$location][$old_slug])) {
178 $menu_lang[$location][$_POST['slug']] = $menu_lang[$location][$old_slug];
179 unset($menu_lang[$location][$old_slug]);
180 }
181 }
182 update_option('polylang_nav_menus', $menu_lang);
183
184 // update language option in widgets
185 foreach ($widget_lang as $key=>$lang) {
186 if ($lang == $old_slug)
187 $widget_lang[$key] = $_POST['slug'];
188 }
189 update_option('polylang_widgets', $widget_lang);
190
191 // update the default language option if necessary
192 if ($options['default_lang'] == $old_slug) {
193 $options['default_lang'] = $_POST['slug'];
194 update_option('polylang', $options);
195 }
196 }
197
198 // and finally update the language itself
199 $args = array('name'=>$_POST['name'], 'slug'=>$_POST['slug'], 'description'=>$_POST['description'], 'term_group'=>$_POST['term_group']);
200 wp_update_term($lang_id, 'language', $args);
201 $wp_rewrite->flush_rules(); // refresh rewrite rules
202 }
203
204 wp_redirect('admin.php?page=mlang'. ($error ? '&error='.$error : '') ); // to refresh the page (possible thanks to the $_GET['noheader']=true)
205 exit;
206 break;
207
208 case 'nav-menus':
209 check_admin_referer( 'nav-menus-lang', '_wpnonce_nav-menus-lang' );
210
211 $menu_lang = $_POST['menu-lang'];
212 foreach ($locations as $location => $description)
213 foreach (array('switcher', 'show_names', 'show_flags', 'force_home') as $key)
214 $menu_lang[$location][$key] = isset($menu_lang[$location][$key]) ? 1 : 0;
215
216 update_option('polylang_nav_menus', $menu_lang);
217 break;
218
219 case 'string-translation':
220 check_admin_referer( 'string-translation', '_wpnonce_string-translation' );
221
222 $mo = new MO();
223 foreach ($listlanguages as $language) {
224 $reader = new POMO_StringReader(base64_decode(get_option('polylang_mo'.$language->term_id)));
225 $mo->import_from_reader($reader);
226
227 foreach ($_POST['string'] as $key=>$string) {
228 $string = stripslashes($string);
229 $mo->add_entry($mo->make_entry($string, stripslashes($_POST['translation'][$language->name][$key])));
230 }
231 // FIXME should I clean the mo object to remove unused strings ?
232 // use base64_encode to store binary mo data in database text field
233 update_option('polylang_mo'.$language->term_id, base64_encode($mo->export()));
234 }
235 break;
236
237 case 'options':
238 check_admin_referer( 'options-lang', '_wpnonce_options-lang' );
239
240 $options['default_lang'] = $_POST['default_lang'];
241 $options['browser'] = isset($_POST['browser']) ? 1 : 0;
242 $options['rewrite'] = $_POST['rewrite'];
243 $options['hide_default'] = isset($_POST['hide_default']) ? 1 : 0;
244 update_option('polylang', $options);
245
246 // refresh refresh permalink structure and rewrite rules in case rewrite or hide_default options have been modified
247 $wp_rewrite->extra_permastructs['language'][0] = $options['rewrite'] ? '%language%' : '/language/%language%';
248 $wp_rewrite->flush_rules();
249
250 // fills existing posts & terms with default language
251 if (isset($_POST['fill_languages'])) {
252 if(isset($_POST['posts'])) {
253 foreach(explode(',', $_POST['posts']) as $post_id) {
254 $this->set_post_language($post_id, $options['default_lang']);
255 }
256 }
257 if(isset($_POST['terms'])) {
258 foreach(explode(',', $_POST['terms']) as $term_id) {
259 $this->set_term_language($term_id, $options['default_lang']);
260 }
261 }
262 }
263 break;
264
265 default:
266 break;
267 }
268
269 // prepare the list of tabs
270 $tabs = array(
271 'lang' => __('Languages','polylang'),
272 'menus' => __('Menus','polylang'),
273 'strings' => __('Strings translation','polylang'),
274 'settings' => __('Settings', 'polylang')
275 );
276 if (!current_theme_supports( 'menus' ))
277 unset($tabs['menus']); // don't display the menu tab if the active theme does not support nav menus
278
279 $active_tab = isset($_GET['tab']) && $_GET['tab'] ? $_GET['tab'] : 'lang';
280
281 switch($active_tab) {
282 case 'lang':
283 // prepare the list table of languages
284 $data = array();
285 foreach ($listlanguages as $lang)
286 $data[] = array_merge( (array) $lang, array('flag' => $this->get_flag($lang)) ) ;
287
288 $list_table = new Polylang_List_Table();
289 $list_table->prepare_items($data);
290
291 // error messages for data validation
292 $errors[1] = __('Enter a valid WorPress locale', 'polylang');
293 $errors[2] = __('The language code must be 2 characters long', 'polylang');
294 $errors[3] = __('The language code must be unique', 'polylang');
295 $errors[4] = __('The language must have a name', 'polylang');
296 $errors[5] = __('The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang');
297 break;
298
299 case 'menus':
300 // prepare the list of options for the language switcher
301 // FIXME do not include the dropdown yet as I need to create a better script (only available for the widget now)
302 $menu_options = array(
303 'switcher' => __('Displays a language switcher at the end of the menu', 'polylang'),
304 'show_names' => __('Displays language names', 'polylang'),
305 'show_flags' => __('Displays flags', 'polylang'),
306 'force_home' => __('Forces link to front page', 'polylang')
307 );
308
309 // default values
310 foreach ($locations as $key=>$location)
311 $menu_lang[$key] = wp_parse_args($menu_lang[$key], array('switcher'=> 0, 'show_names'=>1, 'show_flags'=>0, 'force_home'=>0));
312
313 break;
314
315 case 'strings':
316 global $wp_registered_widgets;
317
318 // WP strings
319 $this->register_string(__('Site Title'), get_option('blogname'));
320 $this->register_string(__('Tagline'), get_option('blogdescription'));
321
322 // widgets titles
323 $sidebars = wp_get_sidebars_widgets();
324 foreach ($sidebars as $sidebar => $widgets) {
325 if ($sidebar == 'wp_inactive_widgets')
326 continue;
327
328 foreach ($widgets as $widget) {
329 if (!isset($wp_registered_widgets[$widget]))
330 continue;
331
332 $widget_settings = $wp_registered_widgets[$widget]['callback'][0]->get_settings();
333 $number = $wp_registered_widgets[$widget]['params'][0]['number'];
334 $title = $widget_settings[$number]['title'];
335 if(isset($title) && $title)
336 $this->register_string(__('Widget title'), $title);
337 }
338 }
339
340 $data = &$this->strings;
341
342 // load translations
343 $mo = new MO();
344 foreach ($listlanguages as $language) {
345 $reader = new POMO_StringReader(base64_decode(get_option('polylang_mo'.$language->term_id)));
346 $mo->import_from_reader($reader);
347
348 foreach ($data as $key=>$row) {
349 $data[$key]['translations'][$language->name] = $mo->translate($data[$key]['string']);
350 $data[$key]['row'] = $key; // store the row number for convenience
351 }
352 }
353
354 $string_table = new Polylang_String_Table();
355 $string_table->prepare_items($data);
356 break;
357
358 case 'settings':
359 //FIXME rework this as it would not be efficient in case of thousands posts or terms !
360 // detects posts & pages without language set
361 $q = array(
362 'numberposts'=>-1,
363 'post_type' => 'any',
364 'post_status'=>'any',
365 'fields' => 'ids',
366 'tax_query' => array(array(
367 'taxonomy'=> 'language',
368 'terms'=> get_terms('language', array('fields'=>'ids')),
369 'operator'=>'NOT IN'
370 ))
371 );
372 $posts = implode(',', get_posts($q));
373
374 // detects categories & post tags without language set
375 $terms = get_terms(get_taxonomies(array('show_ui'=>true)), array('get'=>'all', 'fields'=>'ids'));
376
377 foreach ($terms as $key => $term_id) {
378 if ($this->get_term_language($term_id))
379 unset($terms[$key]);
380 }
381 $terms = implode(',', $terms);
382 break;
383
384 default:
385 break;
386 }
387 // displays the page
388 include(PLL_INC.'/languages-form.php');
389 }
390
391 // validates data entered when creating or updating a language
392 function validate_lang($lang = null) {
393 // validate locale
394 $loc = $_POST['description'];
395 if ( !preg_match('#^[a-z]{2}$#', $loc) && !preg_match('#^[a-z]{2}_[A-Z]{2}$#', $loc) )
396 $error = 1;
397
398 // validate slug length
399 if (strlen($_POST['slug']) != 2)
400 $error = 2;
401
402 // validate slug is unique
403 if ($this->get_language($_POST['slug']) != null && isset($lang) && $lang->slug != $_POST['slug'])
404 $error = 3;
405
406 // validate name
407 if ($_POST['name'] == '')
408 $error = 4;
409
410 return isset($error) ? $error : 0;
411 }
412
413 // downloads mofiles
414 function download_mo($locale, $upgrade = false) {
415 global $wp_version;
416 $mofile = WP_LANG_DIR."/$locale.mo";
417
418 // does file exists ?
419 if ((file_exists($mofile) && !$upgrade) || $locale == 'en_US')
420 return true;
421
422 // does language directory exists ?
423 if(!is_dir(WP_LANG_DIR)) {
424 if(!@mkdir(WP_LANG_DIR))
425 return false;
426 }
427
428 // will first look in tags/ (most languages) then in branches/ (only Greek ?)
429 $base = 'http://svn.automattic.com/wordpress-i18n/'.$locale;
430 $bases = array($base.'/tags/', $base.'/branches/');
431
432 foreach ($bases as $base) {
433 // get all the versions available in the subdirectory
434 $resp = wp_remote_get($base);
435 if (is_wp_error($resp) || 200 != $resp['response']['code'])
436 continue;
437
438 preg_match_all('#>([0-9\.]+)\/#', $resp['body'], $matches);
439 if (empty($matches[1]))
440 continue;
441
442 rsort($matches[1]);
443 $versions = $matches[1];
444
445 $newest = $upgrade ? $upgrade : $wp_version;
446 foreach ($versions as $key=>$version) {
447 // will not try to download a too recent mofile
448 if (version_compare($version, $newest, '>'))
449 unset($versions[$key]);
450 // will not download an older version if we are upgrading
451 if ($upgrade && version_compare($version, $wp_version, '<='))
452 unset($versions[$key]);
453 }
454
455 $versions = array_splice($versions, 0, 5); // reduce the number of versions to test to 5
456
457 // try to download the file
458 foreach ($versions as $version) {
459 $resp = wp_remote_get($base."$version/messages/$locale.mo", array('timeout' => 30, 'stream' => true, 'filename' => $mofile));
460 if (is_wp_error($resp) || 200 != $resp['response']['code'])
461 continue;
462
463 // try to download ms and continents-cities files if exist (will not return false if failed)
464 foreach (array("ms-$locale.mo", "continent-cities-$locale.mo") as $file)
465 wp_remote_get($base."$version/messages/$file", array('timeout' => 30, 'stream' => true, 'filename' => WP_LANG_DIR."/$file"));
466
467 return true;
468 }
469 }
470 // we did not succeeded to download a file :(
471 return false;
472 }
473
474 // ugrades languages files after a core upgrade
475 function upgrade_languages($version) {
476 apply_filters('update_feedback', __('Upgrading language files&#8230;', 'polylang'));
477 foreach ($this->get_languages_list() as $language)
478 $this->download_mo($language->description, $version);
479 }
480
481 } // class Polylang_Admin
482
483 ?>
484