PluginProbe
Polylang / 0.9.5
Polylang v0.9.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
polylang / include / admin.php

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

452 lines 16.1 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.'/list-table.php');
4
5 // setups the Polylang admin panel
6 class Polylang_Admin extends Polylang_Admin_Base {
7
8 function __construct() {
9 parent::__construct();
10
11 // adds screen options and the about box in the languages admin panel
12 add_action('load-settings_page_mlang', array(&$this, 'load_page'));
13
14 // saves per-page value in screen option
15 add_filter('set-screen-option', create_function('$s, $o, $v', 'return $v;'), 10, 3);
16 }
17
18 // adds screen options and the about box in the languages admin panel
19 function load_page() {
20 // test of $_GET['tab'] avoids displaying the automatically generated screen options on other tabs
21 if (PLL_DISPLAY_ABOUT && (!isset($_GET['tab']) || $_GET['tab'] == 'lang')) {
22 add_meta_box('pll_about_box', __('About Polylang', 'polylang'), create_function('',"include(PLL_INC.'/about.php');"), 'settings_page_mlang', 'normal');
23 add_screen_option('per_page', array('label' => __('Languages', 'polylang'), 'default' => 10, 'option' => 'pll_lang_per_page'));
24 }
25
26 if (isset($_GET['tab']) && $_GET['tab'] == 'strings')
27 add_screen_option('per_page', array('label' => __('Strings translations', 'polylang'), 'default' => 10, 'option' => 'pll_strings_per_page'));
28 }
29
30 // used to update the translation when a language slug has been modified
31 function update_translations($type, $ids, $old_slug) {
32 foreach ($ids as $id) {
33 $tr = $this->get_translations($type, $id);
34 if ($tr) {
35 $tr[$_POST['slug']] = $tr[$old_slug];
36 unset($tr[$old_slug]);
37 update_metadata($type, (int) $id, '_translations', $tr);
38 }
39 }
40 }
41
42 // used to delete the translation when a language is deleted
43 function delete_translations($type, $ids, $old_slug) {
44 foreach ($ids as $id) {
45 $tr = $this->get_translations($type, $id);
46 if ($tr) {
47 unset($tr[$old_slug]);
48 update_metadata($type, (int) $id, '_translations', $tr);
49 }
50 }
51 }
52
53 // the languages panel
54 function languages_page() {
55 $options = get_option('polylang');
56
57 // for nav menus form
58 $locations = get_registered_nav_menus();
59 $menus = wp_get_nav_menus();
60 $menu_lang = get_option('polylang_nav_menus');
61
62 // for widgets
63 $widget_lang = get_option('polylang_widgets', array()); // returns empty array if not set yet
64
65 $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
66
67 switch ($action) {
68 case 'add':
69 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
70 $error = $this->validate_lang();
71
72 if ($error == 0) {
73 $r = wp_insert_term($_POST['name'],'language', array('slug'=>$_POST['slug'], 'description'=>$_POST['description']));
74 wp_update_term($r['term_id'], 'language', array('term_group'=>$_POST['term_group'])); // can't set the term group directly in wp_insert_term
75 update_metadata('term', $r['term_id'], '_rtl', $_POST['rtl']);
76
77 if (!isset($options['default_lang'])) { // if this is the first language created, set it as default language
78 $options['default_lang'] = $_POST['slug'];
79 update_option('polylang', $options);
80 }
81
82 flush_rewrite_rules(); // refresh rewrite rules
83
84 if (!$this->download_mo($_POST['description']))
85 $error = 5;
86 }
87
88 wp_redirect('admin.php?page=mlang'. ($error ? '&error='.$error : '') ); // to refresh the page (possible thanks to the $_GET['noheader']=true)
89 exit;
90 break;
91
92 case 'delete':
93 check_admin_referer('delete-lang');
94
95 if (isset($_GET['lang']) && $_GET['lang']) {
96 $lang_id = (int) $_GET['lang'];
97 $lang = $this->get_language($lang_id);
98 $lang_slug = $lang->slug;
99
100 // update the language slug in posts meta
101 $posts = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'meta_key'=>'_translations', 'post_type'=>'any', 'post_status'=>'any'));
102 $this->delete_translations('post', $posts, $lang_slug);
103
104 // update the language slug in categories & post tags meta
105 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
106 $this->delete_translations('term', $terms, $lang_slug);
107
108 // FIXME should find something more efficient (with a sql query ?)
109 foreach ($terms as $id) {
110 if (($lg = $this->get_term_language($id)) && $lg->term_id == $lang_id)
111 $this->delete_term_language($id); // delete language of this term
112 }
113
114 // delete menus locations
115 foreach ($locations as $location => $description) {
116 if (isset($menu_lang[$location][$lang_slug]))
117 unset($menu_lang[$location][$lang_slug]);
118 }
119 update_option('polylang_nav_menus', $menu_lang);
120
121 // delete language option in widgets
122 foreach ($widget_lang as $key=>$slug) {
123 if ($slug == $lang_slug)
124 unset ($widget_lang[$key]);
125 }
126 update_option('polylang_widgets', $widget_lang);
127
128 // delete users options
129 foreach (get_users(array('fields' => 'ID')) as $user_id) {
130 delete_user_meta($user_id, 'user_lang', $lang->description);
131 delete_user_meta($user_id, 'pll_filter_content', $lang_slug);
132 delete_user_meta($user_id, 'description_'.$lang_slug);
133 }
134
135 // delete the string translations
136 delete_option('polylang_mo'.$lang_id);
137
138 // delete the language itself
139 delete_metadata('term', $lang_id, '_rtl');
140 wp_delete_term($lang_id, 'language');
141
142 // oops ! we deleted the default language...
143 if ($options['default_lang'] == $lang_slug) {
144 if ($listlanguages = $this->get_languages_list())
145 $options['default_lang'] = $listlanguages[0]->slug; // arbitrary choice...
146 else
147 unset($options['default_lang']);
148 update_option('polylang', $options);
149 }
150
151 flush_rewrite_rules(); // refresh rewrite rules
152 }
153 wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
154 exit;
155 break;
156
157 case 'edit':
158 if (isset($_GET['lang']) && $_GET['lang']) {
159 $edit_lang = $this->get_language((int) $_GET['lang']);
160 $rtl = get_metadata('term', $edit_lang->term_id, '_rtl', true);
161 }
162 break;
163
164 case 'update':
165 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
166 $lang_id = (int) $_POST['lang_id'];
167 $lang = $this->get_language($lang_id);
168 $error = $this->validate_lang($lang);
169
170 if ($error == 0) {
171 // Update links to this language in posts and terms in case the slug has been modified
172 $old_slug = $lang->slug;
173
174 if ($old_slug != $_POST['slug']) {
175 // update the language slug in posts meta
176 $posts = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'meta_key'=>'_translations', 'post_type'=>'any', 'post_status'=>'any'));
177 $this->update_translations('post', $posts, $old_slug);
178
179 // update the language slug in categories & post tags meta
180 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
181 $this->update_translations('term', $terms, $old_slug);
182
183 // update menus locations
184 foreach ($locations as $location => $description) {
185 if (isset($menu_lang[$location][$old_slug])) {
186 $menu_lang[$location][$_POST['slug']] = $menu_lang[$location][$old_slug];
187 unset($menu_lang[$location][$old_slug]);
188 }
189 }
190 update_option('polylang_nav_menus', $menu_lang);
191
192 // update language option in widgets
193 foreach ($widget_lang as $key=>$lang) {
194 if ($lang == $old_slug)
195 $widget_lang[$key] = $_POST['slug'];
196 }
197 update_option('polylang_widgets', $widget_lang);
198
199 // update the default language option if necessary
200 if ($options['default_lang'] == $old_slug) {
201 $options['default_lang'] = $_POST['slug'];
202 update_option('polylang', $options);
203 }
204 }
205
206 // and finally update the language itself
207 $args = array('name'=>$_POST['name'], 'slug'=>$_POST['slug'], 'description'=>$_POST['description'], 'term_group'=>$_POST['term_group']);
208 wp_update_term($lang_id, 'language', $args);
209 update_metadata('term', $lang_id, '_rtl', $_POST['rtl']);
210
211 flush_rewrite_rules(); // refresh rewrite rules
212 }
213
214 wp_redirect('admin.php?page=mlang'. ($error ? '&error='.$error : '') ); // to refresh the page (possible thanks to the $_GET['noheader']=true)
215 exit;
216 break;
217
218 case 'nav-menus':
219 check_admin_referer( 'nav-menus-lang', '_wpnonce_nav-menus-lang' );
220
221 $menu_lang = $_POST['menu-lang'];
222 foreach ($locations as $location => $description)
223 foreach ($this->get_switcher_options('menu') as $key => $str)
224 $menu_lang[$location][$key] = isset($menu_lang[$location][$key]) ? 1 : 0;
225
226 update_option('polylang_nav_menus', $menu_lang);
227 break;
228
229 case 'string-translation':
230 check_admin_referer( 'string-translation', '_wpnonce_string-translation' );
231
232 $strings = $this->get_strings();
233
234 foreach ($this->get_languages_list() as $language) {
235 $mo = $this->mo_import($language);
236
237 foreach ($_POST['translation'][$language->name] as $key=>$translation) {
238 $mo->add_entry($mo->make_entry($strings[$key]['string'], stripslashes($translation)));
239 }
240 $mo->add_entry($mo->make_entry('', '')); // empty string translation, just in case
241
242 // clean database
243 if (isset($_POST['clean']) && $_POST['clean']) {
244 $new_mo = new MO();
245 foreach ($strings as $string)
246 $new_mo->add_entry($mo->make_entry($string['string'], $mo->translate($string['string'])));
247 }
248 $this->mo_export(isset($new_mo) ? $new_mo : $mo, $language);
249 }
250
251 // to refresh the page (possible thanks to the $_GET['noheader']=true)
252 wp_redirect('admin.php?page=mlang&tab=strings'.(isset($_GET['paged']) ? '&paged='.$_GET['paged'] : ''));
253 exit;
254 break;
255
256 case 'options':
257 check_admin_referer( 'options-lang', '_wpnonce_options-lang' );
258
259 $options['default_lang'] = $_POST['default_lang'];
260 if (isset($_POST['force_lang']))
261 $options['force_lang'] = $_POST['force_lang'];
262 if (isset($_POST['rewrite']))
263 $options['rewrite'] = $_POST['rewrite'];
264
265 foreach (array('browser', 'hide_default', 'redirect_lang', 'sync') as $key)
266 $options[$key] = isset($_POST[$key]) ? 1 : 0;
267
268 update_option('polylang', $options);
269
270 // refresh rewrite rules in case rewrite or hide_default options have been modified
271 // it seems useless to refresh permastruct here
272 flush_rewrite_rules();
273
274 // fills existing posts & terms with default language
275 if (isset($_POST['fill_languages']) && $nolang = $this->get_objects_with_no_lang()) {
276 global $wpdb;
277 $lang = $this->get_language($options['default_lang']);
278
279 $values = array();
280 foreach ($nolang['posts'] as $post_id)
281 $values[] = $wpdb->prepare("(%d, %d)", $post_id, $lang->term_taxonomy_id);
282
283 if ($values) {
284 $wpdb->query("INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id) VALUES " . implode(',', $values));
285 wp_update_term_count($lang->term_taxonomy_id, 'language'); // updating term count is mandatory (thanks to AndyDeGroo)
286 }
287
288 $values = array();
289 foreach ($nolang['terms'] as $term_id)
290 $values[] = $wpdb->prepare("(%d, %s, %d)", $term_id, '_language', $lang->term_id);
291
292 if ($values)
293 $wpdb->query("INSERT INTO $wpdb->termmeta (term_id, meta_key, meta_value) VALUES " . implode(',', $values));
294
295 }
296 wp_redirect('admin.php?page=mlang&tab=settings');
297 exit;
298 break;
299
300 default:
301 break;
302 }
303
304 // prepare the list of tabs
305 $tabs = array('lang' => __('Languages','polylang'));
306
307 // only if at least one language has been created
308 if ($listlanguages = $this->get_languages_list()) {
309 if (current_theme_supports('menus'))
310 $tabs['menus'] = __('Menus','polylang'); // don't display the menu tab if the active theme does not support nav menus
311
312 $tabs['strings'] = __('Strings translation','polylang');
313 $tabs['settings'] = __('Settings', 'polylang');
314 }
315
316 $active_tab = isset($_GET['tab']) && $_GET['tab'] ? $_GET['tab'] : 'lang';
317
318 switch($active_tab) {
319 case 'lang':
320 // prepare the list table of languages
321 $data = array();
322 foreach ($listlanguages as $lang)
323 $data[] = array_merge( (array) $lang, array('flag' => $this->get_flag($lang)) ) ;
324
325 $list_table = new Polylang_List_Table();
326 $list_table->prepare_items($data);
327
328 if (!$action)
329 $rtl = 0;
330
331 // error messages for data validation
332 $errors[1] = __('Enter a valid WorPress locale', 'polylang');
333 $errors[2] = __('The language code must be 2 characters long', 'polylang');
334 $errors[3] = __('The language code must be unique', 'polylang');
335 $errors[4] = __('The language must have a name', 'polylang');
336 $errors[5] = __('The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang');
337 break;
338
339 case 'menus':
340 // default values
341 foreach ($locations as $key=>$location)
342 if (isset($menu_lang[$key]))
343 $menu_lang[$key] = wp_parse_args($menu_lang[$key], $this->get_switcher_options('menu', 'default'));
344 break;
345
346 case 'strings':
347 // get the strings to translate
348 $data = $this->get_strings();
349
350 // load translations
351 foreach ($listlanguages as $language) {
352 // filters by language if requested
353 if (($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) && $language->slug != $lg)
354 continue;
355
356 $mo = $this->mo_import($language);
357 foreach ($data as $key=>$row) {
358 $data[$key]['translations'][$language->name] = $mo->translate($data[$key]['string']);
359 $data[$key]['row'] = $key; // store the row number for convenience
360 }
361 }
362
363 $string_table = new Polylang_String_Table();
364 $string_table->prepare_items($data);
365 break;
366
367 default:
368 break;
369 }
370 // displays the page
371 include(PLL_INC.'/languages-form.php');
372 }
373
374 // validates data entered when creating or updating a language
375 function validate_lang($lang = null) {
376 // validate locale
377 $loc = $_POST['description'];
378 if ( !preg_match('#^[a-z]{2,3}$#', $loc) && !preg_match('#^[a-z]{2,3}_[A-Z]{2,3}$#', $loc) )
379 $error = 1;
380
381 // validate slug length
382 if (!preg_match('#^[a-z]{2,3}$#', $_POST['slug']))
383 $error = 2;
384
385 // validate slug is unique
386 if ($this->get_language($_POST['slug']) && ( $lang === null || (isset($lang) && $lang->slug != $_POST['slug'])))
387 $error = 3;
388
389 // validate name
390 if ($_POST['name'] == '')
391 $error = 4;
392
393 return isset($error) ? $error : 0;
394 }
395
396 // returns unstranslated posts and terms ids
397 function get_objects_with_no_lang() {
398 $posts = get_posts(array(
399 'numberposts'=> -1,
400 'post_type' => $this->post_types,
401 'post_status'=> 'any',
402 'fields' => 'ids',
403 'tax_query' => array(array(
404 'taxonomy'=> 'language',
405 'terms'=> get_terms('language', array('fields'=>'ids')),
406 'operator'=> 'NOT IN'
407 ))
408 ));
409
410 global $wpdb;
411 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
412 $tr_terms = $wpdb->get_col("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '_language'");
413 $terms = array_unique(array_diff($terms, $tr_terms)); // array_unique to avoid duplicates if a term is in more than one taxonomy
414
415 return apply_filters('pll_get_objects_with_no_lang', empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms));
416 }
417
418 function &get_strings() {
419 global $wp_registered_widgets;
420
421 // WP strings
422 $this->register_string(__('Site Title'), get_option('blogname'));
423 $this->register_string(__('Tagline'), get_option('blogdescription'));
424 $this->register_string(__('Date Format'), get_option('date_format'));
425 $this->register_string(__('Time Format'), get_option('time_format'));
426
427 // widgets titles
428 $sidebars = wp_get_sidebars_widgets();
429 foreach ($sidebars as $sidebar => $widgets) {
430 if ($sidebar == 'wp_inactive_widgets' || !isset($widgets))
431 continue;
432
433 foreach ($widgets as $widget) {
434 // nothing can be done if the widget is created using pre WP2.8 API :(
435 // there is no object, so we can't access it to get the widget options
436 // the second part of the test is probably useless
437 if (!isset($wp_registered_widgets[$widget]['callback'][0]) || !is_object($wp_registered_widgets[$widget]['callback'][0]))
438 continue;
439
440 $widget_settings = $wp_registered_widgets[$widget]['callback'][0]->get_settings();
441 $number = $wp_registered_widgets[$widget]['params'][0]['number'];
442 if (isset($widget_settings[$number]['title']) && $title = $widget_settings[$number]['title'])
443 $this->register_string(__('Widget title', 'polylang'), $title);
444 }
445 }
446 return $this->strings;
447 }
448
449 } // class Polylang_Admin
450
451 ?>
452