PluginProbe
Polylang / 2.3.10
Polylang v2.3.10
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 / admin-sync.php

admin-sync.php in Polylang 2.3.10, at modules/sync/admin-sync.php

280 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Manages copy and synchronization of terms and post metas
5 *
6 * @since 1.2
7 */
8 class PLL_Admin_Sync {
9 public $taxonomies, $post_metas, $term_meta;
10
11 /**
12 * Constructor
13 *
14 * @since 1.2
15 *
16 * @param object $polylang
17 */
18 public function __construct( &$polylang ) {
19 $this->model = &$polylang->model;
20 $this->options = &$polylang->options;
21
22 $this->taxonomies = new PLL_Sync_Tax( $polylang );
23 $this->post_metas = new PLL_Sync_Post_Metas( $polylang );
24 $this->term_metas = new PLL_Sync_Term_Metas( $polylang );
25
26 add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 3 );
27 add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 5, 2 ); // Before Types which populates custom fields in same hook with priority 10
28
29 add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
30 add_action( 'pll_save_term', array( $this, 'sync_term_parent' ), 10, 3 );
31
32 add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 );
33
34 if ( $this->options['media_support'] ) {
35 add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
36 add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
37 add_action( 'edit_attachment', array( $this, 'edit_attachment' ) );
38 }
39
40 add_filter( 'pre_update_option_sticky_posts', array( $this, 'sync_sticky_posts' ), 10, 2 );
41 }
42
43 /**
44 * Translate post parent if exists when using "Add new" ( translation )
45 *
46 * @since 0.6
47 *
48 * @param int $post_parent Post parent ID
49 * @param int $post_id Post ID, unused
50 * @param array $postarr Array of parsed post data
51 * @return int
52 */
53 public function wp_insert_post_parent( $post_parent, $post_id, $postarr ) {
54 // Make sure not to impact media translations created at the same time
55 return isset( $_GET['from_post'], $_GET['new_lang'], $_GET['post_type'] ) && $_GET['post_type'] === $postarr['post_type'] && ( $id = wp_get_post_parent_id( (int) $_GET['from_post'] ) ) && ( $parent = $this->model->post->get_translation( $id, $_GET['new_lang'] ) ) ? $parent : $post_parent;
56 }
57
58 /**
59 * Copy post metas, menu order, comment and ping status when using "Add new" ( translation )
60 * formerly used dbx_post_advanced deprecated in WP 3.7
61 *
62 * @since 1.2
63 *
64 * @param string $post_type unused
65 * @param object $post current post object
66 */
67 public function add_meta_boxes( $post_type, $post ) {
68 if ( 'post-new.php' == $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) && $this->model->is_translated_post_type( $post->post_type ) ) {
69 // Capability check already done in post-new.php
70 $from_post_id = (int) $_GET['from_post'];
71 $from_post = get_post( $from_post_id );
72 $lang = $this->model->get_language( $_GET['new_lang'] );
73
74 if ( ! $from_post || ! $lang ) {
75 return;
76 }
77
78 $this->taxonomies->copy( $from_post_id, $post->ID, $lang->slug );
79 $this->post_metas->copy( $from_post_id, $post->ID, $lang->slug );
80
81 foreach ( array( 'menu_order', 'comment_status', 'ping_status' ) as $property ) {
82 $post->$property = $from_post->$property;
83 }
84
85 // Copy the date only if the synchronization is activated
86 if ( in_array( 'post_date', $this->options['sync'] ) ) {
87 $post->post_date = $from_post->post_date;
88 $post->post_date_gmt = $from_post->post_date_gmt;
89 }
90
91 if ( is_sticky( $from_post_id ) ) {
92 stick_post( $post->ID );
93 }
94 }
95 }
96
97 /**
98 * Synchronizes post fields in translations
99 *
100 * @since 1.2
101 *
102 * @param int $post_id post id
103 * @param object $post post object
104 * @param array $translations post translations
105 */
106 public function pll_save_post( $post_id, $post, $translations ) {
107 global $wpdb;
108
109 // Prepare properties to synchronize
110 foreach ( array( 'comment_status', 'ping_status', 'menu_order' ) as $property ) {
111 if ( in_array( $property, $this->options['sync'] ) ) {
112 $postarr[ $property ] = $post->$property;
113 }
114 }
115
116 if ( in_array( 'post_date', $this->options['sync'] ) ) {
117 // For new drafts, save the date now otherwise it is overriden by WP. Thanks to JoryHogeveen. See #32.
118 if ( 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) {
119 $original = get_post( (int) $_GET['from_post'] );
120 $wpdb->update(
121 $wpdb->posts, array(
122 'post_date' => $original->post_date,
123 'post_date_gmt' => $original->post_date_gmt,
124 ),
125 array( 'ID' => $post_id )
126 );
127 } else {
128 $postarr['post_date'] = $post->post_date;
129 $postarr['post_date_gmt'] = $post->post_date_gmt;
130 }
131 }
132
133 foreach ( $translations as $lang => $tr_id ) {
134 if ( ! $tr_id || $tr_id === $post_id ) {
135 continue;
136 }
137
138 // Add comment status, ping status, menu order... to synchronization
139 $tr_arr = empty( $postarr ) ? array() : $postarr;
140
141 if ( isset( $GLOBALS['post_type'] ) ) {
142 $post_type = $GLOBALS['post_type'];
143 } elseif ( isset( $_REQUEST['post_type'] ) ) {
144 $post_type = $_REQUEST['post_type']; // 2nd case for quick edit
145 }
146
147 // Add post parent to synchronization
148 // Make sure not to impact media translations when creating them at the same time as post
149 // Do not udpate the translation parent if the user set a parent with no translation
150 if ( in_array( 'post_parent', $this->options['sync'] ) && isset( $post_type ) && $post_type === $post->post_type ) {
151 $post_parent = ( $parent_id = wp_get_post_parent_id( $post_id ) ) ? $this->model->post->get_translation( $parent_id, $lang ) : 0;
152 if ( ! ( $parent_id && ! $post_parent ) ) {
153 $tr_arr['post_parent'] = $post_parent;
154 }
155 }
156
157 // Update all the row at once
158 // Don't use wp_update_post to avoid infinite loop
159 if ( ! empty( $tr_arr ) ) {
160 $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
161 clean_post_cache( $tr_id );
162 }
163 }
164
165 // Sticky posts
166 if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
167 $stickies = get_option( 'sticky_posts' );
168 if ( isset( $_REQUEST['sticky'] ) && 'sticky' === $_REQUEST['sticky'] ) {
169 $stickies = array_merge( $stickies, array_values( $translations ) );
170 } else {
171 $stickies = array_diff( $stickies, array_values( $translations ) );
172 }
173 update_option( 'sticky_posts', array_unique( $stickies ) );
174 }
175 }
176
177 /**
178 * Synchronize term parent in translations
179 * Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
180 * Before WP 3.9 clean_term_cache could be called ( efficiently ) only one time due to static array which prevented to update the option more than once
181 * This is the reason to use the edit_term filter and not edited_term
182 *
183 * @since 2.3
184 *
185 * @param int $term_id Term id
186 * @param string $taxonomy Taxonomy name
187 * @param array $translations The list of translations term ids
188 */
189 public function sync_term_parent( $term_id, $taxonomy, $translations ) {
190 global $wpdb;
191
192 if ( is_taxonomy_hierarchical( $taxonomy ) && $this->model->is_translated_taxonomy( $taxonomy ) ) {
193 $term = get_term( $term_id );
194
195 foreach ( $translations as $lang => $tr_id ) {
196 if ( ! empty( $tr_id ) && $tr_id !== $term_id ) {
197 $tr_parent = $this->model->term->get_translation( $term->parent, $lang );
198
199 $wpdb->update(
200 $wpdb->term_taxonomy,
201 array( 'parent' => isset( $tr_parent ) ? $tr_parent : 0 ),
202 array( 'term_taxonomy_id' => get_term( (int) $tr_id, $taxonomy )->term_taxonomy_id )
203 );
204
205 clean_term_cache( $tr_id, $taxonomy ); // OK since WP 3.9
206 }
207 }
208 }
209 }
210
211 /**
212 * Synchronizes terms and metas in translations for media
213 *
214 * @since 1.8
215 *
216 * @param int $post_id post id
217 */
218 public function edit_attachment( $post_id ) {
219 $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
220 }
221
222 /**
223 * Synchronize sticky posts
224 *
225 * @since 2.3
226 *
227 * @param array $value New option value
228 * @param array $old_value Old option value
229 * @return array
230 */
231 public function sync_sticky_posts( $value, $old_value ) {
232 if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
233 // Stick post
234 if ( $sticked = array_diff( $value, $old_value ) ) {
235 $translations = $this->model->post->get_translations( reset( $sticked ) );
236 $value = array_unique( array_merge( $value, array_values( $translations ) ) );
237 }
238
239 // Unstick post
240 if ( $unsticked = array_diff( $old_value, $value ) ) {
241 $translations = $this->model->post->get_translations( reset( $unsticked ) );
242 $value = array_unique( array_diff( $value, array_values( $translations ) ) );
243 }
244 }
245
246 return $value;
247 }
248
249 /**
250 * Some backward compatibility with Polylang < 2.3
251 * allows to call PLL()->sync->copy_post_metas() and PLL()->sync->copy_taxonomies()
252 * used for example in Polylang for WooCommerce
253 * the compatibility is however only partial as the 4th argument $sync is lost
254 *
255 * @since 2.3
256 *
257 * @param string $func Function name
258 * @param array $args Function arguments
259 */
260 public function __call( $func, $args ) {
261 $obj = substr( $func, 5 );
262
263 if ( is_object( $this->$obj ) && method_exists( $this->$obj, 'copy' ) ) {
264 if ( WP_DEBUG ) {
265 $debug = debug_backtrace();
266 $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
267
268 trigger_error( sprintf(
269 '%1$s was called incorrectly in %3$s on line %4$s: the call to PLL()->sync->%1$s() has been deprecated in Polylang 2.3, use PLL()->sync->%2$s->copy() instead.' . "\nError handler",
270 $func, $obj, $debug[ $i ]['file'], $debug[ $i ]['line']
271 ) );
272 }
273 return call_user_func_array( array( $this->$obj, 'copy' ), $args );
274 }
275
276 $debug = debug_backtrace();
277 trigger_error( sprintf( 'Call to undefined function PLL()->sync->%1$s() in %2$s on line %3$s' . "\nError handler", $func, $debug[0]['file'], $debug[0]['line'] ), E_USER_ERROR );
278 }
279 }
280