| 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' => __('— No Change —')))) : |
| 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' => '— '.$taxonomy->labels->parent_item.' —', |
| 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…', '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 |
|