PluginProbe
Polylang / 0.9.3
Polylang v0.9.3
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.3, at include/admin.php

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