PluginProbe
Polylang / 3.8.3
Polylang v3.8.3
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 / src / modules / sync / sync.php

sync.php in Polylang 3.8.3, at src/modules/sync/sync.php

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