PluginProbe
Polylang / 0.9.1
Polylang v0.9.1
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.1, at include/admin.php

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