PluginProbe
Polylang / 0.8.3
Polylang v0.8.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.8.3, at include/admin.php

420 lines 14.2 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=>$lang) {
110 if ($lang == $lang_slug)
111 unset ($widget_lang[$key]);
112 }
113 update_option('polylang_widgets', $widget_lang);
114
115 // delete the string translations
116 delete_option('polylang_mo'.$lang_id);
117
118 // delete the language itself
119 delete_metadata('term', $lang_id, '_rtl');
120 wp_delete_term($lang_id, 'language');
121
122 // oops ! we deleted the default language...
123 if ($options['default_lang'] == $lang_slug) {
124 if ($listlanguages = $this->get_languages_list())
125 $options['default_lang'] = $listlanguages[0]->slug; // arbitrary choice...
126 else
127 unset($options['default_lang']);
128 update_option('polylang', $options);
129
130 flush_rewrite_rules(); // refresh rewrite rules
131 }
132 }
133 wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
134 exit;
135 break;
136
137 case 'edit':
138 if (isset($_GET['lang']) && $_GET['lang']) {
139 $edit_lang = $this->get_language((int) $_GET['lang']);
140 $rtl = get_metadata('term', $edit_lang->term_id, '_rtl', true);
141 }
142 break;
143
144 case 'update':
145 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
146 $lang_id = (int) $_POST['lang_id'];
147 $lang = $this->get_language($lang_id);
148 $error = $this->validate_lang($lang);
149
150 if ($error == 0) {
151 // Update links to this language in posts and terms in case the slug has been modified
152 $old_slug = $lang->slug;
153
154 if ($old_slug != $_POST['slug']) {
155 // update the language slug in posts meta
156 $posts = get_posts(array('numberposts'=>-1, 'fields' => 'ids', 'meta_key'=>'_translations', 'post_type'=>'any', 'post_status'=>'any'));
157 $this->update_translations('post', $posts, $old_slug);
158
159 // update the language slug in categories & post tags meta
160 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
161 $this->update_translations('term', $terms, $old_slug);
162
163 // update menus locations
164 foreach ($locations as $location => $description) {
165 if (isset($menu_lang[$location][$old_slug])) {
166 $menu_lang[$location][$_POST['slug']] = $menu_lang[$location][$old_slug];
167 unset($menu_lang[$location][$old_slug]);
168 }
169 }
170 update_option('polylang_nav_menus', $menu_lang);
171
172 // update language option in widgets
173 foreach ($widget_lang as $key=>$lang) {
174 if ($lang == $old_slug)
175 $widget_lang[$key] = $_POST['slug'];
176 }
177 update_option('polylang_widgets', $widget_lang);
178
179 // update the default language option if necessary
180 if ($options['default_lang'] == $old_slug) {
181 $options['default_lang'] = $_POST['slug'];
182 update_option('polylang', $options);
183 }
184 }
185
186 // and finally update the language itself
187 $args = array('name'=>$_POST['name'], 'slug'=>$_POST['slug'], 'description'=>$_POST['description'], 'term_group'=>$_POST['term_group']);
188 wp_update_term($lang_id, 'language', $args);
189 update_metadata('term', $lang_id, '_rtl', $_POST['rtl']);
190
191 flush_rewrite_rules(); // refresh rewrite rules
192 }
193
194 wp_redirect('admin.php?page=mlang'. ($error ? '&error='.$error : '') ); // to refresh the page (possible thanks to the $_GET['noheader']=true)
195 exit;
196 break;
197
198 case 'nav-menus':
199 check_admin_referer( 'nav-menus-lang', '_wpnonce_nav-menus-lang' );
200
201 $menu_lang = $_POST['menu-lang'];
202 foreach ($locations as $location => $description)
203 foreach ($this->get_switcher_options('menu') as $key => $str)
204 $menu_lang[$location][$key] = isset($menu_lang[$location][$key]) ? 1 : 0;
205
206 update_option('polylang_nav_menus', $menu_lang);
207 break;
208
209 case 'string-translation':
210 check_admin_referer( 'string-translation', '_wpnonce_string-translation' );
211
212 $strings = $this->get_strings();
213
214 foreach ($this->get_languages_list() as $language) {
215 $mo = $this->mo_import($language);
216
217 foreach ($_POST['translation'][$language->name] as $key=>$translation) {
218 $mo->add_entry($mo->make_entry($strings[$key]['string'], stripslashes($translation)));
219 }
220 // FIXME should I clean the mo object to remove unused strings ?
221 $this->mo_export($mo, $language);
222 }
223
224 $paged = isset($_GET['paged']) ? '&paged='.$_GET['paged'] : '';
225 wp_redirect('admin.php?page=mlang&tab=strings'.$paged); // to refresh the page (possible thanks to the $_GET['noheader']=true)
226 exit;
227 break;
228
229 case 'options':
230 check_admin_referer( 'options-lang', '_wpnonce_options-lang' );
231
232 $options['default_lang'] = $_POST['default_lang'];
233 $options['rewrite'] = $_POST['rewrite'];
234 foreach (array('browser', 'hide_default', 'force_lang', 'redirect_lang') as $key)
235 $options[$key] = isset($_POST[$key]) ? 1 : 0;
236
237 update_option('polylang', $options);
238
239 // refresh rewrite rules in case rewrite or hide_default options have been modified
240 // it seems useless to refresh permastruct here
241 flush_rewrite_rules();
242
243 // fills existing posts & terms with default language
244 if (isset($_POST['fill_languages'])) {
245 global $wpdb;
246 $untranslated = $this->get_untranslated();
247 $lang = $this->get_language($options['default_lang']);
248
249 $values = array();
250 foreach ($untranslated['posts'] as $post_id)
251 $values[] = $wpdb->prepare("(%d, %d)", $post_id, $lang->term_taxonomy_id);
252
253 if ($values) {
254 $wpdb->query("INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id) VALUES " . implode(',', $values));
255 wp_update_term_count($lang->term_taxonomy_id, 'language'); // updating term count is mandatory (thanks to AndyDeGroo)
256 }
257
258 $values = array();
259 foreach ($untranslated['terms'] as $term_id)
260 $values[] = $wpdb->prepare("(%d, %s, %d)", $term_id, '_language', $lang->term_id);
261
262 if ($values)
263 $wpdb->query("INSERT INTO $wpdb->termmeta (term_id, meta_key, meta_value) VALUES " . implode(',', $values));
264 }
265 break;
266
267 default:
268 break;
269 }
270
271 // prepare the list of tabs
272 $tabs = array('lang' => __('Languages','polylang'));
273
274 // only if at least one language has been created
275 if ($listlanguages = $this->get_languages_list()) {
276 if (current_theme_supports('menus'))
277 $tabs['menus'] = __('Menus','polylang'); // don't display the menu tab if the active theme does not support nav menus
278
279 $tabs['strings'] = __('Strings translation','polylang');
280 $tabs['settings'] = __('Settings', 'polylang');
281 }
282
283 $active_tab = isset($_GET['tab']) && $_GET['tab'] ? $_GET['tab'] : 'lang';
284
285 switch($active_tab) {
286 case 'lang':
287 // prepare the list table of languages
288 $data = array();
289 foreach ($listlanguages as $lang)
290 $data[] = array_merge( (array) $lang, array('flag' => $this->get_flag($lang)) ) ;
291
292 $list_table = new Polylang_List_Table();
293 $list_table->prepare_items($data);
294
295 $rtl = 0;
296
297 // error messages for data validation
298 $errors[1] = __('Enter a valid WorPress locale', 'polylang');
299 $errors[2] = __('The language code must be 2 characters long', 'polylang');
300 $errors[3] = __('The language code must be unique', 'polylang');
301 $errors[4] = __('The language must have a name', 'polylang');
302 $errors[5] = __('The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang');
303 break;
304
305 case 'menus':
306 // default values
307 foreach ($locations as $key=>$location) {
308 if (isset($menu_lang[$key]))
309 $menu_lang[$key] = wp_parse_args($menu_lang[$key], $this->get_switcher_options('menu', 'default'));
310 }
311 break;
312
313 case 'strings':
314 // get the strings to translate
315 $data = $this->get_strings();
316
317 // load translations
318 foreach ($listlanguages as $language) {
319 $mo = $this->mo_import($language);
320 foreach ($data as $key=>$row) {
321 $data[$key]['translations'][$language->name] = $mo->translate($data[$key]['string']);
322 $data[$key]['row'] = $key; // store the row number for convenience
323 }
324 }
325
326 $string_table = new Polylang_String_Table();
327 $string_table->prepare_items($data);
328 break;
329
330 case 'settings':
331 // detects posts & pages without language set
332 $untranslated = $this->get_untranslated();
333 break;
334
335 default:
336 break;
337 }
338 // displays the page
339 include(PLL_INC.'/languages-form.php');
340 }
341
342 // validates data entered when creating or updating a language
343 function validate_lang($lang = null) {
344 // validate locale
345 $loc = $_POST['description'];
346 if ( !preg_match('#^[a-z]{2,3}$#', $loc) && !preg_match('#^[a-z]{2,3}_[A-Z]{2,3}$#', $loc) )
347 $error = 1;
348
349 // validate slug length
350 if (!preg_match('#^[a-z]{2,3}$#', $_POST['slug']))
351 $error = 2;
352
353 // validate slug is unique
354 if ($this->get_language($_POST['slug']) != null && ( $lang === null || (isset($lang) && $lang->slug != $_POST['slug'])))
355 $error = 3;
356
357 // validate name
358 if ($_POST['name'] == '')
359 $error = 4;
360
361 return isset($error) ? $error : 0;
362 }
363
364 // returns unstranslated posts and terms ids
365 function get_untranslated() {
366 $posts = get_posts(array(
367 'numberposts'=> -1,
368 'post_type' => $this->post_types,
369 'post_status'=> 'any',
370 'fields' => 'ids',
371 'tax_query' => array(array(
372 'taxonomy'=> 'language',
373 'terms'=> get_terms('language', array('fields'=>'ids')),
374 'operator'=> 'NOT IN'
375 ))
376 ));
377
378 global $wpdb;
379 $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
380 $tr_terms = $wpdb->get_col("SELECT t.term_id FROM $wpdb->terms AS t
381 LEFT JOIN $wpdb->termmeta AS tm ON t.term_id = tm.term_id
382 WHERE tm.meta_key = '_language'");
383 $terms = array_diff($terms, $tr_terms);
384
385 return empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms);
386 }
387
388 function &get_strings() {
389 global $wp_registered_widgets;
390
391 // WP strings
392 $this->register_string(__('Site Title'), get_option('blogname'));
393 $this->register_string(__('Tagline'), get_option('blogdescription'));
394
395 // widgets titles
396 $sidebars = wp_get_sidebars_widgets();
397 foreach ($sidebars as $sidebar => $widgets) {
398 if ($sidebar == 'wp_inactive_widgets' || !isset($widgets))
399 continue;
400
401 foreach ($widgets as $widget) {
402 // nothing can be done if the widget is created using pre WP2.8 API :(
403 // there is no object, so we can't access it to get the widget options
404 // the second part of the test is probably useless
405 if (!isset($wp_registered_widgets[$widget]['callback'][0]) || !is_object($wp_registered_widgets[$widget]['callback'][0]))
406 continue;
407
408 $widget_settings = $wp_registered_widgets[$widget]['callback'][0]->get_settings();
409 $number = $wp_registered_widgets[$widget]['params'][0]['number'];
410 if (isset($widget_settings[$number]['title']) && $title = $widget_settings[$number]['title'])
411 $this->register_string(__('Widget title', 'polylang'), $title);
412 }
413 }
414 return $this->strings;
415 }
416
417 } // class Polylang_Admin
418
419 ?>
420