PluginProbe
Polylang / 1.1
Polylang v1.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-filters.php

admin-filters.php in Polylang 1.1, at include/admin-filters.php

1,136 lines 46.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // all modifications of the WordPress admin ui
4 class Polylang_Admin_Filters extends Polylang_Admin_Base {
5 private $pre_term_name; // used to store the term name before creating a slug if needed
6
7 function __construct() {
8 parent::__construct();
9
10 // additionnal filters and actions
11 add_action('wp_loaded', array(&$this, 'admin_init'), 5);// after Polylang_Base::add_post_types_taxonomie
12
13 // refresh rewrite rules if the 'page_on_front' option is modified
14 add_action('update_option_page_on_front', 'flush_rewrite_rules');
15
16 // adds a 'settings' link in the plugins table
17 add_filter('plugin_action_links_'.basename(POLYLANG_DIR).'/polylang.php', array(&$this, 'plugin_action_links'));
18
19 // ugrades languages files after a core upgrade (timing is important)
20 // FIXME private action ? is there a better way to do this ?
21 add_action( '_core_updated_successfully', array(&$this, 'upgrade_languages'), 1); // since WP 3.3
22 }
23
24 // add these actions and filters here and not in the constructor to be sure that all taxonomies are registered
25 function admin_init() {
26 if (!$this->get_languages_list())
27 return;
28
29 // add the language and translations columns in 'All Posts', 'All Pages' and 'Media library' panels
30 foreach ($this->post_types as $type) {
31 // use the latest filter late as some plugins purely overwrite what's done by others :(
32 // specific case for media
33 add_filter('manage_'. ($type == 'attachment' ? 'upload' : 'edit-'. $type) .'_columns', array(&$this, 'add_post_column'), 100);
34 add_action('manage_'. ($type == 'attachment' ? 'media' : $type .'_posts') .'_custom_column', array(&$this, 'post_column'), 10, 2);
35 }
36
37 // quick edit and bulk edit
38 add_filter('quick_edit_custom_box', array(&$this, 'quick_edit_custom_box'), 10, 2);
39 add_filter('bulk_edit_custom_box', array(&$this, 'quick_edit_custom_box'), 10, 2);
40
41 // filters posts, pages and media by language
42 add_filter('parse_query',array(&$this,'parse_query'));
43
44 // adds the Languages box in the 'Edit Post' and 'Edit Page' panels
45 add_action('add_meta_boxes', array(&$this, 'add_meta_boxes'));
46
47 // ajax response for changing the language in the post metabox
48 add_action('wp_ajax_post_lang_choice', array(&$this,'post_lang_choice'));
49
50 add_action('wp_ajax_polylang-ajax-tag-search', array(&$this,'ajax_tag_search'));
51
52 // filters the pages by language in the parent dropdown list in the page attributes metabox
53 add_filter('page_attributes_dropdown_pages_args', array(&$this, 'page_attributes_dropdown_pages_args'), 10, 2);
54
55 // adds actions and filters related to languages when creating, saving or deleting posts and pages
56 add_filter('wp_insert_post_parent', array(&$this, 'wp_insert_post_parent'));
57 add_action('dbx_post_advanced', array(&$this, 'dbx_post_advanced'));
58 add_action('save_post', array(&$this, 'save_post'), 200, 2); // priority 200 to come after advanced custom fields (20) and custom fields template (100)
59 add_action('before_delete_post', array(&$this, 'delete_post'));
60
61 if ($this->options['media_support']) {
62 // adds the language field and translations tables in the 'Edit Media' panel
63 add_filter('attachment_fields_to_edit', array(&$this, 'attachment_fields_to_edit'), 10, 2);
64
65 // ajax response for changing the language in media form
66 add_action('wp_ajax_media_lang_choice', array(&$this,'media_lang_choice'));
67
68 // adds actions related to languages when creating, saving or deleting media
69 add_action('add_attachment', array(&$this, 'add_attachment'));
70 add_filter('attachment_fields_to_save', array(&$this, 'save_media'), 10, 2);
71 add_action('delete_attachment', array(&$this, 'delete_post'));
72 add_filter('wp_delete_file', array(&$this, 'wp_delete_file'));
73
74 // creates a media translation
75 if (isset($_GET['action']) && $_GET['action'] == 'translate_media' && isset($_GET['new_lang']) && isset($_GET['from_media']))
76 $this->translate_media();
77 }
78
79 // filters categories and post tags by language
80 add_filter('terms_clauses', array(&$this, 'terms_clauses'), 10, 3);
81
82 foreach ($this->taxonomies as $tax) {
83 // adds the language field in the 'Categories' and 'Post Tags' panels
84 add_action($tax.'_add_form_fields', array(&$this, 'add_term_form'));
85
86 // adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
87 add_action($tax.'_edit_form_fields', array(&$this, 'edit_term_form'));
88
89 // adds the language column in the 'Categories' and 'Post Tags' tables
90 add_filter('manage_edit-'.$tax.'_columns', array(&$this, 'add_term_column'));
91 add_action('manage_'.$tax.'_custom_column', array(&$this, 'term_column'), 10, 3);
92
93 // adds action related to languages when deleting categories and post tags
94 add_action('delete_'.$tax, array(&$this, 'delete_term'));
95 }
96
97 // adds actions related to languages when creating or saving categories and post tags
98 add_filter('wp_dropdown_cats', array(&$this, 'wp_dropdown_cats'));
99 add_action('create_term', array(&$this, 'save_term'), 10, 3);
100 add_action('edit_term', array(&$this, 'save_term'), 10, 3);
101 add_filter('pre_term_name', array(&$this, 'pre_term_name'));
102 add_filter('pre_term_slug', array(&$this, 'pre_term_slug'), 10, 2);
103
104 // ajax response for edit term form
105 add_action('wp_ajax_term_lang_choice', array(&$this,'term_lang_choice'));
106
107 // widgets languages filter
108 add_action('in_widget_form', array(&$this, 'in_widget_form'));
109 add_filter('widget_update_callback', array(&$this, 'widget_update_callback'), 10, 4);
110
111 // language management for users
112 add_action('personal_options_update', array(&$this, 'personal_options_update'));
113 add_action('edit_user_profile_update', array(&$this, 'personal_options_update'));
114 add_action('personal_options', array(&$this, 'personal_options'));
115
116 //modifies posts and terms links when needed
117 $this->add_post_term_link_filters();
118
119 // filters comments by language
120 add_filter('comments_clauses', array(&$this, 'comments_clauses'), 10, 2);
121 }
122
123 // adds languages and translations columns in posts, pages, media, categories and tags tables
124 function add_column($columns, $before) {
125 if ($n = array_search($before, array_keys($columns))) {
126 $end = array_slice($columns, $n);
127 $columns = array_slice($columns, 0, $n);
128 }
129
130 foreach ($this->get_languages_list() as $language)
131 // don't add the column for the filtered language
132 if ($language->slug != get_user_meta(get_current_user_id(), 'pll_filter_content', true))
133 $columns['language_'.$language->slug] = ($flag = $this->get_flag($language)) ? $flag : esc_html($language->slug);
134
135 return isset($end) ? array_merge($columns, $end) : $columns;
136 }
137
138 // returns the first language column in the posts, pages and media library tables
139 function get_first_language_column() {
140 foreach ($this->get_languages_list() as $language)
141 if ($language->slug != get_user_meta(get_current_user_id(), 'pll_filter_content', true))
142 $columns[] = 'language_'.$language->slug;
143
144 return reset($columns);
145 }
146
147 // adds the language and translations columns (before the comments column) in the posts, pages and media library tables
148 // test of $columns avoids to add columns (in screen options) in the edit media form which calls the filter too
149 // see get_column_headers in wp-admin/screen.php
150 // FIXME I have the same issue for terms but WP adds columns too
151 function add_post_column($columns) {
152 return $this->add_column($columns, 'comments');
153 }
154
155 // fills the language and translations columns in the posts, pages and media library tables
156 // take care that when doing ajax inline edit, the post may not be updated in database yet
157 // FIXME if inline edit breaks translations, the rows corresponding to these translations are not updated
158 function post_column($column, $post_id) {
159 $inline = defined('DOING_AJAX') && $_REQUEST['action'] == 'inline-save' ? 1 : 0;
160 if (false === strpos($column, 'language_') || !($lang = $inline ? $this->get_language($_POST['post_lang_choice']) : $this->get_post_language($post_id)))
161 return;
162
163 $post_type = isset($GLOBALS['post_type']) ? $GLOBALS['post_type'] : $_POST['post_type']; // 2nd case for quick edit
164 $language = $this->get_language(substr($column, 9));
165
166 // hidden field containing the post language for quick edit
167 if ($column == $this->get_first_language_column())
168 printf('<input type="hidden" name="lang_%d" value="%s" />', esc_attr($post_id), esc_attr($lang->slug));
169
170 // link to edit post (or a translation)
171 if ($id = ($inline && $lang->slug != $_POST['old_lang']) ? ($language->slug == $lang->slug ? $post_id : 0) : $this->get_post($post_id, $language))
172 printf('<a class="%1$s" title="%2$s" href="%3$s"></a>',
173 $id == $post_id ? 'pll_icon_tick' : 'pll_icon_edit',
174 esc_attr(get_post($id)->post_title),
175 esc_url(get_edit_post_link($id, true ))
176 );
177
178 // link to add a new translation
179 else
180 printf('<a class="pll_icon_add" title="%1$s" href="%2$s"></a>',
181 __('Add new translation', 'polylang'),
182 esc_url(admin_url('manage_media_custom_column' == current_filter() ?
183 'admin.php?action=translate_media&from_media=' . $post_id . '&new_lang=' . $language->slug :
184 'post-new.php?post_type=' . $post_type . '&from_post=' . $post_id . '&new_lang=' . $language->slug
185 ))
186 );
187 }
188
189 // quick edit & bulk edit
190 function quick_edit_custom_box($column, $type) {
191 if ($column == $this->get_first_language_column()) {
192 $name = $type == 'edit-tags' ? 'inline_lang_choice' : 'post_lang_choice';
193
194 $args = current_filter() == 'bulk_edit_custom_box' ?
195 array('name' => $name, 'add_options' => array(array('value' => -1, 'text' => __('&mdash; No Change &mdash;')))) :
196 array('name' => $name);
197
198 printf(
199 '<fieldset class="inline-edit-col-left">
200 <div class="inline-edit-col">
201 <input type="hidden" value="" name = "old_lang">' // a hidden field to pass the old language to ajax request
202 .'<label for="%s" class="alignleft">
203 <span class="title">%s</span>
204 %s
205 </label>
206 </div>
207 </fieldset>',
208 $name,
209 __('Language', 'polylang'),
210 $this->dropdown_languages($args)
211 );
212 }
213 return $column;
214 }
215
216 // filters posts, pages and media by language
217 function parse_query($query) {
218 $qvars = &$query->query_vars;
219
220 // do not filter post types such as nav_menu_item
221 if (isset($qvars['post_type']) && !in_array($qvars['post_type'], $this->post_types)) {
222 if (isset($qvars['lang']))
223 unset ($qvars['lang']);
224 return;
225 }
226
227 // filters the list of media by language when uploading from post
228 if ($this->options['media_support'] && ($GLOBALS['pagenow'] == 'media-upload.php' || // WP < 3.5
229 ($GLOBALS['pagenow'] == 'admin-ajax.php' && isset($_REQUEST['action']) && $_REQUEST['action'] == 'query-attachments')) && // WP 3.5+
230 isset($_REQUEST['post_id']) && $lang = $this->get_post_language($_REQUEST['post_id']))
231 $query->set('lang', $lang->slug);
232
233 if (isset($qvars['post_type']) && in_array($qvars['post_type'], $this->post_types) && !isset($qvars['lang']) && $lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true))
234 $qvars['lang'] = $lg;
235
236 if ((isset($qvars['post_type']) && !in_array($qvars['post_type'], $this->post_types)) || (isset($qvars['lang']) && $qvars['lang'] == 'all'))
237 unset ($qvars['lang']);
238 }
239
240 // adds the Language box in the 'Edit Post' and 'Edit Page' panels (as well as in custom post types panels)
241 function add_meta_boxes($post_type) {
242 if (in_array($post_type, $this->post_types))
243 add_meta_box('ml_box', __('Languages','polylang'), array(&$this, 'post_language'), $post_type, 'side', 'high');
244
245 // replace tag metabox by our own
246 foreach (get_object_taxonomies($post_type) as $tax_name) {
247 $taxonomy = get_taxonomy($tax_name);
248 if ($taxonomy->show_ui && !is_taxonomy_hierarchical($tax_name)) {
249 remove_meta_box('tagsdiv-' . $tax_name, null, 'side');
250 add_meta_box('pll-tagsdiv-' . $tax_name, $taxonomy->labels->name, 'post_tags_meta_box', null, 'side', 'core', array('taxonomy' => $tax_name));
251 }
252 }
253 }
254
255 // the Languages metabox in the 'Edit Post' and 'Edit Page' panels
256 function post_language() {
257 global $post_ID;
258 $post_id = $post_ID;
259 $post_type = get_post_type($post_ID);
260
261 $lang = ($lg = $this->get_post_language($post_ID)) ? $lg :
262 (isset($_GET['new_lang']) ? $this->get_language($_GET['new_lang']) :
263 $this->get_preferred_language());
264
265 // NOTE: the class "tags-input" allows to include the field in the autosave $_POST (see autosave.js)
266 printf("<p><em>%s</em></p>\n<p>%s<br /></p>\n<div id='post-translations' class='translations'>",
267 __('Language', 'polylang'),
268 $this->dropdown_languages(array(
269 'name' => $post_type == 'attachment' ? sprintf('attachments[%d][language]', $post_ID) : 'post_lang_choice',
270 'class' => $post_type == 'attachment' ? 'media_lang_choice' : 'tags-input',
271 'selected' => $lang ? $lang->slug : ''
272 ))
273 );
274 if ($lang)
275 include(PLL_INC.'/'.($post_type == 'attachment' ? 'media' : 'post').'-translations.php');
276 echo "</div>\n";
277 }
278
279 // ajax response for changing the language in the post metabox
280 function post_lang_choice() {
281 global $post_ID; // obliged to use the global variable for wp_popular_terms_checklist
282 $post_ID = $_POST['post_id'];
283 $post_type = get_post_type($post_ID);
284 $lang = $this->get_language($_POST['lang']);
285
286 $this->set_post_language($post_ID, $lang); // save language, useful to set the language when uploading media from post
287
288 ob_start();
289 if ($lang)
290 include(PLL_INC.'/post-translations.php');
291 $x = new WP_Ajax_Response(array('what' => 'translations', 'data' => ob_get_contents()));
292 ob_end_clean();
293
294 // categories
295 if (isset($_POST['taxonomies'])) {
296 // not set for pages
297 foreach ($_POST['taxonomies'] as $taxname) {
298 $taxonomy = get_taxonomy($taxname);
299
300 ob_start();
301 $popular_ids = wp_popular_terms_checklist($taxonomy->name);
302 $supplemental['populars'] = ob_get_contents();
303 ob_end_clean();
304
305 ob_start();
306 // use $post_ID to remember ckecked terms in case we come back to the original language
307 wp_terms_checklist( $post_ID, array( 'taxonomy' => $taxonomy->name, 'popular_cats' => $popular_ids ));
308 $supplemental['all'] = ob_get_contents();
309 ob_end_clean();
310
311 $supplemental['dropdown'] = wp_dropdown_categories(array(
312 'taxonomy' => $taxonomy->name,
313 'hide_empty' => 0,
314 'name' => 'new'.$taxonomy->name.'_parent',
315 'orderby' => 'name',
316 'hierarchical' => 1,
317 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;',
318 'echo' => 0
319 ));
320
321 $x->Add(array('what' => 'taxonomy', 'data' => $taxonomy->name, 'supplemental' => $supplemental));
322 }
323 }
324
325 // parent dropdown list (only for hierarchical post types)
326 // $dropdown_args copied from page_attributes_meta_box
327 if (in_array($post_type, get_post_types(array('hierarchical' => true)))) {
328 $post = get_post($post_ID);
329 $dropdown_args = array(
330 'post_type' => $post->post_type,
331 'exclude_tree' => $post->ID,
332 'selected' => $post->post_parent,
333 'name' => 'parent_id',
334 'show_option_none' => __('(no parent)'),
335 'sort_column' => 'menu_order, post_title',
336 'echo' => 0,
337 );
338 $dropdown_args = apply_filters('page_attributes_dropdown_pages_args', $dropdown_args, $post);
339 $x->Add(array('what' => 'pages', 'data' => wp_dropdown_pages($dropdown_args)));
340 }
341
342 $x->send();
343 }
344
345 // replaces ajax tag search of WP to filter tags by language
346 function ajax_tag_search() {
347 global $wpdb;
348
349 if ( isset( $_GET['tax'] ) ) {
350 $taxonomy = sanitize_key( $_GET['tax'] );
351 $tax = get_taxonomy( $taxonomy );
352 if ( ! $tax )
353 die( '0' );
354 if ( ! current_user_can( $tax->cap->assign_terms ) )
355 die( '-1' );
356 } else {
357 die('0');
358 }
359
360 $s = stripslashes( $_GET['q'] );
361
362 if ( false !== strpos( $s, ',' ) ) {
363 $s = explode( ',', $s );
364 $s = $s[count( $s ) - 1];
365 }
366 $s = trim( $s );
367 if ( strlen( $s ) < 2 )
368 die; // require 2 chars for matching
369
370 $lang = $this->get_language($_GET['lang']);
371
372 $results = $wpdb->get_col( $wpdb->prepare(
373 "SELECT t.name FROM $wpdb->term_taxonomy AS tt
374 INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
375 INNER JOIN $wpdb->termmeta AS tm ON tm.term_id = t.term_id
376 WHERE tt.taxonomy = %s AND t.name LIKE (%s) AND tm.meta_key = '_language' AND tm.meta_value = %d",
377 $taxonomy, '%' . like_escape( $s ) . '%', $lang->term_id ) );
378
379 echo join( $results, "\n" );
380 die;
381 }
382
383 // filters the pages by language in the parent dropdown list in the page attributes metabox
384 function page_attributes_dropdown_pages_args($dropdown_args, $post) {
385 $lang = isset($_POST['lang']) ? $this->get_language($_POST['lang']) : $this->get_post_language($post->ID); // ajax or not ?
386 if (!$lang)
387 $lang = $this->get_preferred_language();
388
389 $pages = implode(',', $this->exclude_pages($lang->term_id));
390 $dropdown_args['exclude'] = isset($dropdown_args['exclude']) ? $dropdown_args['exclude'].','.$pages : $pages;
391 return $dropdown_args;
392 }
393
394 // translate post parent if exists when using "Add new" (translation)
395 function wp_insert_post_parent($post_parent) {
396 return isset($_GET['from_post']) && isset($_GET['new_lang']) && ($id = wp_get_post_parent_id($_GET['from_post'])) &&
397 ($parent = $this->get_translation('post', $id, $_GET['new_lang'])) ? $parent : $post_parent;
398 }
399
400 // copy page template, menu order, comment and ping status when using "Add new" (translation)
401 // the hook was probably not intended for that but did not find a better one
402 // copy the meta '_wp_page_template' in save_post is not sufficient (the dropdown list in the metabox is not updated)
403 // We need to set $post->page_template (and so need to wait for the availability of $post)
404 function dbx_post_advanced() {
405 if (isset($_GET['from_post']) && isset($_GET['new_lang'])) {
406 global $post;
407 $post->page_template = get_post_meta($_GET['from_post'], '_wp_page_template', true);
408
409 $from_post = get_post($_GET['from_post']);
410 foreach (array('menu_order', 'comment_status', 'ping_status') as $property)
411 $post->$property = $from_post->$property;
412
413 if (in_array('sticky_posts', $this->options['sync']) && is_sticky($_GET['from_post']))
414 stick_post($post->ID);
415 }
416 }
417
418 // copy or synchronize terms and metas
419 function copy_post_metas($from, $to, $lang, $sync = false) {
420 // copy or synchronize terms
421 if (!$sync || in_array('taxonomies', $this->options['sync'])) {
422 foreach ($this->taxonomies as $tax) {
423 $newterms = array();
424 $terms = get_the_terms($from, $tax);
425 if (is_array($terms)) {
426 foreach ($terms as $term) {
427 if ($term_id = $this->get_translation('term', $term->term_id, $lang))
428 $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
429 }
430 }
431
432 // for some reasons, the user may have untranslated terms in the translation. don't forget them.
433 if ($sync) {
434 $tr_terms = get_the_terms($to, $tax);
435 if (is_array($tr_terms)) {
436 foreach ($tr_terms as $term) {
437 if (!$this->get_translation('term', $term->term_id, $_POST['post_lang_choice']))
438 $newterms[] = (int) $term->term_id;
439 }
440 }
441 }
442
443 if (!empty($newterms) || $sync)
444 wp_set_object_terms($to, $newterms, $tax); // replace terms in translation
445 }
446 }
447
448 // copy or synchronize post formats
449 if (!$sync || in_array('post_format', $this->options['sync']))
450 ($format = get_post_format($from)) ? set_post_format($to, $format) : set_post_format($to, '');
451
452 // copy or synchronize post metas and allow plugins to do the same
453 $metas = get_post_custom($from);
454
455 // get public meta keys (including from translated post in case we just deleted a custom field)
456 if (!$sync || in_array('post_meta', $this->options['sync'])) {
457 foreach ($keys = array_unique(array_merge(array_keys($metas), array_keys(get_post_custom($to)))) as $k => $meta_key)
458 if (is_protected_meta($meta_key))
459 unset ($keys[$k]);
460 }
461
462 // add page template and featured image
463 foreach (array('_wp_page_template', '_thumbnail_id') as $meta)
464 if (!$sync || in_array($meta, $this->options['sync']))
465 $keys[] = $meta;
466
467 $keys = array_unique(apply_filters('pll_copy_post_metas', empty($keys) ? array() : $keys, $sync));
468
469 // and now copy / synchronize
470 foreach ($keys as $key) {
471 delete_post_meta($to, $key); // the synchronization process of multiple values custom fields is easier if we delete all metas first
472 if (isset($metas[$key])) {
473 foreach ($metas[$key] as $value) {
474 // important: always maybe_unserialize value coming from get_post_custom. See codex.
475 // thanks to goncalveshugo http://wordpress.org/support/topic/plugin-polylang-pll_copy_post_meta
476 $value = maybe_unserialize($value);
477 // special case for featured images which can be translated
478 add_post_meta($to, $key, ($key == '_thumbnail_id' && $tr_value = $this->get_translation('post', $value, $lang)) ? $tr_value : $value);
479 }
480 }
481 }
482 }
483
484 // called when a post (or page) is saved, published or updated
485 function save_post($post_id, $post) {
486 global $wpdb;
487
488 // does nothing except on post types which are filterable
489 if (!in_array($post->post_type, $this->post_types))
490 return;
491
492 // bulk edit does not modify the language
493 if (isset($_GET['bulk_edit']) && $_REQUEST['post_lang_choice'] == -1)
494 return;
495
496 if ($id = wp_is_post_revision($post_id))
497 $post_id = $id;
498
499 // save language
500 if (isset($_REQUEST['post_lang_choice'])) {
501 if (($lang = $this->get_post_language($post_id)) && $lang->slug != $_REQUEST['post_lang_choice'])
502 $this->delete_translation('post', $post_id); // in case the language is modified using inline edit
503 $this->set_post_language($post_id, $_REQUEST['post_lang_choice']);
504 }
505
506 elseif (isset($_GET['new_lang']))
507 $this->set_post_language($post_id, $_GET['new_lang']);
508
509 elseif (isset($_REQUEST['action']) && in_array($_REQUEST['action'], array('post-quickpress-save', 'post-quickpress-publish')))
510 $this->set_post_language($post_id, $this->get_preferred_language()); // default language for QuickPress
511
512 elseif ($this->get_post_language($post_id))
513 {} // avoids breaking the language if post is updated outside the edit post page (thanks to Gonçalo Peres)
514
515 else
516 $this->set_post_language($post_id, $this->get_preferred_language());
517
518 // the hook is called when the post is created
519 // let's use it translate terms and copy metas when using "Add new" (translation)
520 if (isset($_GET['from_post']) && isset($_GET['new_lang']))
521 $this->copy_post_metas($_GET['from_post'], $post_id, $_GET['new_lang']);
522
523 if (!isset($_POST['post_lang_choice']))
524 return;
525
526 // make sure we get save terms in the right language (especially tags with same name in different languages)
527 if ($_POST['post_lang_choice']) {
528 foreach ($this->taxonomies as $tax) {
529 $terms = get_the_terms($post_id, $tax);
530 if (is_array($terms)) {
531 $newterms = array();
532 foreach ($terms as $term) {
533 if ($term_id = $this->get_term($term->term_id, $_POST['post_lang_choice']))
534 $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
535 elseif (!is_wp_error($term_info = wp_insert_term($term->name, $tax))) // create the term in the correct language
536 $newterms[] = (int) $term_info['term_id'];
537 }
538 wp_set_object_terms($post_id, $newterms, $tax);
539 }
540 }
541 }
542
543 if (!isset($_POST['post_tr_lang'])) // just in case only one language has been created
544 return;
545
546 // save translations after checking the translated post is in the right language
547 foreach ($_POST['post_tr_lang'] as $lang=>$tr_id)
548 $translations[$lang] = ($tr_id && $this->get_post_language((int) $tr_id)->slug == $lang) ? (int) $tr_id : 0;
549
550 $this->save_translations('post', $post_id, $translations);
551
552 // prepare some synchronizations
553 foreach (array('comment_status', 'ping_status', 'menu_order', 'post_date') as $property)
554 if (in_array($property, $this->options['sync']))
555 $postarr[$property] = $post->$property;
556
557 if (in_array('post_date', $this->options['sync']))
558 $post_arr['post_date_gmt'] = $post->post_date_gmt;
559
560 // synchronise terms and metas in translations
561 foreach ($translations as $lang => $tr_id) {
562 if (!$tr_id)
563 continue;
564
565 // synchronize terms and metas
566 $this->copy_post_metas($post_id, $tr_id, $lang, true);
567
568 // sticky posts
569 if (in_array('sticky_posts', $this->options['sync']))
570 isset($_REQUEST['sticky']) ? stick_post($tr_id) : unstick_post($tr_id);
571
572 // synchronize comment status, ping status, menu order...
573 if (!empty($postarr))
574 $wpdb->update($wpdb->posts, $postarr, array('ID' => $tr_id));
575
576 // FIXME: optimize the 2 db update in 1
577 // post parent
578 // do not udpate the translation parent if the user set a parent with no translation
579 if (in_array('post_parent', $this->options['sync'])) {
580 $post_parent = ($parent_id = wp_get_post_parent_id($post_id)) ? $this->get_translation('post', $parent_id, $lang) : 0;
581 if (!($parent_id && !$post_parent))
582 $wpdb->update($wpdb->posts, array('post_parent'=> $post_parent), array( 'ID' => $tr_id ));
583 }
584 }
585 }
586
587 // called when a post, page or media is deleted
588 // don't delete translations if this is a post revision thanks to AndyDeGroo who catched this bug
589 // http://wordpress.org/support/topic/plugin-polylang-quick-edit-still-breaks-translation-linking-of-pages-in-072
590 function delete_post($post_id) {
591 if (!wp_is_post_revision($post_id))
592 $this->delete_translation('post', $post_id);
593 }
594
595 // adds the language field and translations tables in the 'Edit Media' panel
596 function attachment_fields_to_edit($fields, $post) {
597 if ($GLOBALS['pagenow'] == 'post.php')
598 return $fields; // don't add anything on edit media panel for WP 3.5+ since we have the metabox
599
600 $post_id = $post->ID;
601 $lang = $this->get_post_language($post_id);
602
603 $fields['language'] = array(
604 'label' => __('Language', 'polylang'),
605 'input' => 'html',
606 'html' => $this->dropdown_languages(array(
607 'name' => "attachments[$post_id][language]",
608 'class' => "media_lang_choice",
609 'selected' => $lang ? $lang->slug : ''
610 ))
611 );
612
613 // don't show translations except on edit media panel for WP < 3.5
614 if ($GLOBALS['pagenow'] == 'media.php') {
615 if ($lang) {
616 ob_start();
617 include PLL_INC . '/media-translations.php';
618 $fields['translations'] = array(
619 'label' => __('Translations', 'polylang'),
620 'input' => 'html',
621 'html' => ob_get_contents(),
622 );
623 ob_end_clean();
624 }
625 else
626 $fields['translations'] = array('tr' => '<tr class="translations"></tr>'); // to get a field for ajax
627 }
628
629 return $fields;
630 }
631
632 // ajax response for changing the language in media form
633 function media_lang_choice() {
634 preg_match('#([0-9]+)#', $_POST['post_id'], $matches);
635 $post_id = $matches[1];
636 $lang = $this->get_language($_POST['lang']);
637
638 ob_start();
639 if ($lang) {
640 include(PLL_INC.'/media-translations.php');
641 $data = ob_get_contents();
642
643 // Special case for WP < 3.5, first add the html generated by WP if non AJAX, then our translation table
644 if (version_compare($GLOBALS['wp_version'], '3.5', '<'))
645 $data = sprintf("
646 <th valign='top' scope='row' class='label'>
647 <label for='attachments[%d][translations]'>
648 <span class='alignleft'>%s</span><br class='clear' />
649 </label>
650 </th>
651 <td class='field'>
652 %s
653 </td>",
654 $post_id, __('Translations', 'polylang'), $data
655 );
656 }
657 $x = new WP_Ajax_Response(array('what' => 'translations', 'data' => $data));
658 ob_end_clean();
659
660 $x->send();
661 }
662
663 // creates a media translation
664 function translate_media() {
665 $post = get_post($_GET['from_media']);
666 $post_id = $post->ID;
667
668 // create a new attachment (translate attachment parent if exists)
669 $post->ID = null; // will force the creation
670 $post->post_parent = ($post->post_parent && $tr_parent = $this->get_translation('post', $post->post_parent, $_GET['new_lang'])) ? $tr_parent : 0;
671 $tr_id = wp_insert_attachment($post);
672 add_post_meta($tr_id, '_wp_attachment_metadata', get_post_meta($post_id, '_wp_attachment_metadata', true));
673 add_post_meta($tr_id, '_wp_attached_file', get_post_meta($post_id, '_wp_attached_file', true));
674
675 $translations = $this->get_translations('post', $post_id);
676 if (!$translations && $lang = $this->get_post_language($post_id))
677 $translations[$lang->slug] = $post_id;
678
679 $translations[$_GET['new_lang']] = $tr_id;
680 $this->save_translations('post', $tr_id, $translations);
681
682 wp_redirect(admin_url(sprintf(
683 version_compare($GLOBALS['wp_version'], '3.5', '<') ?
684 'media.php?attachment_id=%d&action=edit' : // WP < 3.5
685 'post.php?post=%d&action=edit', // WP 3.5+
686 $tr_id)));
687
688 exit;
689 }
690
691 // sets the language of a new attachment
692 function add_attachment($post_id) {
693 if (!empty($_GET['new_lang'])) // created as a translation from an existing attachment
694 $lang = $_GET['new_lang'];
695 else {
696 $post = get_post($post_id);
697 if (!empty($post->post_parent)) // upload in the "Add media" modal when editing a post
698 $lang = $this->get_post_language($post->post_parent);
699 }
700
701 $this->set_post_language($post_id, isset($lang) ? $lang : $this->get_preferred_language());
702 }
703
704 // called when a media is saved
705 function save_media($post, $attachment) {
706 $this->set_post_language($post['ID'], $attachment['language']); // FIXME the language is no more automatically saved by WP since WP 3.5
707
708 $this->delete_translation('post', $post['ID']);
709
710 // save translations after checking the translated media is in the right language
711 if (isset($_POST['media_tr_lang'])) {
712 foreach ($_POST['media_tr_lang'] as $lang=>$tr_id)
713 $translations[$lang] = $this->get_post_language((int) $tr_id)->slug == $lang && $tr_id != $post['ID'] ? (int) $tr_id : 0;
714
715 $this->save_translations('post', $post['ID'], $translations);
716 }
717
718 return $post;
719 }
720
721 // prevents WP deleting files when there are still media using them
722 // thanks to Bruno "Aesqe" Babic and its plugin file gallery in which I took all the ideas for this function
723 function wp_delete_file($file) {
724 global $wpdb;
725 $uploadpath = wp_upload_dir();
726 $ids = $wpdb->get_col($wpdb->prepare(
727 "SELECT `post_id` FROM $wpdb->postmeta
728 WHERE `meta_key` = '_wp_attached_file' AND `meta_value` = '%s'",
729 ltrim($file, $uploadpath['basedir'])
730 ));
731
732 if (!empty($ids)) {
733 // regenerate intermediate sizes if it's an image (since we could not prevent WP deleting them before)
734 wp_update_attachment_metadata($ids[0], wp_generate_attachment_metadata($ids[0], $file));
735 return ''; // prevent deleting the main file
736 }
737
738 return $file;
739 }
740
741 // filters categories and post tags by language when needed
742 function terms_clauses($clauses, $taxonomies, $args) {
743 // does nothing except on taxonomies which are filterable
744 foreach ($taxonomies as $tax)
745 if (!in_array($tax, $this->taxonomies))
746 return $clauses;
747
748
749 // if get_terms is queried with a 'lang' parameter
750 if (!empty($args['lang']))
751 return $this->_terms_clauses($clauses, $args['lang']);
752
753 if (function_exists('get_current_screen'))
754 $screen = get_current_screen(); // since WP 3.1, may not be available the first time(s) get_terms is called
755
756 // does nothing in Languages and dasboard admin panels
757 if (isset($screen) && in_array($screen->base, array('toplevel_page_mlang', 'dashboard')))
758 return $clauses;
759
760 // FIXME this complex test allows not to filter the 'get_terms_not_translated'
761 // maybe it's more robust to add a new arg to the function in polylang and to test it
762 if (isset($screen) && $screen->base == 'edit-tags' && !isset($args['page']) && $args['fields'] != 'count' && !isset($args['class']) && !$args['hide_empty'])
763 return $clauses;
764
765 // The only ajax response I want to deal with is when changing the language in post metabox
766 if (isset($_POST['action']) && $_POST['action'] != 'post_lang_choice' && $_POST['action'] != 'term_lang_choice' && $_POST['action'] != 'get-tagcloud')
767 return $clauses;
768
769 // I only want to filter the parent dropdown list when editing a term in a hierarchical taxonomy
770 if (isset($_POST['action']) && $_POST['action'] == 'term_lang_choice' && !(isset($args['class']) || isset($args['unit'])))
771 return $clauses;
772
773 // ajax response for changing the language in the post metabox (or in the edit-tags panels)
774 if (isset($_POST['lang']))
775 $lang = $this->get_language($_POST['lang']);
776
777 // the post is created with the 'add new' (translation) link
778 elseif (!empty($_GET['new_lang']))
779 $lang = $this->get_language($_GET['new_lang']);
780
781 // the language filter selection has just changed
782 // test $screen->base to avoid interference between the language filter and the post language selection and the category parent dropdown list
783 elseif (!empty($_GET['lang']) && !in_array($screen->base, array('post', 'edit-tags'))) {
784 if ($_GET['lang'] != 'all')
785 $lang = $this->get_language($_GET['lang']);
786 elseif ($screen->base == 'edit-tags' && isset($args['class']))
787 $lang = $this->get_preferred_language(); // parent dropdown
788 }
789
790 // again the language filter
791 elseif (($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) &&
792 $screen->base != 'post' && !($screen->base == 'edit-tags' && isset($args['class']))) // don't apply to post edit and the category parent dropdown list
793 $lang = $this->get_language($lg);
794
795 elseif (isset($_GET['post']))
796 $lang = $this->get_post_language($_GET['post']);
797
798 // for the parent dropdown list in edit term
799 elseif (isset($_GET['tag_ID']))
800 $lang = $this->get_term_language($_GET['tag_ID']);
801
802 // when a new category is created in the edit post panel
803 elseif (isset($_POST['term_lang_choice']))
804 $lang = $this->get_language($_POST['term_lang_choice']);
805
806 // for a new post (or the parent dropdown list of a new term)
807 elseif (isset($screen) && ($screen->base == 'post' || ($screen->base == 'edit-tags' && isset($args['class']))))
808 $lang = $this->get_preferred_language();
809
810 // adds our clauses to filter by current language
811 return !empty($lang) ? $this->_terms_clauses($clauses, $lang) : $clauses;
812 }
813
814 // adds the language field in the 'Categories' and 'Post Tags' panels
815 function add_term_form() {
816 $taxonomy = $_GET['taxonomy'];
817 $lang = isset($_GET['new_lang']) ? $this->get_language($_GET['new_lang']) : $this->get_preferred_language();
818
819 printf("<div class='form-field'><label for='term_lang_choice'>%s</label>\n%s<p>%s</p>\n</div>",
820 __('Language', 'polylang'),
821 $this->dropdown_languages(array('name' => 'term_lang_choice', 'value' => 'term_id', 'selected' => $lang ? $lang->term_id : '')),
822 __('Sets the language', 'polylang')
823 );
824
825 // adds translation fields
826 echo "<div id='term-translations' class='form-field'>";
827 if ($lang)
828 include(PLL_INC.'/term-translations.php');
829 echo "</div>\n";
830 }
831
832 // adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
833 function edit_term_form($tag) {
834 $term_id = $tag->term_id;
835 $lang = $this->get_term_language($term_id);
836 $taxonomy = $tag->taxonomy;
837
838 printf("<tr class='form-field'><th scope='row' valign='top'><label for='term_lang_choice'>%s</label></th>", __('Language', 'polylang'));
839 printf("<td>%s<br /><span class='description'>%s</span></td></tr>",
840 $this->dropdown_languages(array('name' => 'term_lang_choice', 'value' => 'term_id', 'selected' => $lang ? $lang->term_id : '')),
841 __('Sets the language', 'polylang')
842 );
843
844 echo "<tr id='term-translations' class='form-field'>";
845 if ($lang)
846 include(PLL_INC.'/term-translations.php');
847 echo "</tr>\n";
848 }
849
850 // adds the language column (before the posts column) in the 'Categories' or 'Post Tags' table
851 function add_term_column($columns) {
852 return $this->add_column($columns, 'posts');
853 }
854
855 // fills the language column in the 'Categories' or 'Post Tags' table
856 // FIXME if inline edit breaks translations, the rows corresponding to these translations are not updated
857 function term_column($empty, $column, $term_id) {
858 $inline = defined('DOING_AJAX') && $_REQUEST['action'] == 'inline-save-tax' ? 1 : 0;
859 if (false === strpos($column, 'language_') || !($lang = $inline ? $this->get_language($_POST['inline_lang_choice']) : $this->get_term_language($term_id)))
860 return;
861
862 $post_type = isset($GLOBALS['post_type']) ? $GLOBALS['post_type'] : $_POST['post_type']; // 2nd case for quick edit
863 $taxonomy = isset($GLOBALS['taxonomy']) ? $GLOBALS['taxonomy'] : $_POST['taxonomy'];
864 $language = $this->get_language(substr($column, 9));
865
866 if ($column == $this->get_first_language_column())
867 printf('<input type="hidden" name="lang_%d" value="%s" />', $term_id, esc_attr($lang->slug));
868
869 // link to edit term (or a translation)
870 if ($id = ($inline && $lang->slug != $_POST['old_lang']) ? ($language->slug == $lang->slug ? $term_id : 0) : $this->get_term($term_id, $language))
871 printf('<a class="%1$s" title="%2$s" href="%3$s"></a>',
872 $id == $term_id ? 'pll_icon_tick' : 'pll_icon_edit',
873 esc_attr(get_term($id, $taxonomy)->name),
874 esc_url(get_edit_term_link($id, $taxonomy, $post_type))
875 );
876
877 // link to add a new translation
878 else
879 printf('<a class="pll_icon_add" title="%1$s" href="%2$s"></a>',
880 __('Add new translation', 'polylang'),
881 esc_url(admin_url(sprintf('edit-tags.php?taxonomy=%1$s&from_tag=%2$d&new_lang=%3$s', $taxonomy, $term_id, $language->slug)))
882 );
883 }
884
885 // translate term parent if exists when using "Add new" (translation)
886 function wp_dropdown_cats($output) {
887 if (isset($_GET['taxonomy']) && isset($_GET['from_tag']) && isset($_GET['new_lang']) && $id = get_term($_GET['from_tag'], $_GET['taxonomy'])->parent) {
888 if ($parent = $this->get_translation('term', $id, $_GET['new_lang']))
889 return str_replace('"'.$parent.'"', '"'.$parent.'" selected="selected"', $output);
890 }
891 return $output;
892 }
893
894 // called when a category or post tag is created or edited
895 function save_term($term_id, $tt_id, $taxonomy) {
896 // does nothing except on taxonomies which are filterable
897 if (!in_array($taxonomy, $this->taxonomies))
898 return;
899
900 // save language
901 if (isset($_POST['term_lang_choice']))
902 $this->set_term_language($term_id, $_POST['term_lang_choice']);
903 if (isset($_POST['inline_lang_choice'])) {
904 // don't use term_lang_choice for quick edit to avoid conflict with the "add term" form
905 if ($this->get_term_language($term_id)->slug != $_POST['inline_lang_choice'])
906 $this->delete_translation('term', $term_id);
907 $this->set_term_language($term_id, $_POST['inline_lang_choice']);
908 }
909 elseif (isset($_POST['post_lang_choice']))
910 $this->set_term_language($term_id, $_POST['post_lang_choice']);
911
912 if (!isset($_POST['term_tr_lang']))
913 return;
914
915 // save translations after checking the translated term is in the right language (as well as cast id to int)
916 foreach ($_POST['term_tr_lang'] as $lang=>$tr_id) {
917 $tr_lang = $this->get_term_language((int) $tr_id);
918 $translations[$lang] = $tr_lang && $tr_lang->slug == $lang ? (int) $tr_id : 0;
919 }
920
921 $this->save_translations('term', $term_id, $translations);
922
923 // synchronize translations of this term in all posts
924
925 // STOP synchronisation if unwanted
926 if (!in_array('taxonomies', $this->options['sync']))
927 return;
928
929 // get all posts associated to this term
930 $posts = get_posts(array(
931 'numberposts' => -1,
932 'nopaging' => true,
933 'post_type' => 'any',
934 'post_status' => 'any',
935 'fields' => 'ids',
936 'tax_query' => array(array(
937 'taxonomy' => $taxonomy,
938 'field' => 'id',
939 'terms' => array_merge(array($term_id), array_values($translations)),
940 ))
941 ));
942
943 // associate translated term to translated post
944 foreach ($this->get_languages_list() as $language) {
945 if ($translated_term = $this->get_term($term_id, $language)) {
946 foreach ($posts as $post_id) {
947 if ($translated_post = $this->get_post($post_id, $language))
948 wp_set_object_terms($translated_post, $translated_term, $taxonomy, true);
949 }
950 }
951 }
952
953 // synchronize parent in translations
954 // calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
955 // but clean_term_cache can be called (efficiently) only one time due to static array which prevents to update the option more than once
956 // this is the reason to use the edit_term filter and not edited_term
957 // take care that $_POST contains the only valid values for the current term
958 foreach ($_POST['term_tr_lang'] as $lang=>$tr_id) {
959 if (!$tr_id)
960 continue;
961
962 if (isset($_POST['parent']) && $_POST['parent'] != -1) // since WP 3.1
963 $term_parent = $this->get_translation('term', $_POST['parent'], $lang);
964
965 global $wpdb;
966 $wpdb->update($wpdb->term_taxonomy,
967 array('parent'=> isset($term_parent) ? $term_parent : 0),
968 array('term_taxonomy_id' => get_term($tr_id, $taxonomy)->term_taxonomy_id));
969 }
970 }
971
972 // stores the term name for use in pre_term_slug
973 function pre_term_name($name) {
974 return $this->pre_term_name = $name;
975 }
976
977 // creates the term slug in case the term already exists in another language
978 function pre_term_slug($slug, $taxonomy) {
979 $name = sanitize_title($this->pre_term_name);
980
981 // if the new term has the same name as a language, we *need* to differentiate the term
982 // see http://core.trac.wordpress.org/ticket/23199
983 if (term_exists($name, 'language') && !term_exists($name, $taxonomy) && (!$slug || $slug == $name))
984 $slug = $name.'-'.$taxonomy; // a convenient slug which may be modified later by the user
985
986 return !$slug && in_array($taxonomy, $this->taxonomies) && term_exists($name, $taxonomy) ?
987 $name.'-'.$this->get_language($_POST['term_lang_choice'])->slug : $slug;
988 }
989
990 // called when a category or post tag is deleted
991 function delete_term($term_id) {
992 $this->delete_term_language($term_id);
993 $this->delete_translation('term', $term_id);
994 }
995
996 // returns all terms in the $taxonomy in the $term_language which have no translation in the $translation_language
997 function get_terms_not_translated($taxonomy, $term_language, $translation_language) {
998 $new_terms = array();
999 foreach (get_terms($taxonomy, 'hide_empty=0') as $term) {
1000 $lang = $this->get_term_language($term->term_id);
1001 if ($lang && $lang->name == $term_language->name && !$this->get_translation('term', $term->term_id, $translation_language))
1002 $new_terms[] = $term;
1003 }
1004 return $new_terms;
1005 }
1006
1007 // ajax response for edit term form
1008 function term_lang_choice() {
1009 $lang = $this->get_language($_POST['lang']);
1010 $term_id = isset($_POST['term_id']) ? $_POST['term_id'] : null;
1011 $taxonomy = $_POST['taxonomy'];
1012
1013 ob_start();
1014 if ($lang)
1015 include(PLL_INC.'/term-translations.php');
1016 $x = new WP_Ajax_Response(array('what' => 'translations', 'data' => ob_get_contents()));
1017 ob_end_clean();
1018
1019 // parent dropdown list (only for hierarchical taxonomies)
1020 // $args copied from edit_tags.php except echo
1021 if (is_taxonomy_hierarchical($taxonomy)) {
1022 $args = array(
1023 'hide_empty' => 0,
1024 'hide_if_empty' => false,
1025 'taxonomy' => $taxonomy,
1026 'name' => 'parent',
1027 'orderby' => 'name',
1028 'hierarchical' => true,
1029 'show_option_none' => __('None'),
1030 'echo' => 0,
1031 );
1032 $x->Add(array('what' => 'parent', 'data' => wp_dropdown_categories($args)));
1033 }
1034
1035 // tag cloud
1036 // tests copied from edit_tags.php
1037 else {
1038 $tax = get_taxonomy($taxonomy);
1039 if (!is_null($tax->labels->popular_items)) {
1040 $args = array('taxonomy' => $taxonomy, 'echo' => false);
1041 if (current_user_can($tax->cap->edit_terms))
1042 $args = array_merge($args, array('link' => 'edit'));
1043
1044 if ($tag_cloud = wp_tag_cloud($args))
1045 $x->Add(array('what' => 'tag_cloud', 'data' => '<h3>'.$tax->labels->popular_items.'</h3>'.$tag_cloud));
1046 }
1047 }
1048
1049 $x->send();
1050 }
1051
1052 // modifies the widgets forms to add our language dropdwown list
1053 function in_widget_form($widget) {
1054 printf('<p><label for="%1$s">%2$s%3$s</label></p>',
1055 esc_attr( $widget->id.'_lang_choice'),
1056 __('The widget is displayed for:', 'polylang'),
1057 $this->dropdown_languages(array(
1058 'name' => $widget->id.'_lang_choice',
1059 'class' => 'tags-input',
1060 'add_options' => array(array('value' => 0, 'text' => __('All languages', 'polylang'))),
1061 'selected' => empty($this->options['widgets'][$widget->id]) ? '' : $this->options['widgets'][$widget->id]
1062 ))
1063 );
1064 }
1065
1066 // called when widget options are saved
1067 function widget_update_callback($instance, $new_instance, $old_instance, $widget) {
1068 $this->options['widgets'][$widget->id] = $_POST[$widget->id.'_lang_choice'];
1069 update_option('polylang', $this->options);
1070 return $instance;
1071 }
1072
1073 // updates language user preference
1074 function personal_options_update($user_id) {
1075 update_user_meta($user_id, 'user_lang', $_POST['user_lang']); // admin language
1076 foreach ($this->get_languages_list() as $lang)
1077 update_user_meta($user_id, 'description_'.$lang->slug, $_POST['description_'.$lang->slug]); // biography translations
1078 }
1079
1080 // form for language user preference
1081 function personal_options($profileuser) {
1082 printf('<tr><th><label for="user_lang">%s</label></th><td>%s</td></tr>',
1083 __('Admin language', 'polylang'),
1084 $this->dropdown_languages(array(
1085 'name' => 'user_lang',
1086 'value' => 'description',
1087 'selected' => get_user_meta($profileuser->ID, 'user_lang', true),
1088 'add_options' => array(array('value' => 0, 'text' => __('Wordpress default', 'polylang')))
1089 ))
1090 );
1091
1092 // hidden informations to modify the biography form with js
1093 foreach ($this->get_languages_list() as $lang)
1094 printf('<input type="hidden" class="biography" name="%s-%s" value="%s" />',
1095 esc_attr($lang->slug),
1096 esc_attr($lang->name),
1097 esc_attr(get_user_meta($profileuser->ID, 'description_'.$lang->slug, true))
1098 );
1099 }
1100
1101 // filters comments by language
1102 function comments_clauses($clauses, $query) {
1103 if (!empty($query->query_vars['lang']))
1104 $lang = $query->query_vars['lang'];
1105
1106 elseif (!empty($_GET['lang']) && $_GET['lang'] != 'all')
1107 $lang = $this->get_language($_GET['lang']);
1108
1109 elseif ($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true))
1110 $lang = $this->get_language($lg);
1111
1112 return empty($lang) ? $clauses : $this->_comments_clauses($clauses, $lang);
1113 }
1114
1115 // adds a 'settings' link in the plugins table
1116 function plugin_action_links($links) {
1117 array_unshift($links, '<a href="admin.php?page=mlang">' . __('Settings', 'polylang') . '</a>');
1118 return $links;
1119 }
1120
1121 // ugrades languages files after a core upgrade
1122 function upgrade_languages($version) {
1123 apply_filters('update_feedback', __('Upgrading language files&#8230;', 'polylang'));
1124 foreach ($this->get_languages_list() as $language)
1125 if ($language->description != $_POST['locale']) // do not (re)update the language files of a localized WordPress
1126 $this->download_mo($language->description, $version);
1127 }
1128
1129 // returns either the user preferred language or the default language
1130 function get_preferred_language() {
1131 $default_language = $this->get_language(($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) ? $lg : $this->options['default_lang']);
1132 return apply_filters('pll_admin_preferred_language', $default_language);
1133 }
1134
1135 } // class Polylang_Admin_Filters
1136