PluginProbe
Polylang / 3.6.7
Polylang v3.6.7
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 | include/translated-term.php +236 -110 3.0.13.6.7 View file →
@@ -2,163 +2,226 @@
2 2 /**
3 3 * @package Polylang
4 4 */
5 5
6 +defined( 'ABSPATH' ) || exit;
7 +
6 8 /**
7 - * Setups the taxonomies languages and translations model
9 + * Sets the taxonomies languages and translations model up.
8 10 *
9 11 * @since 1.8
12 + *
13 + * @phpstan-import-type DBInfoWithType from PLL_Translatable_Object_With_Types_Interface
10 14 */
11 -class PLL_Translated_Term extends PLL_Translated_Object {
15 +class PLL_Translated_Term extends PLL_Translated_Object implements PLL_Translatable_Object_With_Types_Interface {
16 + use PLL_Translatable_Object_With_Types_Trait;
12 17
13 18 /**
14 - * Constructor
19 + * Taxonomy name for the languages.
15 20 *
16 - * @since 1.8
21 + * @var string
17 22 *
18 - * @param object $model
23 + * @phpstan-var non-empty-string
19 24 */
20 - public function __construct( &$model ) {
21 - $this->object_type = 'term'; // For taxonomies
22 - $this->type = 'term'; // For capabilities
23 - $this->tax_language = 'term_language';
24 - $this->tax_translations = 'term_translations';
25 - $this->tax_tt = 'tl_term_taxonomy_id';
25 + protected $tax_language = 'term_language';
26 26
27 - parent::__construct( $model );
27 + /**
28 + * Object type to use when registering the taxonomy.
29 + *
30 + * @var string
31 + *
32 + * @phpstan-var non-empty-string
33 + */
34 + protected $object_type = 'term';
28 35
29 - // Filters to prime terms cache
30 - add_filter( 'get_terms', array( $this, '_prime_terms_cache' ), 10, 2 );
31 - add_filter( 'get_object_terms', array( $this, 'wp_get_object_terms' ), 10, 3 );
36 + /**
37 + * Identifier that must be unique for each type of content.
38 + * Also used when checking capabilities.
39 + *
40 + * @var string
41 + *
42 + * @phpstan-var non-empty-string
43 + */
44 + protected $type = 'term';
32 45
33 - add_action( 'clean_term_cache', array( $this, 'clean_term_cache' ) );
34 - }
35 -
36 46 /**
37 - * Stores the term language in the database.
47 + * Identifier for each type of content to used for cache type.
38 48 *
39 - * @since 0.6
49 + * @var string
40 50 *
41 - * @param int $term_id Term id.
42 - * @param int|string|PLL_Language $lang Language (term_id or slug or object).
43 - * @return void
51 + * @phpstan-var non-empty-string
44 52 */
45 - public function set_language( $term_id, $lang ) {
46 - $term_id = (int) $term_id;
53 + protected $cache_type = 'terms';
47 54
48 - $old_lang = $this->get_language( $term_id );
49 - $old_lang = $old_lang ? $old_lang->tl_term_id : '';
50 55
51 - $lang = $this->model->get_language( $lang );
52 - $lang = $lang ? $lang->tl_term_id : '';
56 + /**
57 + * Taxonomy name for the translation groups.
58 + *
59 + * @var string
60 + *
61 + * @phpstan-var non-empty-string
62 + */
63 + protected $tax_translations = 'term_translations';
53 64
54 - if ( $old_lang !== $lang ) {
55 - wp_set_object_terms( $term_id, $lang, 'term_language' );
65 + /**
66 + * Constructor.
67 + *
68 + * @since 1.8
69 + *
70 + * @param PLL_Model $model Instance of `PLL_Model`.
71 + */
72 + public function __construct( PLL_Model &$model ) {
73 + parent::__construct( $model );
56 74
57 - // Add translation group for correct WXR export
58 - $translations = $this->get_translations( $term_id );
59 - if ( $slug = array_search( $term_id, $translations ) ) {
60 - unset( $translations[ $slug ] );
61 - }
62 -
63 - $this->save_translations( $term_id, $translations );
64 - }
75 + // Keep hooks in constructor for backward compatibility.
76 + $this->init();
65 77 }
66 78
67 79 /**
68 - * Removes the term language in database
80 + * Adds hooks.
69 81 *
70 - * @since 0.5
82 + * @since 3.4
71 83 *
72 - * @param int $term_id term id
73 - * @return void
84 + * @return static
74 85 */
75 - public function delete_language( $term_id ) {
76 - wp_delete_object_term_relationships( $term_id, 'term_language' );
86 + public function init() {
87 + add_filter( 'get_terms', array( $this, '_prime_terms_cache' ), 10, 2 );
88 + add_action( 'clean_term_cache', array( $this, 'clean_term_cache' ) );
89 + return parent::init();
77 90 }
78 91
79 92 /**
80 - * Returns the language of a term
93 + * Stores the term's language into the database.
81 94 *
82 - * @since 0.1
95 + * @since 0.6
96 + * @since 3.4 Renamed the parameter $term_id into $id.
83 97 *
84 - * @param int|string $value term id or term slug
85 - * @param string $taxonomy optional taxonomy needed when the term slug is passed as first parameter
86 - * @return PLL_Language|false PLL_Language object, false if no language is associated to that term
98 + * @param int $id Term ID.
99 + * @param PLL_Language|string|int $lang Language (object, slug, or term ID).
100 + * @return bool True when successfully assigned. False otherwise (or if the given language is already assigned to
101 + * the object).
87 102 */
88 - public function get_language( $value, $taxonomy = '' ) {
89 - if ( is_numeric( $value ) ) {
90 - $term_id = $value;
103 + public function set_language( $id, $lang ) {
104 + if ( ! parent::set_language( $id, $lang ) ) {
105 + return false;
91 106 }
92 107
93 - // get_term_by still not cached in WP 3.5.1 but internally, the function is always called by term_id
94 - elseif ( is_string( $value ) && $taxonomy ) {
95 - $term = get_term_by( 'slug', $value, $taxonomy );
96 - if ( $term instanceof WP_Term ) {
97 - $term_id = $term->term_id;
98 - }
108 + $id = $this->sanitize_int_id( $id );
109 +
110 + // Add translation group for correct WXR export.
111 + $translations = $this->get_translations( $id );
112 +
113 + if ( ! empty( $translations ) ) {
114 + $translations = array_diff( $translations, array( $id ) );
99 115 }
100 116
101 - // Get the language and make sure it is a PLL_Language object
102 - return isset( $term_id ) && ( $lang = $this->get_object_term( $term_id, 'term_language' ) ) ? $this->model->get_language( $lang->term_id ) : false;
117 + $this->save_translations( $id, $translations );
118 +
119 + return true;
103 120 }
104 121
105 122 /**
106 - * Tells whether a translation term must updated.
123 + * Returns the language of a term.
107 124 *
108 - * @since 2.3
125 + * @since 0.1
126 + * @since 3.4 Renamed the parameter $value into $id.
127 + * @since 3.4 Deprecated to retrieve the language by term slug + taxonomy anymore.
109 128 *
110 - * @param int $id Post id or term id.
111 - * @param int[] $translations An associative array of translations with language code as key and translation id as value.
112 - * @return bool
129 + * @param int $id Term ID.
130 + * @return PLL_Language|false A `PLL_Language` object. `false` if no language is associated to that term or if the
131 + * ID is invalid.
113 132 */
114 - protected function should_update_translation_group( $id, $translations ) {
115 - // Don't do anything if no translations have been added to the group
116 - $old_translations = $this->get_translations( $id );
117 - if ( count( $translations ) > 1 && count( array_diff_assoc( $translations, $old_translations ) ) > 0 ) {
118 - return true;
133 + public function get_language( $id ) {
134 + if ( func_num_args() > 1 ) {
135 + // Backward compatibility.
136 + _deprecated_argument( __METHOD__ . '()', '3.4' );
137 +
138 + $term = get_term_by( 'slug', $id, func_get_arg( 1 ) ); // @phpstan-ignore-line
139 + $id = $term instanceof WP_Term ? $term->term_id : 0;
119 140 }
120 141
121 - // But we need a translation group for terms to allow relationships remap when importing from a WXR file
122 - $term = $this->get_object_term( $id, $this->tax_translations );
123 - return empty( $term ) || count( array_diff_assoc( $translations, $old_translations ) );
142 + return parent::get_language( $id );
124 143 }
125 144
126 145 /**
127 - * Deletes a translation
146 + * Deletes a translation of a term.
128 147 *
129 148 * @since 0.5
130 149 *
131 - * @param int $id term id
150 + * @param int $id Term ID.
132 151 * @return void
133 152 */
134 153 public function delete_translation( $id ) {
135 154 global $wpdb;
136 - $slug = array_search( $id, $this->get_translations( $id ) ); // in case some plugin stores the same value with different key
137 155
156 + $id = $this->sanitize_int_id( $id );
157 +
158 + if ( empty( $id ) ) {
159 + return;
160 + }
161 +
162 + $slug = array_search( $id, $this->get_translations( $id ) ); // In case some plugin stores the same value with different key.
163 +
138 164 parent::delete_translation( $id );
139 - wp_delete_object_term_relationships( $id, 'term_translations' );
165 + wp_delete_object_term_relationships( $id, $this->tax_translations );
140 166
141 - if ( ! doing_action( 'pre_delete_term' ) && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
142 - // Always keep a group for terms to allow relationships remap when importing from a WXR file
143 - $translations = array( $slug => $id );
144 - wp_insert_term( $group = uniqid( 'pll_' ), 'term_translations', array( 'description' => maybe_serialize( $translations ) ) );
145 - wp_set_object_terms( $id, $group, 'term_translations' );
167 + if ( doing_action( 'pre_delete_term' ) ) {
168 + return;
146 169 }
170 +
171 + if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM $wpdb->terms WHERE term_id = %d;", $id ) ) ) {
172 + return;
173 + }
174 +
175 + // Always keep a group for terms to allow relationships remap when importing from a WXR file.
176 + $group = uniqid( 'pll_' );
177 + $translations = array( $slug => $id );
178 + wp_insert_term( $group, $this->tax_translations, array( 'description' => maybe_serialize( $translations ) ) );
179 + wp_set_object_terms( $id, $group, $this->tax_translations );
147 180 }
148 181
149 182 /**
150 - * A join clause to add to sql queries when filtering by language is needed directly in query
183 + * Returns object types (taxonomy names) that need to be translated.
184 + * The taxonomies list is cached for better performance.
185 + * The method waits for 'after_setup_theme' to apply the cache to allow themes adding the filter in functions.php.
151 186 *
152 - * @since 1.2
153 - * @since 2.6 The `$alias` parameter was added.
187 + * @since 3.4
154 188 *
155 - * @param string $alias Alias for $wpdb->terms table
156 - * @return string join clause
189 + * @param bool $filter True if we should return only valid registered object types.
190 + * @return string[] Object type names for which Polylang manages languages.
191 + *
192 + * @phpstan-return array<non-empty-string, non-empty-string>
157 193 */
158 - public function join_clause( $alias = 't' ) {
159 - global $wpdb;
160 - return " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = $alias.term_id";
194 + public function get_translated_object_types( $filter = true ) {
195 + $taxonomies = $this->model->cache->get( 'taxonomies' );
196 +
197 + if ( false === $taxonomies ) {
198 + $taxonomies = array( 'category' => 'category', 'post_tag' => 'post_tag' );
199 +
200 + if ( ! empty( $this->model->options['taxonomies'] ) && is_array( $this->model->options['taxonomies'] ) ) {
201 + $taxonomies = array_merge( $taxonomies, array_combine( $this->model->options['taxonomies'], $this->model->options['taxonomies'] ) );
202 + }
203 +
204 + /**
205 + * Filters the list of taxonomies available for translation.
206 + * The default are taxonomies which have the parameter ‘public’ set to true.
207 + * The filter must be added soon in the WordPress loading process:
208 + * in a function hooked to ‘plugins_loaded’ or directly in functions.php for themes.
209 + *
210 + * @since 0.8
211 + *
212 + * @param string[] $taxonomies List of taxonomy names (as array keys and values).
213 + * @param bool $is_settings True when displaying the list of custom taxonomies in Polylang settings.
214 + */
215 + $taxonomies = (array) apply_filters( 'pll_get_taxonomies', $taxonomies, false );
216 +
217 + if ( did_action( 'after_setup_theme' ) && ! doing_action( 'switch_blog' ) ) {
218 + $this->model->cache->set( 'taxonomies', $taxonomies );
219 + }
220 + }
221 +
222 + /** @var array<non-empty-string, non-empty-string> $taxonomies */
223 + return $filter ? array_intersect( $taxonomies, get_taxonomies() ) : $taxonomies;
161 224 }
162 225
163 226 /**
164 227 * Caches the language and translations when terms are queried by get_terms().
@@ -167,49 +230,112 @@
167 230 *
168 231 * @param WP_Term[]|int[] $terms Queried terms.
169 232 * @param string[] $taxonomies Queried taxonomies.
170 233 * @return WP_Term[]|int[] Unmodified $terms.
234 + *
235 + * @phpstan-param array<WP_Term|positive-int> $terms
236 + * @phpstan-param array<non-empty-string> $taxonomies
237 + * @phpstan-return array<WP_Term|positive-int>
171 238 */
172 239 public function _prime_terms_cache( $terms, $taxonomies ) {
173 - $term_ids = array();
240 + $ids = array();
174 241
175 242 if ( is_array( $terms ) && $this->model->is_translated_taxonomy( $taxonomies ) ) {
176 243 foreach ( $terms as $term ) {
177 - $term_ids[] = is_object( $term ) ? $term->term_id : (int) $term;
244 + $ids[] = is_object( $term ) ? $term->term_id : (int) $term;
178 245 }
179 246 }
180 247
181 - if ( ! empty( $term_ids ) ) {
182 - update_object_term_cache( array_unique( $term_ids ), 'term' ); // Adds language and translation of terms to cache
248 + if ( ! empty( $ids ) ) {
249 + update_object_term_cache( array_unique( $ids ), 'term' ); // Adds language and translation of terms to cache.
183 250 }
184 251 return $terms;
185 252 }
186 253
187 254 /**
188 - * When terms are found for posts, add their language and translations to cache.
255 + * When the term cache is cleaned, cleans the object term cache too.
189 256 *
257 + * @since 2.0
258 + *
259 + * @param int[] $ids An array of term IDs.
260 + * @return void
261 + *
262 + * @phpstan-param array<positive-int> $ids
263 + */
264 + public function clean_term_cache( $ids ) {
265 + clean_object_term_cache( $this->sanitize_int_ids_list( $ids ), 'term' );
266 + }
267 +
268 + /**
269 + * Tells whether a translation term must be updated.
270 + *
271 + * @since 2.3
272 + *
273 + * @param int $id Term ID.
274 + * @param int[] $translations An associative array of translations with language code as key and translation ID as
275 + * value. Make sure to sanitize this.
276 + * @return bool
277 + *
278 + * @phpstan-param array<non-empty-string, positive-int> $translations
279 + */
280 + protected function should_update_translation_group( $id, $translations ) {
281 + // Don't do anything if no translations have been added to the group.
282 + $old_translations = $this->get_translations( $id );
283 + if ( count( $translations ) > 1 && ! empty( array_diff_assoc( $translations, $old_translations ) ) ) {
284 + return true;
285 + }
286 +
287 + // But we need a translation group for terms to allow relationships remap when importing from a WXR file
288 + $term = $this->get_object_term( $id, $this->tax_translations );
289 + return empty( $term ) || ! empty( array_diff_assoc( $translations, $old_translations ) );
290 + }
291 +
292 + /**
293 + * Assigns a language to terms in mass.
294 + *
190 295 * @since 1.2
296 + * @since 3.4 Moved from PLL_Admin_Model class.
191 297 *
192 - * @param WP_Term[] $terms Array of terms for the given object or objects.
193 - * @param int[] $object_ids Array of object IDs for which terms were retrieved.
194 - * @param string[] $taxonomies Array of taxonomy names from which terms were retrieved.
195 - * @return WP_Term[] Unmodified $terms.
298 + * @param int[] $ids Array of post ids or term ids.
299 + * @param PLL_Language $lang Language to assign to the posts or terms.
300 + * @return void
196 301 */
197 - public function wp_get_object_terms( $terms, $object_ids, $taxonomies ) {
198 - if ( ! in_array( 'term_translations', $taxonomies ) ) {
199 - $this->_prime_terms_cache( $terms, $taxonomies );
302 + public function set_language_in_mass( $ids, $lang ) {
303 + parent::set_language_in_mass( $ids, $lang );
304 +
305 + $translations = array();
306 +
307 + foreach ( $ids as $id ) {
308 + $translations[] = array( $lang->slug => $id );
200 309 }
201 - return $terms;
310 +
311 + if ( ! empty( $translations ) ) {
312 + $this->set_translation_in_mass( $translations );
313 + }
202 314 }
203 315
204 316 /**
205 - * When the term cache is cleaned, cleans the object term cache too.
317 + * Returns database-related information that can be used in some of this class methods.
318 + * These are specific to the table containing the objects.
206 319 *
207 - * @since 2.0
320 + * @see PLL_Translatable_Object::join_clause()
321 + * @see PLL_Translatable_Object::get_objects_with_no_lang_sql()
208 322 *
209 - * @param int[] $ids An array of term IDs.
210 - * @return void
323 + * @since 3.4.3
324 + *
325 + * @return string[] {
326 + * @type string $table Name of the table.
327 + * @type string $id_column Name of the column containing the object's ID.
328 + * @type string $type_column Name of the column containing the object's type.
329 + * @type string $default_alias Default alias corresponding to the object's table.
330 + * }
331 + * @phpstan-return DBInfoWithType
211 332 */
212 - public function clean_term_cache( $ids ) {
213 - clean_object_term_cache( $ids, 'term' );
333 + protected function get_db_infos() {
334 + return array(
335 + 'table' => $GLOBALS['wpdb']->term_taxonomy,
336 + 'id_column' => 'term_id',
337 + 'type_column' => 'taxonomy',
338 + 'default_alias' => 't',
339 + );
214 340 }
215 341 }