PluginProbe
Polylang / 1.5
Polylang v1.5
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
← All changes | admin/admin-filters-term.php +385 -452 2.81.5 View file →
@@ -1,330 +1,218 @@
1 1 <?php
2 -/**
3 - * @package Polylang
4 - */
5 2
6 -/**
7 - * Manages filters and actions related to terms on admin side
3 +/*
4 + * manages filters and actions related to terms on admin side
8 5 *
9 6 * @since 1.2
10 7 */
11 8 class PLL_Admin_Filters_Term {
12 - public $links, $model, $options, $pref_lang;
13 - protected $pre_term_name; // Used to store the term name before creating a slug if needed
14 - protected $post_id; // Used to store the current post_id when bulk editing posts
9 + public $links, $model, $options, $curlang, $pref_lang;
10 + protected $pre_term_name; // used to store the term name before creating a slug if needed
15 11
16 - /**
17 - * Constructor: setups filters and actions
12 + /*
13 + * constructor: setups filters and actions
18 14 *
19 15 * @param object $polylang
20 16 */
21 - public function __construct( &$polylang ) {
17 + public function __construct(&$polylang) {
22 18 $this->links = &$polylang->links;
23 19 $this->model = &$polylang->model;
24 20 $this->options = &$polylang->options;
21 + $this->curlang = &$polylang->curlang;
25 22 $this->pref_lang = &$polylang->pref_lang;
26 23
27 - foreach ( $this->model->get_translated_taxonomies() as $tax ) {
28 - // Adds the language field in the 'Categories' and 'Post Tags' panels
29 - add_action( $tax . '_add_form_fields', array( $this, 'add_term_form' ) );
24 + foreach ($this->model->get_translated_taxonomies() as $tax) {
25 + // adds the language field in the 'Categories' and 'Post Tags' panels
26 + add_action($tax.'_add_form_fields', array(&$this, 'add_term_form'));
30 27
31 - // Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
32 - add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
28 + // adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
29 + add_action($tax.'_edit_form_fields', array(&$this, 'edit_term_form'));
30 +
31 + // adds action related to languages when deleting categories and post tags
32 + add_action('delete_'.$tax, array(&$this, 'delete_term'));
33 33 }
34 34
35 - // Adds actions related to languages when creating or saving categories and post tags
36 - add_filter( 'wp_dropdown_cats', array( $this, 'wp_dropdown_cats' ) );
37 - add_action( 'create_term', array( $this, 'save_term' ), 900, 3 );
38 - add_action( 'edit_term', array( $this, 'save_term' ), 900, 3 ); // Late as it may conflict with other plugins, see http://wordpress.org/support/topic/polylang-and-wordpress-seo-by-yoast
39 - add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
40 - add_filter( 'pre_term_name', array( $this, 'pre_term_name' ) );
41 - add_filter( 'pre_term_slug', array( $this, 'pre_term_slug' ), 10, 2 );
35 + // adds actions related to languages when creating or saving categories and post tags
36 + add_filter('wp_dropdown_cats', array(&$this, 'wp_dropdown_cats'));
37 + add_filter('pre_insert_term', array(&$this, 'pre_insert_term'), 10, 2);
38 + add_action('create_term', array(&$this, 'save_term'), 10, 3);
39 + add_action('edit_term', array(&$this, 'save_term'), 10, 3);
40 + add_filter('pre_term_name', array(&$this, 'pre_term_name'));
41 + add_filter('pre_term_slug', array(&$this, 'pre_term_slug'), 10, 2);
42 42
43 - // Ajax response for edit term form
44 - add_action( 'wp_ajax_term_lang_choice', array( $this, 'term_lang_choice' ) );
45 - add_action( 'wp_ajax_pll_terms_not_translated', array( $this, 'ajax_terms_not_translated' ) );
43 + // ajax response for edit term form
44 + add_action('wp_ajax_term_lang_choice', array(&$this,'term_lang_choice'));
45 + add_action('wp_ajax_pll_terms_not_translated', array(&$this,'ajax_terms_not_translated'));
46 46
47 - // Allows to get the default categories in all languages
48 - add_filter( 'option_default_category', array( $this, 'option_default_category' ) );
49 - add_action( 'update_option_default_category', array( $this, 'update_option_default_category' ), 10, 2 );
47 + // filters categories and post tags by language
48 + add_filter('terms_clauses', array(&$this, 'terms_clauses'), 10, 3);
50 49
51 - // Updates the translations term ids when splitting a shared term
52 - add_action( 'split_shared_term', array( $this, 'split_shared_term' ), 10, 4 ); // WP 4.2
50 + // backward compatibility WP < 3.7
51 + version_compare($GLOBALS['wp_version'], '3.7', '<') ?
52 + add_action('wp_ajax_polylang-ajax-tag-search', array(&$this,'ajax_tag_search')) :
53 + add_action('wp_ajax_polylang-ajax-tag-search', 'wp_ajax_ajax_tag_search'); // take profit of new filter, cache...
54 +
55 + add_filter('option_default_category', array(&$this, 'option_default_category'));
53 56 }
54 57
55 - /**
56 - * Adds the language field in the 'Categories' and 'Post Tags' panels
58 + /*
59 + * adds the language field in the 'Categories' and 'Post Tags' panels
57 60 *
58 61 * @since 0.1
59 62 */
60 63 public function add_term_form() {
61 - if ( isset( $_GET['taxonomy'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
62 - $taxonomy = sanitize_key( $_GET['taxonomy'] ); // phpcs:ignore WordPress.Security.NonceVerification
63 - }
64 -
65 - if ( isset( $_REQUEST['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
66 - $post_type = sanitize_key( $_REQUEST['post_type'] ); // phpcs:ignore WordPress.Security.NonceVerification
67 - }
68 -
69 - if ( isset( $GLOBALS['post_type'] ) ) {
70 - $post_type = $GLOBALS['post_type'];
71 - }
72 -
73 - if ( empty( $taxonomy ) || ! taxonomy_exists( $taxonomy ) || ! post_type_exists( $post_type ) ) {
74 - return;
75 - }
76 -
77 - $from_term_id = isset( $_GET['from_tag'] ) ? (int) $_GET['from_tag'] : 0; // phpcs:ignore WordPress.Security.NonceVerification
78 -
79 - $lang = isset( $_GET['new_lang'] ) ? $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ) : $this->pref_lang; // phpcs:ignore WordPress.Security.NonceVerification
80 -
64 + $taxonomy = $_GET['taxonomy'];
65 + $post_type = isset($GLOBALS['post_type']) ? $GLOBALS['post_type'] : $_REQUEST['post_type'];
66 + $lang = isset($_GET['new_lang']) ? $this->model->get_language($_GET['new_lang']) : $this->pref_lang;
81 67 $dropdown = new PLL_Walker_Dropdown();
82 68
83 - $dropdown_html = $dropdown->walk(
84 - $this->model->get_languages_list(),
85 - -1,
86 - array(
87 - 'name' => 'term_lang_choice',
88 - 'value' => 'term_id',
89 - 'selected' => $lang ? $lang->term_id : '',
90 - 'flag' => true,
91 - )
92 - );
69 + wp_nonce_field('pll_language', '_pll_nonce');
93 70
94 - wp_nonce_field( 'pll_language', '_pll_nonce' );
95 -
96 - printf(
97 - '<div class="form-field">
71 + printf('
72 + <div class="form-field">
98 73 <label for="term_lang_choice">%s</label>
99 - <div id="select-add-term-language">%s</div>
74 + %s
100 75 <p>%s</p>
101 76 </div>',
102 - esc_html__( 'Language', 'polylang' ),
103 - $dropdown_html, // phpcs:ignore
104 - esc_html__( 'Sets the language', 'polylang' )
77 + __('Language', 'polylang'),
78 + $dropdown->walk($this->model->get_languages_list(), array('name' => 'term_lang_choice', 'value' => 'term_id', 'selected' => $lang ? $lang->term_id : '')),
79 + __('Sets the language', 'polylang')
105 80 );
106 81
107 - if ( ! empty( $from_term_id ) ) {
108 - printf( '<input type="hidden" name="from_tag" value="%d" />', (int) $from_term_id );
109 - }
82 + if (!empty($_GET['from_tag']))
83 + printf('<input type="hidden" name="from_tag" value="%d" />', $_GET['from_tag']);
110 84
111 - // Adds translation fields
85 + // adds translation fields
112 86 echo '<div id="term-translations" class="form-field">';
113 - if ( $lang ) {
114 - include __DIR__ . '/view-translations-term.php';
115 - }
116 - echo '</div>' . "\n";
87 + if ($lang)
88 + include(PLL_ADMIN_INC.'/view-translations-term.php');
89 + echo '</div>'."\n";
117 90 }
118 91
119 - /**
120 - * Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
92 + /*
93 + * adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
121 94 *
122 95 * @since 0.1
123 - *
124 - * @param object $tag
125 96 */
126 - public function edit_term_form( $tag ) {
127 - if ( isset( $_REQUEST['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
128 - $post_type = sanitize_key( $_REQUEST['post_type'] ); // phpcs:ignore WordPress.Security.NonceVerification
129 - }
130 -
131 - if ( isset( $GLOBALS['post_type'] ) ) {
132 - $post_type = $GLOBALS['post_type'];
133 - }
134 -
135 - if ( ! post_type_exists( $post_type ) ) {
136 - return;
137 - }
138 -
139 - $term_id = $tag->term_id;
140 - $taxonomy = $tag->taxonomy; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
141 -
142 - $lang = $this->model->term->get_language( $term_id );
143 - $lang = empty( $lang ) ? $this->pref_lang : $lang;
144 -
145 - // Disable the language dropdown and the translations input fields for default categories to prevent removal
146 - $disabled = in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) );
147 -
97 + public function edit_term_form($tag) {
98 + $term_id = $tag->term_id;
99 + $lang = $this->model->get_term_language($term_id);
100 + $taxonomy = $tag->taxonomy;
101 + $post_type = isset($GLOBALS['post_type']) ? $GLOBALS['post_type'] : $_REQUEST['post_type'];
148 102 $dropdown = new PLL_Walker_Dropdown();
149 103
150 - $dropdown_html = $dropdown->walk(
151 - $this->model->get_languages_list(),
152 - -1,
153 - array(
154 - 'name' => 'term_lang_choice',
155 - 'value' => 'term_id',
156 - 'selected' => $lang ? $lang->term_id : '',
157 - 'disabled' => $disabled,
158 - 'flag' => true,
159 - )
160 - );
104 + wp_nonce_field('pll_language', '_pll_nonce');
161 105
162 - wp_nonce_field( 'pll_language', '_pll_nonce' );
163 -
164 - printf(
165 - '<tr class="form-field">
106 + printf('
107 + <tr class="form-field">
166 108 <th scope="row">
167 109 <label for="term_lang_choice">%s</label>
168 110 </th>
169 - <td id="select-edit-term-language">
111 + <td>
170 112 %s<br />
171 - <p class="description">%s</p>
113 + <span class="description">%s</span>
172 114 </td>
173 115 </tr>',
174 - esc_html__( 'Language', 'polylang' ),
175 - $dropdown_html, // phpcs:ignore
176 - esc_html__( 'Sets the language', 'polylang' )
116 + __('Language', 'polylang'),
117 + $dropdown->walk($this->model->get_languages_list(), array('name' => 'term_lang_choice', 'value' => 'term_id', 'selected' => $lang ? $lang->term_id : '')),
118 + __('Sets the language', 'polylang')
177 119 );
178 120
179 121 echo '<tr id="term-translations" class="form-field">';
180 - if ( $lang ) {
181 - include __DIR__ . '/view-translations-term.php';
182 - }
183 - echo '</tr>' . "\n";
122 + if ($lang)
123 + include(PLL_ADMIN_INC.'/view-translations-term.php');
124 + echo '</tr>'."\n";
184 125 }
185 126
186 - /**
187 - * Translates term parent if exists when using "Add new" ( translation )
127 + /*
128 + * translates term parent if exists when using "Add new" (translation)
188 129 *
189 130 * @since 0.7
190 131 *
191 - * @param string $output html markup for dropdown list of categories
132 + * @param string html markup for dropdown list of categories
192 133 * @return string modified html
193 134 */
194 - public function wp_dropdown_cats( $output ) {
195 - if ( isset( $_GET['taxonomy'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
196 - $taxonomy = sanitize_key( $_GET['taxonomy'] ); // phpcs:ignore WordPress.Security.NonceVerification
135 + public function wp_dropdown_cats($output) {
136 + if (isset($_GET['taxonomy'], $_GET['from_tag'], $_GET['new_lang']) && $id = get_term($_GET['from_tag'], $_GET['taxonomy'])->parent) {
137 + if ($parent = $this->model->get_translation('term', $id, $_GET['new_lang']))
138 + return str_replace('"'.$parent.'"', '"'.$parent.'" selected="selected"', $output);
197 139 }
198 -
199 - if ( isset( $taxonomy, $_GET['from_tag'], $_GET['new_lang'] ) && taxonomy_exists( $taxonomy ) ) { // phpcs:ignore WordPress.Security.NonceVerification
200 - $term = get_term( (int) $_GET['from_tag'], $taxonomy ); // phpcs:ignore WordPress.Security.NonceVerification
201 -
202 - if ( $term && $id = $term->parent ) {
203 - $lang = $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
204 - if ( $parent = $this->model->term->get_translation( $id, $lang ) ) {
205 - return str_replace( '"' . $parent . '"', '"' . $parent . '" selected="selected"', $output );
206 - }
207 - }
208 - }
209 140 return $output;
210 141 }
211 142
212 - /**
213 - * Stores the current post_id when bulk editing posts for use in save_language and pre_term_slug
143 + /*
144 + * prevents duplicating a term translation
214 145 *
215 - * @since 1.7
146 + * @since 1.3
216 147 *
217 - * @param int $post_id
148 + * @param string $term The term to add or update.
149 + * @param string $taxonomy The taxonomy to which to add the term
150 + *
151 + * @return object|string WP_Error object if the translation already exits, unmodified $term otherwise
218 152 */
219 - public function pre_post_update( $post_id ) {
220 - if ( isset( $_GET['bulk_edit'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
221 - $this->post_id = $post_id;
153 + public function pre_insert_term($term, $taxonomy) {
154 + if (isset($_POST['action'], $_POST['from_tag'], $_POST['term_lang_choice']) && 'add-tag' == $_POST['action'] && $this->model->get_translation('term', $_POST['from_tag'], $_POST['term_lang_choice'])) {
155 + $from_term = get_term($_POST['from_tag'], $taxonomy);
156 + return new WP_Error('term_translation_exists', sprintf(
157 + __('A translation does already exist for %s', 'polylang'),
158 + $from_term->name
159 + ));
222 160 }
161 + return $term;
223 162 }
224 163
225 - /**
226 - * Saves language
164 + /*
165 + * saves language
227 166 *
228 167 * @since 1.5
229 168 *
230 - * @param int $term_id
169 + * @param int $term_id
231 170 * @param string $taxonomy
232 171 */
233 - protected function save_language( $term_id, $taxonomy ) {
234 - global $wpdb;
235 - // Security checks are necessary to accept language modifications
172 + protected function save_language($term_id, $taxonomy) {
173 + // security checks are necessary to accept language modifications
236 174 // as 'wp_update_term' can be called from outside WP admin
237 175
238 - // Edit tags
239 - if ( isset( $_POST['term_lang_choice'] ) ) {
240 - if ( isset( $_POST['action'] ) && sanitize_key( $_POST['action'] ) === 'add-' . $taxonomy ) { // phpcs:ignore WordPress.Security.NonceVerification
241 - check_ajax_referer( 'add-' . $taxonomy, '_ajax_nonce-add-' . $taxonomy ); // Category metabox
242 - } else {
243 - check_admin_referer( 'pll_language', '_pll_nonce' ); // Edit tags or tags metabox
244 - }
176 + // edit tags
177 + if (isset($_POST['term_lang_choice'])) {
178 + if ('add-' . $taxonomy == $_POST['action'])
179 + check_ajax_referer($_POST['action'], '_ajax_nonce-add-' . $taxonomy); // category metabox
245 180
246 - $this->model->term->set_language( $term_id, $this->model->get_language( sanitize_key( $_POST['term_lang_choice'] ) ) );
181 + else
182 + check_admin_referer('pll_language', '_pll_nonce'); // edit tags or tags metabox
183 +
184 + $this->model->set_term_language($term_id, $_POST['term_lang_choice']);
247 185 }
248 186
249 - // *Post* bulk edit, in case a new term is created
250 - elseif ( isset( $_GET['bulk_edit'], $_GET['inline_lang_choice'] ) ) {
251 - check_admin_referer( 'bulk-posts' );
187 + // quick edit
188 + elseif (isset($_POST['inline_lang_choice'])) {
189 + check_ajax_referer('taxinlineeditnonce', '_inline_edit');
252 190
253 - // Bulk edit does not modify the language
254 - // So we possibly create a tag in several languages
255 - if ( -1 == $_GET['inline_lang_choice'] ) {
256 - // The language of the current term is set a according to the language of the current post
257 - $this->model->term->set_language( $term_id, $this->model->post->get_language( $this->post_id ) );
258 - $term = get_term( $term_id, $taxonomy );
191 + if (isset($_POST['inline-save-tax']) && $this->model->get_term_language($term_id)->slug != $_POST['inline_lang_choice'])
192 + $this->model->delete_translation('term', $term_id);
193 + $this->model->set_term_language($term_id, $_POST['inline_lang_choice']);
194 + }
259 195
260 - // Get all terms with the same name
261 - // FIXME backward compatibility WP < 4.2
262 - // No WP function to get all terms with the exact same name so let's use a custom query
263 - // $terms = get_terms( $taxonomy, array( 'name' => $term->name, 'hide_empty' => false, 'fields' => 'ids' ) ); should be OK in 4.2
264 - // I may need to rework the loop below
265 - $terms = $wpdb->get_results(
266 - $wpdb->prepare(
267 - "SELECT t.term_id FROM $wpdb->terms AS t
268 - INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
269 - WHERE tt.taxonomy = %s AND t.name = %s",
270 - $taxonomy,
271 - $term->name
272 - )
273 - );
274 -
275 - // If we have several terms with the same name, they are translations of each other
276 - if ( count( $terms ) > 1 ) {
277 - $translations = array();
278 -
279 - foreach ( $terms as $term ) {
280 - $translations[ $this->model->term->get_language( $term->term_id )->slug ] = $term->term_id;
281 - }
282 -
283 - $this->model->term->save_translations( $term_id, $translations );
284 - }
285 - }
286 -
287 - else {
288 - $this->model->term->set_language( $term_id, $this->model->get_language( sanitize_key( $_GET['inline_lang_choice'] ) ) );
289 - }
196 + // edit post
197 + elseif (isset($_POST['post_lang_choice'])) {// FIXME should be useless now
198 + check_admin_referer('pll_language', '_pll_nonce');
199 + $this->model->set_term_language($term_id, $_POST['post_lang_choice']);
290 200 }
291 201
292 - // Quick edit
293 - elseif ( isset( $_POST['inline_lang_choice'] ) ) {
294 - check_ajax_referer(
295 - isset( $_POST['action'] ) && 'inline-save' == $_POST['action'] ? 'inlineeditnonce' : 'taxinlineeditnonce', // Post quick edit or tag quick edit ?
296 - '_inline_edit'
297 - );
202 + elseif ($this->model->get_term_language($term_id))
203 + {} // avoids breaking the language if the term is updated outside the edit post or edit tag pages
298 204
299 - $old_lang = $this->model->term->get_language( $term_id ); // Stores the old language
300 - $lang = $this->model->get_language( sanitize_key( $_POST['inline_lang_choice'] ) ); // New language
301 - $translations = $this->model->term->get_translations( $term_id );
205 + // sets language from term parent if exists thanks to Scott Kingsley Clark
206 + elseif (($term = get_term($term_id, $taxonomy)) && !empty($term->parent) && $parent_lang = $this->model->get_term_language($term->parent))
207 + $this->model->set_term_language($term_id, $parent_lang);
302 208
303 - // Checks if the new language already exists in the translation group
304 - if ( $old_lang && $old_lang->slug != $lang->slug ) {
305 - if ( array_key_exists( $lang->slug, $translations ) ) {
306 - $this->model->term->delete_translation( $term_id );
307 - }
308 -
309 - elseif ( array_key_exists( $old_lang->slug, $translations ) ) {
310 - unset( $translations[ $old_lang->slug ] );
311 - $this->model->term->save_translations( $term_id, $translations );
312 - }
313 - }
314 -
315 - $this->model->term->set_language( $term_id, $lang ); // Set new language
316 - }
317 -
318 - // Edit post
319 - elseif ( isset( $_POST['post_lang_choice'] ) ) { // FIXME should be useless now
320 - check_admin_referer( 'pll_language', '_pll_nonce' );
321 - $this->model->term->set_language( $term_id, $this->model->get_language( sanitize_key( $_POST['post_lang_choice'] ) ) );
322 - }
209 + else
210 + $this->model->set_term_language($term_id, $this->pref_lang);
323 211 }
324 212
325 - /**
326 - * Save translations from our form
213 + /*
214 + * save translations from our form
327 215 *
328 216 * @since 1.5
329 217 *
330 218 * @param int $term_id
@@ -329,58 +217,55 @@
329 217 *
330 218 * @param int $term_id
331 219 * @return array
332 220 */
333 - protected function save_translations( $term_id ) {
334 - // Security check as 'wp_update_term' can be called from outside WP admin
335 - check_admin_referer( 'pll_language', '_pll_nonce' );
221 + protected function save_translations($term_id) {
222 + // security check
223 + // as 'wp_update_term' can be called from outside WP admin
224 + check_admin_referer('pll_language', '_pll_nonce');
336 225
337 - $translations = array();
338 -
339 - // Save translations after checking the translated term is in the right language ( as well as cast id to int )
340 - if ( isset( $_POST['term_tr_lang'] ) ) {
341 - foreach ( array_map( 'absint', $_POST['term_tr_lang'] ) as $lang => $tr_id ) {
342 - $tr_lang = $this->model->term->get_language( $tr_id );
343 - $translations[ $lang ] = $tr_lang && $tr_lang->slug == $lang ? $tr_id : 0;
344 - }
226 + // save translations after checking the translated term is in the right language (as well as cast id to int)
227 + foreach ($_POST['term_tr_lang'] as $lang => $tr_id) {
228 + $tr_lang = $this->model->get_term_language((int) $tr_id);
229 + $translations[$lang] = $tr_lang && $tr_lang->slug == $lang ? (int) $tr_id : 0;
345 230 }
346 231
347 - $this->model->term->save_translations( $term_id, $translations );
232 + $this->model->save_translations('term', $term_id, $translations);
348 233
349 234 return $translations;
350 235 }
351 236
352 - /**
353 - * Called when a category or post tag is created or edited
354 - * Saves language and translations
237 + /*
238 + * called when a category or post tag is created or edited
239 + * saves language and translations
355 240 *
356 241 * @since 0.1
357 242 *
358 - * @param int $term_id
359 - * @param int $tt_id term taxonomy id
243 + * @param int $term_id
244 + * @param int $tt_id term taxononomy id
360 245 * @param string $taxonomy
361 246 */
362 - public function save_term( $term_id, $tt_id, $taxonomy ) {
363 - // Does nothing except on taxonomies which are filterable
364 - if ( ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
247 + public function save_term($term_id, $tt_id, $taxonomy) {
248 + // does nothing except on taxonomies which are filterable
249 + if (!$this->model->is_translated_taxonomy($taxonomy))
365 250 return;
366 - }
367 251
368 - // Capability check
369 - // As 'wp_update_term' can be called from outside WP admin
370 - // 2nd test for creating tags when creating / editing a post
371 - $tax = get_taxonomy( $taxonomy );
372 - if ( current_user_can( $tax->cap->edit_terms ) || ( isset( $_POST['tax_input'][ $taxonomy ] ) && current_user_can( $tax->cap->assign_terms ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
373 - $this->save_language( $term_id, $taxonomy );
252 + // capability check
253 + // as 'wp_update_term' can be called from outside WP admin
254 + $tax = get_taxonomy($taxonomy);
255 + if (!current_user_can($tax->cap->edit_terms))
256 + wp_die( __( 'Cheatin&#8217; uh?' ) );
374 257
375 - if ( isset( $_POST['term_tr_lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
376 - $this->save_translations( $term_id );
377 - }
378 - }
258 + $this->save_language($term_id, $taxonomy);
259 +
260 + if (isset($_POST['term_tr_lang']))
261 + $translations = $this->save_translations($term_id);
262 +
263 + do_action('pll_save_term', $term_id, $taxonomy, empty($translations) ? $this->model->get_translations('term', $term_id) : $translations);
379 264 }
380 265
381 - /**
382 - * Stores the term name for use in pre_term_slug
266 + /*
267 + * stores the term name for use in pre_term_slug
383 268 *
384 269 * @since 0.9.5
385 270 *
386 271 * @param string $name term name
@@ -385,14 +270,14 @@
385 270 *
386 271 * @param string $name term name
387 272 * @return string unmodified term name
388 273 */
389 - public function pre_term_name( $name ) {
274 + public function pre_term_name($name) {
390 275 return $this->pre_term_name = $name;
391 276 }
392 277
393 - /**
394 - * Creates the term slug in case the term already exists in another language
278 + /*
279 + * creates the term slug in case the term already exists in another language
395 280 *
396 281 * @since 0.9.5
397 282 *
398 283 * @param string $slug
@@ -398,251 +283,299 @@
398 283 * @param string $slug
399 284 * @param string $taxonomy
400 285 * @return string
401 286 */
402 - public function pre_term_slug( $slug, $taxonomy ) {
403 - $name = sanitize_title( $this->pre_term_name );
287 + public function pre_term_slug($slug, $taxonomy) {
288 + $name = sanitize_title($this->pre_term_name);
404 289
405 - // If the term already exists in another language
406 - if ( ! $slug && $this->model->is_translated_taxonomy( $taxonomy ) && term_exists( $name, $taxonomy ) ) {
407 - if ( isset( $_POST['term_lang_choice'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
408 - $lang = $this->model->get_language( sanitize_key( $_POST['term_lang_choice'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
409 - }
290 + // if the new term has the same name as a language, we *need* to differentiate the term
291 + // see http://core.trac.wordpress.org/ticket/23199
292 + if (term_exists($name, 'language') && !term_exists($name, $taxonomy) && (!$slug || $slug == $name))
293 + $slug = $name . '-' . $taxonomy; // a convenient slug which may be modified later by the user
410 294
411 - elseif ( isset( $_POST['inline_lang_choice'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
412 - $lang = $this->model->get_language( sanitize_key( $_POST['inline_lang_choice'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
413 - }
295 + // if the term already exists in another language
296 + if (!$slug && $this->model->is_translated_taxonomy($taxonomy) && term_exists($name, $taxonomy)) {
297 + if (isset($_POST['term_lang_choice']))
298 + $slug = $name . '-' . $this->model->get_language($_POST['term_lang_choice'])->slug;
414 299
415 - // *Post* bulk edit, in case a new term is created
416 - elseif ( isset( $_GET['bulk_edit'], $_GET['inline_lang_choice'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
417 - // Bulk edit does not modify the language
418 - if ( -1 == $_GET['inline_lang_choice'] ) { // phpcs:ignore WordPress.Security.NonceVerification
419 - $lang = $this->model->post->get_language( $this->post_id );
420 - } else {
421 - $lang = $this->model->get_language( sanitize_key( $_GET['inline_lang_choice'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
422 - }
423 - }
424 -
425 - if ( ! empty( $lang ) && ! $this->model->term_exists_by_slug( $name, $lang, $taxonomy ) ) {
426 - $slug = $name . '-' . $lang->slug;
427 - }
300 + elseif (isset($_POST['inline_lang_choice']))
301 + $slug = $name . '-' . $this->model->get_language($_POST['inline_lang_choice'])->slug;
428 302 }
429 303
430 304 return $slug;
431 305 }
432 306
433 - /**
434 - * Ajax response for edit term form
307 + /*
308 + * called when a category or post tag is deleted
309 + * deletes language and translations
435 310 *
311 + * @since 0.1
312 + *
313 + * @param int $term_id
314 + */
315 + public function delete_term($term_id) {
316 + $this->model->delete_translation('term', $term_id);
317 + $this->model->delete_term_language($term_id);
318 + }
319 +
320 + /*
321 + * ajax response for edit term form
322 + *
436 323 * @since 0.2
437 324 */
438 325 public function term_lang_choice() {
439 - check_ajax_referer( 'pll_language', '_pll_nonce' );
326 + check_ajax_referer('pll_language', '_pll_nonce');
440 327
441 - if ( ! isset( $_POST['taxonomy'], $_POST['post_type'], $_POST['lang'] ) ) {
442 - wp_die( 0 );
443 - }
328 + $lang = $this->model->get_language($_POST['lang']);
329 + $term_id = isset($_POST['term_id']) ? $_POST['term_id'] : null;
330 + $taxonomy = $_POST['taxonomy'];
331 + $post_type = $_POST['post_type'];
444 332
445 - $lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) );
446 - $term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : null; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
447 - $taxonomy = sanitize_key( $_POST['taxonomy'] ); // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable
448 - $post_type = sanitize_key( $_POST['post_type'] );
449 -
450 - if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
451 - wp_die( 0 );
452 - }
453 -
454 333 ob_start();
455 - if ( $lang ) {
456 - include __DIR__ . '/view-translations-term.php';
457 - }
458 - $x = new WP_Ajax_Response( array( 'what' => 'translations', 'data' => ob_get_contents() ) );
334 + if ($lang)
335 + include(PLL_ADMIN_INC.'/view-translations-term.php');
336 + $x = new WP_Ajax_Response(array('what' => 'translations', 'data' => ob_get_contents()));
459 337 ob_end_clean();
460 338
461 - // Parent dropdown list ( only for hierarchical taxonomies )
339 + // parent dropdown list (only for hierarchical taxonomies)
462 340 // $args copied from edit_tags.php except echo
463 - if ( is_taxonomy_hierarchical( $taxonomy ) ) {
341 + if (is_taxonomy_hierarchical($taxonomy)) {
464 342 $args = array(
465 - 'hide_empty' => 0,
466 - 'hide_if_empty' => false,
467 - 'taxonomy' => $taxonomy,
468 - 'name' => 'parent',
469 - 'orderby' => 'name',
470 - 'hierarchical' => true,
471 - 'show_option_none' => __( 'None', 'polylang' ),
472 - 'echo' => 0,
343 + 'hide_empty' => 0,
344 + 'hide_if_empty' => false,
345 + 'taxonomy' => $taxonomy,
346 + 'name' => 'parent',
347 + 'orderby' => 'name',
348 + 'hierarchical' => true,
349 + 'show_option_none' => __('None'),
350 + 'echo' => 0,
473 351 );
474 - $x->Add( array( 'what' => 'parent', 'data' => wp_dropdown_categories( $args ) ) );
352 + $x->Add(array('what' => 'parent', 'data' => wp_dropdown_categories($args)));
475 353 }
476 354
477 - // Tag cloud
478 - // Tests copied from edit_tags.php
355 + // tag cloud
356 + // tests copied from edit_tags.php
479 357 else {
480 - $tax = get_taxonomy( $taxonomy );
481 - if ( ! is_null( $tax->labels->popular_items ) ) {
482 - $args = array( 'taxonomy' => $taxonomy, 'echo' => false );
483 - if ( current_user_can( $tax->cap->edit_terms ) ) {
484 - $args = array_merge( $args, array( 'link' => 'edit' ) );
485 - }
358 + $tax = get_taxonomy($taxonomy);
359 + if (!is_null($tax->labels->popular_items)) {
360 + $args = array('taxonomy' => $taxonomy, 'echo' => false);
361 + if (current_user_can($tax->cap->edit_terms))
362 + $args = array_merge($args, array('link' => 'edit'));
486 363
487 - if ( $tag_cloud = wp_tag_cloud( $args ) ) {
488 - $html = sprintf( '<div class="tagcloud"><h2>%1$s</h2>%2$s</div>', esc_html( $tax->labels->popular_items ), $tag_cloud );
489 - $x->Add( array( 'what' => 'tag_cloud', 'data' => $html ) );
490 - }
364 + if ($tag_cloud = wp_tag_cloud($args))
365 + $x->Add(array('what' => 'tag_cloud', 'data' => '<h3>'.$tax->labels->popular_items.'</h3>'.$tag_cloud));
491 366 }
492 367 }
493 368
494 - // Flag
495 - $x->Add( array( 'what' => 'flag', 'data' => empty( $lang->flag ) ? esc_html( $lang->slug ) : $lang->flag ) );
496 -
497 369 $x->send();
498 370 }
499 371
500 - /**
501 - * Ajax response for input in translation autocomplete input box
372 + /*
373 + * ajax response for input in translation autocomplete input box
502 374 *
503 375 * @since 1.5
504 376 */
505 377 public function ajax_terms_not_translated() {
506 - check_ajax_referer( 'pll_language', '_pll_nonce' );
378 + check_ajax_referer('pll_language', '_pll_nonce');
507 379
508 - if ( ! isset( $_GET['term'], $_GET['post_type'], $_GET['taxonomy'], $_GET['term_language'], $_GET['translation_language'] ) ) {
509 - wp_die( 0 );
380 + $return = array();
381 +
382 + // it is more efficient to use one common query for all languages as soon as there are more than 2
383 + // pll_get_terms_not_translated arg to identify this query in terms_clauses filter
384 + foreach (get_terms($_REQUEST['taxonomy'], 'hide_empty=0&pll_get_terms_not_translated=1&name__like=' . $_REQUEST['term']) as $term) {
385 + $lang = $this->model->get_term_language($term->term_id);
386 +
387 + if ($lang && $lang->slug == $_REQUEST['translation_language'] && !$this->model->get_translation('term', $term->term_id, $_REQUEST['term_language']))
388 + $return[] = array(
389 + 'id' => $term->term_id,
390 + 'value' => $term->name,
391 + 'link' => $this->edit_translation_link($term->term_id, $_REQUEST['taxonomy'], $_REQUEST['post_type'])
392 + );
510 393 }
511 394
512 - $s = wp_unslash( $_GET['term'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
513 - $post_type = sanitize_key( $_GET['post_type'] );
514 - $taxonomy = sanitize_key( $_GET['taxonomy'] );
395 + // add current translation in list
396 + // not in add term for as term_id is not set
397 + if ('undefined' !== $_REQUEST['term_id'] && $term_id = $this->model->get_translation('term', $_REQUEST['term_id'], $_REQUEST['translation_language'])) {
398 + $term = get_term($term_id, $_REQUEST['taxonomy']);
399 + array_unshift($return, array(
400 + 'id' => $term_id,
401 + 'value' => $term->name,
402 + 'link' => $this->edit_translation_link($term->term_id, $_REQUEST['taxonomy'], $_REQUEST['post_type'])
403 + ));
404 + }
515 405
516 - if ( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
517 - wp_die( 0 );
518 - }
406 + wp_die(json_encode($return));
407 + }
519 408
520 - $term_language = $this->model->get_language( sanitize_key( $_GET['term_language'] ) );
521 - $translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) );
409 + /*
410 + * filters categories and post tags by language when needed on admin side
411 + *
412 + * @since 0.5
413 + *
414 + * @param array $clauses list of sql clauses
415 + * @param array $taxonomies list of taxonomies
416 + * @param array $args get_terms arguments
417 + * @return array modified sql clauses
418 + */
419 + public function terms_clauses($clauses, $taxonomies, $args) {
420 + // does nothing except on taxonomies which are filterable
421 + foreach ($taxonomies as $tax)
422 + if (!$this->model->is_translated_taxonomy($tax))
423 + return $clauses;
522 424
523 - $terms = array();
524 - $return = array();
425 + if (function_exists('get_current_screen'))
426 + $screen = get_current_screen(); // since WP 3.1, may not be available the first time(s) get_terms is called
525 427
526 - // Add current translation in list.
527 - // Not in add term as term_id is not set.
528 - if ( isset( $_GET['term_id'] ) && 'undefined' !== $_GET['term_id'] && $term_id = $this->model->term->get_translation( (int) $_GET['term_id'], $translation_language ) ) {
529 - $terms = array( get_term( $term_id, $taxonomy ) );
428 + // don't filter nav menus on nav menus screen
429 + if (isset($screen) && 'nav-menus' == $screen->base && in_array('nav_menu', $taxonomies))
430 + return $clauses;
431 +
432 + // if get_terms is queried with a 'lang' parameter
433 + if (!empty($args['lang']))
434 + return $this->model->terms_clauses($clauses, $args['lang']);
435 +
436 + // does nothing in Languages and dasboard admin panels
437 + if (isset($screen) && in_array($screen->base, array('toplevel_page_mlang', 'dashboard')))
438 + return $clauses;
439 +
440 + // do not filter 'get_terms_not_translated'
441 + if (!empty($args['pll_get_terms_not_translated']))
442 + return $clauses;
443 +
444 + // The only ajax response I want to deal with is when changing the language in post metabox
445 + if (isset($_POST['action']) && !in_array($_POST['action'], array('post_lang_choice', 'term_lang_choice', 'get-tagcloud')))
446 + return $clauses;
447 +
448 + // I only want to filter the parent dropdown list when editing a term in a hierarchical taxonomy
449 + if (isset($_POST['action']) && $_POST['action'] == 'term_lang_choice' && !(isset($args['class']) || isset($args['unit'])))
450 + return $clauses;
451 +
452 + // ajax response for changing the language in the post metabox (or in the edit-tags panels)
453 + if (isset($_POST['lang']))
454 + $lang = $this->model->get_language($_POST['lang']);
455 +
456 + // ajax tag search since WP 3.7
457 + elseif (!empty($_GET['lang']) && isset($_GET['action']) && 'polylang-ajax-tag-search' == $_GET['action'])
458 + $lang = $this->model->get_language($_GET['lang']);
459 +
460 + // the post (or term) is created with the 'add new' (translation) link
461 + // test of $args['page'] to avoid filtering the terms list table in edit-tags panel
462 + elseif (!empty($_GET['new_lang']) && empty($args['page']))
463 + $lang = $this->model->get_language($_GET['new_lang']);
464 +
465 + // FIXME can we simplify how we deal with the admin language filter?
466 + // the language filter selection has just changed
467 + // test $screen->base to avoid interference between the language filter and the post language selection and the category parent dropdown list
468 + elseif (!empty($_GET['lang']) && !(isset($screen) && in_array($screen->base, array('post', 'edit-tags')))) {
469 + if ($_GET['lang'] != 'all')
470 + $lang = $this->model->get_language($_GET['lang']);
471 + elseif ($screen->base == 'edit-tags' && isset($args['class']))
472 + $lang = $this->pref_lang; // parent dropdown
530 473 }
531 474
532 - // It is more efficient to use one common query for all languages as soon as there are more than 2.
533 - foreach ( get_terms( $taxonomy, 'hide_empty=0&lang=0&name__like=' . $s ) as $term ) {
534 - $lang = $this->model->term->get_language( $term->term_id );
475 + // again the language filter
476 + elseif (!empty($this->curlang) && (isset($screen) && $screen->base != 'post' && !($screen->base == 'edit-tags' && isset($args['class'])))) // don't apply to post edit and the category parent dropdown list
477 + $lang = $this->curlang;
535 478
536 - if ( $lang && $lang->slug == $translation_language->slug && ! $this->model->term->get_translation( $term->term_id, $term_language ) ) {
537 - $terms[] = $term;
538 - }
539 - }
479 + elseif (isset($_GET['post']))
480 + $lang = $this->model->get_post_language($_GET['post']);
540 481
541 - // Format the ajax response.
542 - foreach ( $terms as $term ) {
543 - $return[] = array(
544 - 'id' => $term->term_id,
545 - 'value' => rtrim( // Trim the seperator added at the end by WP.
546 - get_term_parents_list(
547 - $term->term_id,
548 - $term->taxonomy,
549 - array(
550 - 'separator' => ' > ',
551 - 'link' => false,
552 - )
553 - ),
554 - ' >'
555 - ),
556 - 'link' => $this->links->edit_term_translation_link( $term->term_id, $term->taxonomy, $post_type ),
557 - );
558 - }
482 + // for the parent dropdown list in edit term
483 + elseif (isset($_GET['tag_ID']))
484 + $lang = $this->model->get_term_language($_GET['tag_ID']);
559 485
560 - wp_die( wp_json_encode( $return ) );
486 + // when a new category is created in the edit post panel
487 + elseif (isset($_POST['term_lang_choice']))
488 + $lang = $this->model->get_language($_POST['term_lang_choice']);
489 +
490 + // for a new post (or the parent dropdown list of a new term)
491 + elseif (isset($screen) && ($screen->base == 'post' || ($screen->base == 'edit-tags' && isset($args['class']))))
492 + $lang = $this->pref_lang;
493 +
494 + // adds our clauses to filter by current language
495 + return !empty($lang) ? $this->model->terms_clauses($clauses, $lang) : $clauses;
561 496 }
562 497
563 - /**
564 - * Filters the default category in note below the category list table and in settings->writing dropdown
498 + /*
499 + * replaces ajax tag search of WP to filter tags by language
500 + * backward compatibility WP < 3.7
501 + * see http://core.trac.wordpress.org/ticket/25231
565 502 *
566 - * @since 1.2
567 - *
568 - * @param int $value
569 - * @return int
503 + * @since 0.7
570 504 */
571 - public function option_default_category( $value ) {
572 - if ( isset( $this->pref_lang ) && $tr = $this->model->term->get( $value, $this->pref_lang ) ) {
573 - $value = $tr;
505 + public function ajax_tag_search() {
506 + global $wpdb;
507 +
508 + if ( isset( $_GET['tax'] ) ) {
509 + $taxonomy = sanitize_key( $_GET['tax'] );
510 + $tax = get_taxonomy( $taxonomy );
511 + if ( ! $tax )
512 + die( '0' );
513 + if ( ! current_user_can( $tax->cap->assign_terms ) )
514 + die( '-1' );
515 + } else {
516 + die('0');
574 517 }
575 - return $value;
518 +
519 + $s = stripslashes( $_GET['q'] );
520 +
521 + if ( false !== strpos( $s, ',' ) ) {
522 + $s = explode( ',', $s );
523 + $s = $s[count( $s ) - 1];
524 + }
525 + $s = trim( $s );
526 + if ( strlen( $s ) < 2 )
527 + die; // require 2 chars for matching
528 +
529 + $lang = $this->model->get_language($_GET['lang']);
530 +
531 + $results = $wpdb->get_col( $wpdb->prepare(
532 + "SELECT t.name FROM $wpdb->term_taxonomy AS tt
533 + INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
534 + INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = t.term_id
535 + WHERE tt.taxonomy = %s AND t.name LIKE (%s) AND pll_tr.term_taxonomy_id = %d",
536 + $taxonomy, '%' . like_escape( $s ) . '%', $lang->tl_term_taxonomy_id ) );
537 +
538 + echo join( $results, "\n" );
539 + die;
576 540 }
577 541
578 - /**
579 - * Checks if the new default category is translated in all languages
580 - * If not, create the translations
542 + /*
543 + * hack to avoid displaying delete link for the default category in all languages
544 + * also returns the default category in the right language when called from wp_delete_term
581 545 *
582 - * @since 1.7
546 + * @since 1.2
583 547 *
584 - * @param int $old_value
585 548 * @param int $value
549 + * @return int
586 550 */
587 - public function update_option_default_category( $old_value, $value ) {
588 - $default_cat_lang = $this->model->term->get_language( $value );
551 + public function option_default_category($value) {
552 + $traces = debug_backtrace();
589 553
590 - // Assign a default language to default category
591 - if ( ! $default_cat_lang ) {
592 - $default_cat_lang = $this->model->get_language( $this->options['default_lang'] );
593 - $this->model->term->set_language( (int) $value, $default_cat_lang );
594 - }
554 + if (isset($traces[4])) {
555 + if (in_array($traces[4]['function'], array('column_cb', 'column_name')) && in_array($traces[4]['args'][0]->term_id, $this->model->get_translations('term', $value)))
556 + return $traces[4]['args'][0]->term_id;
595 557
596 - foreach ( $this->model->get_languages_list() as $language ) {
597 - if ( $language->slug != $default_cat_lang->slug && ! $this->model->term->get_translation( $value, $language ) ) {
598 - $this->model->create_default_category( $language );
599 - }
558 + if ('wp_delete_term' == $traces[4]['function'])
559 + return $this->model->get_term($value, $this->model->get_term_language($traces[4]['args'][0]));
600 560 }
561 + return $value;
601 562 }
602 563
603 - /**
604 - * Updates the translations term ids when splitting a shared term
605 - * Splits translations if these are shared terms too
564 + /*
565 + * returns html markup for a translation link
606 566 *
607 - * @since 1.7
567 + * @since 1.4
608 568 *
609 - * @param int $term_id Shared term_id
610 - * @param int $new_term_id
611 - * @param int $term_taxonomy_id
569 + * @param object $term_id translation term id
612 570 * @param string $taxonomy
571 + * @param string $post_type
572 + * @return string
613 573 */
614 - public function split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
615 - if ( ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
616 - return;
617 - }
618 -
619 - // Avoid recursion
620 - static $avoid_recursion = false;
621 - if ( $avoid_recursion ) {
622 - return;
623 - }
624 -
625 - $avoid_recursion = true;
626 - $lang = $this->model->term->get_language( $term_id );
627 - $translations = array();
628 -
629 - foreach ( $this->model->term->get_translations( $term_id ) as $key => $tr_id ) {
630 - if ( $lang->slug == $key ) {
631 - $translations[ $key ] = $new_term_id;
632 - }
633 - else {
634 - $tr_term = get_term( $tr_id, $taxonomy );
635 - $translations[ $key ] = _split_shared_term( $tr_id, $tr_term->term_taxonomy_id );
636 -
637 - // Hack translation ids sent by the form to avoid overwrite in PLL_Admin_Filters_Term::save_translations
638 - if ( isset( $_POST['term_tr_lang'][ $key ] ) && $_POST['term_tr_lang'][ $key ] == $tr_id ) { // phpcs:ignore WordPress.Security.NonceVerification
639 - $_POST['term_tr_lang'][ $key ] = $translations[ $key ];
640 - }
641 - }
642 - $this->model->term->set_language( $translations[ $key ], $key );
643 - }
644 -
645 - $this->model->term->save_translations( $new_term_id, $translations );
646 - $avoid_recursion = false;
574 + public function edit_translation_link($term_id, $taxonomy, $post_type) {
575 + return sprintf(
576 + '<a href="%1$s" class="pll_icon_edit title="%2$s"></a></td>',
577 + esc_url(get_edit_term_link($term_id, $taxonomy, $post_type)),
578 + __('Edit','polylang')
579 + );
647 580 }
648 581 }