PluginProbe
Polylang / 2.3.6
Polylang v2.3.6
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.6, at modules/sync/admin-sync.php

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