PluginProbe
Polylang / 2.4
Polylang v2.4
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 / include / crud-posts.php

crud-posts.php in Polylang 2.4, at include/crud-posts.php

235 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Adds actions and filters related to languages when creating, updating or deleting posts
5 * Actions a filters used when reaing posts are handled separately
6 *
7 * @since 2.4
8 */
9 class PLL_CRUD_Posts {
10
11 /**
12 * Constructor
13 *
14 * @since 2.4
15 *
16 * @param object $polylang
17 */
18 public function __construct( &$polylang ) {
19 $this->model = &$polylang->model;
20 $this->pref_lang = &$polylang->pref_lang;
21 $this->curlang = &$polylang->curlang;
22
23 add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
24 add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 4 );
25 add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 4 );
26 add_action( 'before_delete_post', array( $this, 'delete_post' ) );
27
28 // Specific for media
29 if ( $polylang->options['media_support'] ) {
30 add_action( 'add_attachment', array( $this, 'set_default_language' ) );
31 add_action( 'delete_attachment', array( $this, 'delete_post' ) );
32 add_filter( 'wp_delete_file', array( $this, 'wp_delete_file' ) );
33 }
34 }
35
36 /**
37 * Allows to set a language by default for posts if it has no language yet
38 *
39 * @since 1.5
40 *
41 * @param int $post_id
42 */
43 public function set_default_language( $post_id ) {
44 if ( ! $this->model->post->get_language( $post_id ) ) {
45 if ( ! empty( $_GET['new_lang'] ) && $lang = $this->model->get_language( $_GET['new_lang'] ) ) {
46 // Defined only on admin.
47 $this->model->post->set_language( $post_id, $lang );
48 } elseif ( ! isset( $this->pref_lang ) && ! empty( $_REQUEST['lang'] ) && $lang = $this->model->get_language( $_REQUEST['lang'] ) ) {
49 // Testing $this->pref_lang makes this test pass only on admin.
50 $this->model->post->set_language( $post_id, $lang );
51 } elseif ( ( $parent_id = wp_get_post_parent_id( $post_id ) ) && $parent_lang = $this->model->post->get_language( $parent_id ) ) {
52 $this->model->post->set_language( $post_id, $parent_lang );
53 } elseif ( isset( $this->pref_lang ) ) {
54 // Always defined on admin, never defined on frontend
55 $this->model->post->set_language( $post_id, $this->pref_lang );
56 } else {
57 // Only on frontend due to the previous test always true on admin
58 $this->model->post->set_language( $post_id, $this->curlang );
59 }
60 }
61 }
62
63 /**
64 * Called when a post ( or page ) is saved, published or updated
65 *
66 * @since 0.1
67 * @since 2.3 Does not save the language and translations anymore, unless the post has no language yet
68 *
69 * @param int $post_id
70 * @param object $post
71 */
72 public function save_post( $post_id, $post ) {
73 // Does nothing except on post types which are filterable
74 if ( $this->model->is_translated_post_type( $post->post_type ) ) {
75 if ( $id = wp_is_post_revision( $post_id ) ) {
76 $post_id = $id;
77 }
78
79 $lang = $this->model->post->get_language( $post_id );
80
81 if ( empty( $lang ) ) {
82 $this->set_default_language( $post_id );
83 }
84
85 /**
86 * Fires after the post language and translations are saved
87 *
88 * @since 1.2
89 *
90 * @param int $post_id Post id
91 * @param object $post Post object
92 * @param array $translations The list of translations post ids
93 */
94 do_action( 'pll_save_post', $post_id, $post, $this->model->post->get_translations( $post_id ) );
95 }
96 }
97
98 /**
99 * Make sure saved terms are in the right language (especially tags with same name in different languages)
100 *
101 * @since 2.3
102 *
103 * @param int $object_id Object ID.
104 * @param array $terms An array of object terms.
105 * @param array $tt_ids An array of term taxonomy IDs.
106 * @param string $taxonomy Taxonomy slug.
107 */
108 public function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy ) {
109 static $avoid_recursion;
110
111 if ( ! $avoid_recursion && $this->model->is_translated_taxonomy( $taxonomy ) && ! empty( $terms ) ) {
112 $lang = $this->model->post->get_language( $object_id );
113
114 if ( ! empty( $lang ) && is_array( $terms ) ) {
115 // Convert to term ids if we got tag names
116 $strings = array_filter( $terms, 'is_string' );
117 if ( ! empty( $strings ) ) {
118 $_terms = get_terms( $taxonomy, array( 'name' => $strings, 'object_ids' => $object_id, 'fields' => 'ids' ) );
119 $terms = array_merge( array_diff( $terms, $strings ), $_terms );
120 }
121
122 $term_ids = array_combine( $terms, $terms );
123 $languages = array_map( array( $this->model->term, 'get_language' ), $term_ids );
124 $languages = wp_list_pluck( $languages, 'slug' );
125 $wrong_terms = array_diff( $languages, array( $lang->slug ) );
126
127 if ( ! empty( $wrong_terms ) ) {
128 // We got terms in a wrong language
129 $wrong_term_ids = array_keys( $wrong_terms );
130 $terms = get_the_terms( $object_id, $taxonomy );
131 wp_remove_object_terms( $object_id, $wrong_term_ids, $taxonomy );
132
133 if ( is_array( $terms ) ) {
134 $newterms = array();
135
136 foreach ( $terms as $term ) {
137 if ( in_array( $term->term_id, $wrong_term_ids ) ) {
138 // Check if the term is in the correct language or if a translation exist ( mainly for default category )
139 if ( $newterm = $this->model->term->get( $term->term_id, $lang ) ) {
140 $newterms[] = (int) $newterm;
141 }
142
143 // Or choose the correct language for tags ( initially defined by name )
144 elseif ( $newterm = $this->model->term_exists( $term->name, $taxonomy, $term->parent, $lang ) ) {
145 $newterms[] = (int) $newterm; // Cast is important otherwise we get 'numeric' tags
146 }
147
148 // Or create the term in the correct language
149 elseif ( ! is_wp_error( $term_info = wp_insert_term( $term->name, $taxonomy ) ) ) {
150 $newterms[] = (int) $term_info['term_id'];
151 }
152 }
153 }
154
155 $avoid_recursion = true;
156 wp_set_object_terms( $object_id, array_unique( $newterms ), $taxonomy, true ); // Append
157 $avoid_recursion = false;
158 }
159 }
160 }
161 }
162 }
163
164 /**
165 * Make sure that the post parent is in the correct language when using bulk edit
166 *
167 * @since 1.8
168 *
169 * @param int $post_parent Post parent ID.
170 * @param int $post_id Post ID.
171 * @param array $new_postarr Array of parsed post data.
172 * @param array $postarr Array of sanitized, but otherwise unmodified post data.
173 * @return int
174 */
175 public function wp_insert_post_parent( $post_parent, $post_id, $new_postarr, $postarr ) {
176 if ( isset( $postarr['bulk_edit'], $postarr['inline_lang_choice'] ) ) {
177 check_admin_referer( 'bulk-posts' );
178 $lang = -1 == $postarr['inline_lang_choice'] ?
179 $this->model->post->get_language( $post_id ) :
180 $this->model->get_language( $postarr['inline_lang_choice'] );
181 // Dont break the hierarchy in case the post has no language
182 if ( ! empty( $lang ) ) {
183 $post_parent = $this->model->post->get_translation( $post_parent, $lang );
184 }
185 }
186 return $post_parent;
187 }
188
189 /**
190 * Called when a post, page or media is deleted
191 * Don't delete translations if this is a post revision thanks to AndyDeGroo who catched this bug
192 * http://wordpress.org/support/topic/plugin-polylang-quick-edit-still-breaks-translation-linking-of-pages-in-072
193 *
194 * @since 0.1
195 *
196 * @param int $post_id
197 */
198 public function delete_post( $post_id ) {
199 if ( ! wp_is_post_revision( $post_id ) ) {
200 $this->model->post->delete_translation( $post_id );
201 }
202 }
203
204 /**
205 * Prevents WP deleting files when there are still media using them
206 * Thanks to Bruno "Aesqe" Babic and its plugin file gallery in which I took all the ideas for this function
207 *
208 * @since 0.9
209 *
210 * @param string $file
211 * @return string unmodified $file
212 */
213 public function wp_delete_file( $file ) {
214 global $wpdb;
215
216 $uploadpath = wp_upload_dir();
217
218 $ids = $wpdb->get_col(
219 $wpdb->prepare(
220 "SELECT post_id FROM $wpdb->postmeta
221 WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
222 substr_replace( $file, '', 0, strlen( trailingslashit( $uploadpath['basedir'] ) ) )
223 )
224 );
225
226 if ( ! empty( $ids ) ) {
227 // Regenerate intermediate sizes if it's an image ( since we could not prevent WP deleting them before )
228 wp_update_attachment_metadata( $ids[0], wp_generate_attachment_metadata( $ids[0], $file ) );
229 return ''; // Prevent deleting the main file
230 }
231
232 return $file;
233 }
234 }
235