PluginProbe
Polylang / 1.7.3
Polylang v1.7.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 / admin / admin-sync.php

admin-sync.php in Polylang 1.7.3, at admin/admin-sync.php

271 lines 9.5 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
10 /*
11 * constructor
12 *
13 * @since 1.2
14 *
15 * @param object $polylang
16 */
17 public function __construct(&$polylang) {
18 $this->model = &$polylang->model;
19 $this->options = &$polylang->options;
20
21 add_filter('wp_insert_post_parent', array(&$this, 'wp_insert_post_parent'));
22 add_action('add_meta_boxes', array(&$this, 'add_meta_boxes'), 5, 2); // before Types which populates custom fields in same hook with priority 10
23
24 add_action('pll_save_post', array(&$this, 'pll_save_post'), 10, 3);
25 add_action('pll_save_term', array(&$this, 'pll_save_term'), 10, 3);
26 }
27
28 /*
29 * translate post parent if exists when using "Add new" (translation)
30 *
31 * @since 0.6
32 */
33 function wp_insert_post_parent($post_parent) {
34 return isset($_GET['from_post'], $_GET['new_lang']) && ($id = wp_get_post_parent_id((int) $_GET['from_post'])) && ($parent = $this->model->get_translation('post', $id, $_GET['new_lang'])) ? $parent : $post_parent;
35 }
36
37 /*
38 * copy post metas, menu order, comment and ping status when using "Add new" (translation)
39 * formerly used dbx_post_advanced deprecated in WP 3.7
40 *
41 * @since 1.2
42 *
43 * @param string $post_type unused
44 * @param object $post current post object
45 */
46 function add_meta_boxes($post_type, $post) {
47 if ('post-new.php' == $GLOBALS['pagenow'] && isset($_GET['from_post'], $_GET['new_lang'])) {
48 if (!$this->model->is_translated_post_type($post->post_type))
49 return;
50
51 // capability check already done in post-new.php
52 $from_post_id = (int) $_GET['from_post'];
53 $lang = $this->model->get_language($_GET['new_lang']);
54
55 $this->copy_post_metas($from_post_id, $post->ID, $lang->slug);
56
57 $from_post = get_post($from_post_id);
58 foreach (array('menu_order', 'comment_status', 'ping_status') as $property)
59 $post->$property = $from_post->$property;
60
61 if (in_array('sticky_posts', $this->options['sync']) && is_sticky($from_post_id))
62 stick_post($post->ID);
63 }
64 }
65
66 /*
67 * get the list of taxonomies to copy or to synchronize
68 *
69 * @since 1.7
70 *
71 * @param bool $sync true if it is synchronization, false if it is a copy
72 * @return array list of taxonomy names
73 */
74 public function get_taxonomies_to_copy($sync) {
75 $taxonomies = !$sync || in_array('taxonomies', $this->options['sync']) ? $this->model->get_translated_taxonomies() : array();
76 if (!$sync || in_array('post_format', $this->options['sync']))
77 $taxonomies[] = 'post_format';
78
79 return array_unique(apply_filters('pll_copy_taxonomies', $taxonomies, $sync));
80 }
81
82
83 /*
84 * copy or synchronize terms and metas
85 *
86 * @since 0.9
87 *
88 * @param int $from id of the post from which we copy informations
89 * @param int $to id of the post to which we paste informations
90 * @param string $lang language slug
91 * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
92 */
93 public function copy_post_metas($from, $to, $lang, $sync = false) {
94 // copy or synchronize terms
95 // FIXME quite a lot of query in foreach
96 foreach ($this->get_taxonomies_to_copy($sync) as $tax) {
97 $terms = get_the_terms($from, $tax);
98
99 // translated taxonomy
100 if ($this->model->is_translated_taxonomy($tax)) {
101 $newterms = array();
102 if (is_array($terms)) {
103 foreach ($terms as $term) {
104 if ($term_id = $this->model->get_translation('term', $term->term_id, $lang))
105 $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
106 }
107 }
108
109 // for some reasons, the user may have untranslated terms in the translation. don't forget them.
110 if ($sync) {
111 $tr_terms = get_the_terms($to, $tax);
112 if (is_array($tr_terms)) {
113 foreach ($tr_terms as $term) {
114 if (!$this->model->get_translation('term', $term->term_id, $this->model->get_post_language($from)))
115 $newterms[] = (int) $term->term_id;
116 }
117 }
118 }
119
120 if (!empty($newterms) || $sync)
121 wp_set_object_terms($to, $newterms, $tax); // replace terms in translation
122 }
123
124 // untranslated taxonomy (post format)
125 // don't use simple get_post_format / set_post_format to generalize the case to other taxonomies
126 else {
127 wp_set_object_terms($to, is_array($terms) ? array_map('intval', wp_list_pluck($terms, 'term_id')) : null, $tax);
128 }
129 }
130
131 // copy or synchronize post metas and allow plugins to do the same
132 $metas = get_post_custom($from);
133
134 // get public meta keys (including from translated post in case we just deleted a custom field)
135 if (!$sync || in_array('post_meta', $this->options['sync'])) {
136 foreach ($keys = array_unique(array_merge(array_keys($metas), array_keys(get_post_custom($to)))) as $k => $meta_key)
137 if (is_protected_meta($meta_key))
138 unset ($keys[$k]);
139 }
140
141 // add page template and featured image
142 foreach (array('_wp_page_template', '_thumbnail_id') as $meta)
143 if (!$sync || in_array($meta, $this->options['sync']))
144 $keys[] = $meta;
145
146 $keys = array_unique(apply_filters('pll_copy_post_metas', empty($keys) ? array() : $keys, $sync));
147
148 // and now copy / synchronize
149 foreach ($keys as $key) {
150 delete_post_meta($to, $key); // the synchronization process of multiple values custom fields is easier if we delete all metas first
151 if (isset($metas[$key])) {
152 foreach ($metas[$key] as $value) {
153 // important: always maybe_unserialize value coming from get_post_custom. See codex.
154 // thanks to goncalveshugo http://wordpress.org/support/topic/plugin-polylang-pll_copy_post_meta
155 $value = maybe_unserialize($value);
156 // special case for featured images which can be translated
157 add_post_meta($to, $key, ($key == '_thumbnail_id' && $tr_value = $this->model->get_translation('post', $value, $lang)) ? $tr_value : $value);
158 }
159 }
160 }
161 }
162
163 /*
164 * synchronizes terms and metas in translations
165 *
166 * @since 1.2
167 *
168 * @param int $post_id post id
169 * @param object $post post object
170 * @param array translations post translations
171 */
172 public function pll_save_post($post_id, $post, $translations) {
173 global $wpdb;
174
175 // prepare properties to synchronize
176 foreach (array('comment_status', 'ping_status', 'menu_order', 'post_date') as $property)
177 if (in_array($property, $this->options['sync']))
178 $postarr[$property] = $post->$property;
179
180 if (in_array('post_date', $this->options['sync']))
181 $post_arr['post_date_gmt'] = $post->post_date_gmt;
182
183 // synchronise terms and metas in translations
184 foreach ($translations as $lang => $tr_id) {
185 if (!$tr_id)
186 continue;
187
188 // synchronize terms and metas
189 $this->copy_post_metas($post_id, $tr_id, $lang, true);
190
191 // sticky posts
192 if (in_array('sticky_posts', $this->options['sync']))
193 isset($_REQUEST['sticky']) ? stick_post($tr_id) : unstick_post($tr_id);
194
195 // synchronize comment status, ping status, menu order...
196 if (!empty($postarr))
197 $wpdb->update($wpdb->posts, $postarr, array('ID' => $tr_id));
198
199 // FIXME: optimize the 2 db update in 1
200 // post parent
201 // do not udpate the translation parent if the user set a parent with no translation
202 if (in_array('post_parent', $this->options['sync'])) {
203 $post_parent = ($parent_id = wp_get_post_parent_id($post_id)) ? $this->model->get_translation('post', $parent_id, $lang) : 0;
204 if (!($parent_id && !$post_parent))
205 $wpdb->update($wpdb->posts, array('post_parent'=> $post_parent), array( 'ID' => $tr_id ));
206 }
207 }
208 }
209
210 /*
211 * synchronize translations of a term in all posts
212 *
213 * @since 1.2
214 *
215 * @param int $term_id term id
216 * @param string $taxonomy taxonomy name of the term
217 * @param array $translations translations of the term
218 */
219 public function pll_save_term($term_id, $taxonomy, $translations) {
220 // check if the taxonomy is synchronized
221 if (!$this->model->is_translated_taxonomy($taxonomy) || !in_array($taxonomy, $this->get_taxonomies_to_copy(true)))
222 return;
223
224 // get all posts associated to this term
225 $posts = get_posts(array(
226 'numberposts' => -1,
227 'nopaging' => true,
228 'post_type' => 'any',
229 'post_status' => 'any',
230 'fields' => 'ids',
231 'tax_query' => array(array(
232 'taxonomy' => $taxonomy,
233 'field' => 'id',
234 'terms' => array_merge(array($term_id), array_values($translations)),
235 ))
236 ));
237
238 // associate translated term to translated post
239 // FIXME quite a lot of query in foreach
240 foreach ($this->model->get_languages_list() as $language) {
241 if ($translated_term = $this->model->get_term($term_id, $language)) {
242 foreach ($posts as $post_id) {
243 if ($translated_post = $this->model->get_post($post_id, $language))
244 wp_set_object_terms($translated_post, $translated_term, $taxonomy, true);
245 }
246 }
247 }
248
249 // synchronize parent in translations
250 // calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
251 // but clean_term_cache can be called (efficiently) only one time due to static array which prevents to update the option more than once
252 // this is the reason to use the edit_term filter and not edited_term
253 // take care that $_POST contains the only valid values for the current term
254 // FIXME can I synchronize parent without using $_POST instead?
255 if (isset($_POST['term_tr_lang'])) {
256 foreach ($_POST['term_tr_lang'] as $lang => $tr_id) {
257 if (!$tr_id)
258 continue;
259
260 if (isset($_POST['parent']) && $_POST['parent'] != -1) // since WP 3.1
261 $term_parent = $this->model->get_translation('term', (int) $_POST['parent'], $lang);
262
263 global $wpdb;
264 $wpdb->update($wpdb->term_taxonomy,
265 array('parent'=> isset($term_parent) ? $term_parent : 0),
266 array('term_taxonomy_id' => get_term((int) $tr_id, $taxonomy)->term_taxonomy_id));
267 }
268 }
269 }
270 }
271