PluginProbe
Polylang / 3.7.7
Polylang v3.7.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
polylang / modules / sync / sync.php

sync.php in Polylang 3.7.7, at modules/sync/sync.php

279 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Manages copy and synchronization of terms and post metas on front
8 *
9 * @since 2.4
10 */
11 class PLL_Sync {
12 /**
13 * @var PLL_Sync_Tax
14 */
15 public $taxonomies;
16
17 /**
18 * @var PLL_Sync_Post_Metas
19 */
20 public $post_metas;
21
22 /**
23 * @var PLL_Sync_Term_Metas
24 */
25 public $term_metas;
26
27 /**
28 * Stores the plugin options.
29 *
30 * @var array
31 */
32 protected $options;
33
34 /**
35 * @var PLL_Model
36 */
37 protected $model;
38
39 /**
40 * Constructor
41 *
42 * @since 1.2
43 *
44 * @param object $polylang The Polylang object.
45 */
46 public function __construct( &$polylang ) {
47 $this->model = &$polylang->model;
48 $this->options = &$polylang->options;
49
50 $this->taxonomies = new PLL_Sync_Tax( $polylang );
51 $this->post_metas = new PLL_Sync_Post_Metas( $polylang );
52 $this->term_metas = new PLL_Sync_Term_Metas( $polylang );
53
54 add_filter( 'wp_insert_post_parent', array( $this, 'can_sync_post_parent' ), 10, 3 );
55 add_filter( 'wp_insert_post_data', array( $this, 'can_sync_post_data' ), 10, 2 );
56
57 add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
58 add_action( 'created_term', array( $this, 'sync_term_parent' ), 10, 3 );
59 add_action( 'edited_term', array( $this, 'sync_term_parent' ), 10, 3 );
60
61 add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 );
62
63 if ( $this->options['media_support'] ) {
64 add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
65 add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
66 add_action( 'edit_attachment', array( $this, 'edit_attachment' ) );
67 }
68
69 add_filter( 'pre_update_option_sticky_posts', array( $this, 'sync_sticky_posts' ), 10, 2 );
70 }
71
72 /**
73 * Get post fields to synchronize.
74 *
75 * @since 2.4
76 *
77 * @param WP_Post $post Post object.
78 * @return array
79 */
80 protected function get_fields_to_sync( $post ) {
81 $postarr = array();
82
83 foreach ( array( 'comment_status', 'ping_status', 'menu_order' ) as $property ) {
84 if ( in_array( $property, $this->options['sync'] ) ) {
85 $postarr[ $property ] = $post->$property;
86 }
87 }
88
89 if ( in_array( 'post_date', $this->options['sync'] ) ) {
90 $postarr['post_date'] = $post->post_date;
91 $postarr['post_date_gmt'] = $post->post_date_gmt;
92 }
93
94 if ( in_array( 'post_parent', $this->options['sync'] ) ) {
95 $postarr['post_parent'] = wp_get_post_parent_id( $post->ID );
96 }
97
98 return $postarr;
99 }
100
101 /**
102 * Prevents synchronized post parent modification if the current user hasn't enough rights
103 *
104 * @since 2.6
105 *
106 * @param int $post_parent Post parent ID
107 * @param int $post_id Post ID, unused
108 * @param array $postarr Array of parsed post data
109 * @return int
110 */
111 public function can_sync_post_parent( $post_parent, $post_id, $postarr ) {
112 if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) {
113 $tr_ids = $this->model->post->get_translations( $postarr['ID'] );
114 foreach ( $tr_ids as $tr_id ) {
115 if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) {
116 $post_parent = $post->post_parent;
117 break;
118 }
119 }
120 }
121 return $post_parent;
122 }
123
124 /**
125 * Prevents synchronized post data modification if the current user hasn't enough rights
126 *
127 * @since 2.6
128 *
129 * @param array $data An array of slashed post data.
130 * @param array $postarr An array of sanitized, but otherwise unmodified post data.
131 * @return array
132 */
133 public function can_sync_post_data( $data, $postarr ) {
134 if ( ! empty( $postarr['ID'] ) && ! $this->model->post->current_user_can_synchronize( $postarr['ID'] ) ) {
135 foreach ( $this->model->post->get_translations( $postarr['ID'] ) as $tr_id ) {
136 if ( $tr_id !== $postarr['ID'] && $post = get_post( $tr_id ) ) {
137 $to_sync = $this->get_fields_to_sync( $post );
138 $data = array_merge( $data, $to_sync );
139 break;
140 }
141 }
142 }
143 return $data;
144 }
145
146 /**
147 * Synchronizes post fields in translations.
148 *
149 * @since 2.4
150 *
151 * @param int $post_id Post id.
152 * @param WP_Post $post Post object.
153 * @param int[] $translations Post translations.
154 * @return void
155 */
156 public function pll_save_post( $post_id, $post, $translations ) {
157 global $wpdb;
158
159 if ( $this->model->post->current_user_can_synchronize( $post_id ) ) {
160 $postarr = $this->get_fields_to_sync( $post );
161
162 if ( ! empty( $postarr ) ) {
163 foreach ( $translations as $lang => $tr_id ) {
164 if ( ! $tr_id || $tr_id === $post_id ) {
165 continue;
166 }
167
168 $tr_arr = $postarr;
169 unset( $tr_arr['post_parent'] );
170
171 // Do not update the translation parent if the user set a parent with no translation.
172 if ( isset( $postarr['post_parent'] ) ) {
173 $post_parent = $postarr['post_parent'] ? $this->model->post->get_translation( $postarr['post_parent'], $lang ) : 0;
174 if ( ! ( $postarr['post_parent'] && ! $post_parent ) ) {
175 $tr_arr['post_parent'] = $post_parent;
176 }
177 }
178
179 // Update all the rows at once.
180 if ( ! empty( $tr_arr ) ) {
181 // Don't use wp_update_post to avoid infinite loop.
182 $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
183 clean_post_cache( $tr_id );
184 }
185 }
186 }
187 }
188 }
189
190 /**
191 * Synchronize term parent in translations.
192 * Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
193 *
194 * @since 2.3
195 *
196 * @param int $term_id Term id.
197 * @param int $tt_id Term taxonomy id, not used.
198 * @param string $taxonomy Taxonomy name.
199 * @return void
200 */
201 public function sync_term_parent( $term_id, $tt_id, $taxonomy ) {
202 global $wpdb;
203
204 if ( ! is_taxonomy_hierarchical( $taxonomy ) || ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
205 return;
206 }
207
208 $term = get_term( $term_id );
209 if ( ! $term instanceof WP_Term ) {
210 return;
211 }
212
213 $translations = $this->model->term->get_translations( $term_id );
214
215 foreach ( $translations as $lang => $tr_id ) {
216 if ( $tr_id === $term_id ) {
217 continue;
218 }
219
220 $tr_parent = $this->model->term->get_translation( $term->parent, $lang );
221 $tr_term = get_term( (int) $tr_id, $taxonomy );
222
223 if ( str_starts_with( current_filter(), 'created_' ) && 0 === $tr_parent ) {
224 // Do not remove the existing hierarchy of translations when creating new term without parent.
225 continue;
226 }
227
228 if ( $tr_term instanceof WP_Term && ! ( $term->parent && empty( $tr_parent ) ) ) {
229 $wpdb->update(
230 $wpdb->term_taxonomy,
231 array( 'parent' => $tr_parent ?: 0 ),
232 array( 'term_taxonomy_id' => $tr_term->term_taxonomy_id )
233 );
234
235 clean_term_cache( $tr_id, $taxonomy ); // OK since WP 3.9.
236 }
237 }
238 }
239
240 /**
241 * Synchronizes terms and metas in translations for media
242 *
243 * @since 1.8
244 *
245 * @param int $post_id post id
246 * @return void
247 */
248 public function edit_attachment( $post_id ) {
249 $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
250 }
251
252 /**
253 * Synchronize sticky posts.
254 *
255 * @since 2.3
256 *
257 * @param int[] $value New option value.
258 * @param int[] $old_value Old option value.
259 * @return int[]
260 */
261 public function sync_sticky_posts( $value, $old_value ) {
262 if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
263 // Stick post
264 if ( $sticked = array_diff( $value, $old_value ) ) {
265 $translations = $this->model->post->get_translations( reset( $sticked ) );
266 $value = array_unique( array_merge( $value, array_values( $translations ) ) );
267 }
268
269 // Unstick post
270 if ( $unsticked = array_diff( $old_value, $value ) ) {
271 $translations = $this->model->post->get_translations( reset( $unsticked ) );
272 $value = array_unique( array_diff( $value, array_values( $translations ) ) );
273 }
274 }
275
276 return $value;
277 }
278 }
279