PluginProbe
Polylang / 0.9.2
Polylang v0.9.2
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.2, at include/admin.php

445 lines 15.3 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 break;
292
293 default:
294 break;
295 }
296
297 // prepare the list of tabs
298 $tabs = array('lang' => __('Languages','polylang'));
299
300 // only if at least one language has been created
301 if ($listlanguages = $this->get_languages_list()) {
302 if (current_theme_supports('menus'))
303 $tabs['menus'] = __('Menus','polylang'); // don't display the menu tab if the active theme does not support nav menus
304
305 $tabs['strings'] = __('Strings translation','polylang');
306 $tabs['settings'] = __('Settings', 'polylang');
307 }
308
309 $active_tab = isset($_GET['tab']) && $_GET['tab'] ? $_GET['tab'] : 'lang';
310
311 switch($active_tab) {
312 case 'lang':
313 // prepare the list table of languages
314 $data = array();
315 foreach ($listlanguages as $lang)
316 $data[] = array_merge( (array) $lang, array('flag' => $this->get_flag($lang)) ) ;
317
318 $list_table = new Polylang_List_Table();
319 $list_table->prepare_items($data);
320
321 if (!$action)
322 $rtl = 0;
323
324 // error messages for data validation
325 $errors[1] = __('Enter a valid WorPress locale', 'polylang');
326 $errors[2] = __('The language code must be 2 characters long', 'polylang');
327 $errors[3] = __('The language code must be unique', 'polylang');
328 $errors[4] = __('The language must have a name', 'polylang');
329 $errors[5] = __('The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang');
330 break;
331
332 case 'menus':
333 // default values
334 foreach ($locations as $key=>$location)
335 if (isset($menu_lang[$key]))
336 $menu_lang[$key] = wp_parse_args($menu_lang[$key], $this->get_switcher_options('menu', 'default'));
337 break;
338
339 case 'strings':
340 // get the strings to translate
341 $data = $this->get_strings();
342
343 // load translations
344 foreach ($listlanguages as $language) {
345 // filters by language if requested
346 if (($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) && $language->slug != $lg)
347 continue;
348
349 $mo = $this->mo_import($language);
350 foreach ($data as $key=>$row) {
351 $data[$key]['translations'][$language->name] = $mo->translate($data[$key]['string']);
352 $data[$key]['row'] = $key; // store the row number for convenience
353 }
354 }
355
356 $string_table = new Polylang_String_Table();
357 $string_table->prepare_items($data);
358 break;
359
360 default:
361 break;
362 }
363 // displays the page
364 include(PLL_INC.'/languages-form.php');
365 }
366
367 // validates data entered when creating or updating a language
368 function validate_lang($lang = null) {
369 // validate locale
370 $loc = $_POST['description'];
371 if ( !preg_match('#^[a-z]{2,3}$#', $loc) && !preg_match('#^[a-z]{2,3}_[A-Z]{2,3}$#', $loc) )
372 $error = 1;
373
374 // validate slug length
375 if (!preg_match('#^[a-z]{2,3}$#', $_POST['slug']))
376 $error = 2;
377
378 // validate slug is unique
379 if ($this->get_language($_POST['slug']) && ( $lang === null || (isset($lang) && $lang->slug != $_POST['slug'])))
380 $error = 3;
381
382 // validate name
383 if ($_POST['name'] == '')
384 $error = 4;
385
386 return isset($error) ? $error : 0;
387 }
388
389 // returns unstranslated posts and terms ids
390 function get_objects_with_no_lang() {
391 $posts = get_posts(array(
392 'numberposts'=> -1,
393 'post_type' => $this->post_types,
394 'post_status'=> 'any',
395 'fields' => 'ids',
396 'tax_query' => array(array(
397 'taxonomy'=> 'language',
398 'terms'=> get_terms('language', array('fields'=>'ids')),
399 'operator'=> 'NOT IN'
400 ))
401 ));
402
403 global $wpdb;
404 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
405 $tr_terms = $wpdb->get_col("SELECT t.term_id FROM $wpdb->terms AS t
406 LEFT JOIN $wpdb->termmeta AS tm ON t.term_id = tm.term_id
407 WHERE tm.meta_key = '_language'");
408 $terms = array_diff($terms, $tr_terms);
409
410 return apply_filters('pll_get_objects_with_no_lang', empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms));
411 }
412
413 function &get_strings() {
414 global $wp_registered_widgets;
415
416 // WP strings
417 $this->register_string(__('Site Title'), get_option('blogname'));
418 $this->register_string(__('Tagline'), get_option('blogdescription'));
419
420 // widgets titles
421 $sidebars = wp_get_sidebars_widgets();
422 foreach ($sidebars as $sidebar => $widgets) {
423 if ($sidebar == 'wp_inactive_widgets' || !isset($widgets))
424 continue;
425
426 foreach ($widgets as $widget) {
427 // nothing can be done if the widget is created using pre WP2.8 API :(
428 // there is no object, so we can't access it to get the widget options
429 // the second part of the test is probably useless
430 if (!isset($wp_registered_widgets[$widget]['callback'][0]) || !is_object($wp_registered_widgets[$widget]['callback'][0]))
431 continue;
432
433 $widget_settings = $wp_registered_widgets[$widget]['callback'][0]->get_settings();
434 $number = $wp_registered_widgets[$widget]['params'][0]['number'];
435 if (isset($widget_settings[$number]['title']) && $title = $widget_settings[$number]['title'])
436 $this->register_string(__('Widget title', 'polylang'), $title);
437 }
438 }
439 return $this->strings;
440 }
441
442 } // class Polylang_Admin
443
444 ?>
445