at path:ROOT / wp-admin / includes / post.php
run:R W Run
7.85 KB
2026-03-11 16:18:51
R W Run
3.54 KB
2026-03-11 16:18:51
R W Run
148.33 KB
2026-03-11 16:18:51
R W Run
11.45 KB
2026-03-11 16:18:51
R W Run
3.58 KB
2026-03-11 16:18:51
R W Run
2.53 KB
2026-03-11 16:18:51
R W Run
2.6 KB
2026-03-11 16:18:51
R W Run
6.59 KB
2026-03-11 16:18:51
R W Run
14.83 KB
2026-03-11 16:18:51
R W Run
21.18 KB
2026-03-11 16:18:51
R W Run
48.13 KB
2026-03-11 16:18:51
R W Run
4.07 KB
2026-03-11 16:18:51
R W Run
5.3 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
26.73 KB
2026-03-11 16:18:51
R W Run
2.8 KB
2026-03-11 16:18:51
R W Run
15.2 KB
2026-03-11 16:18:51
R W Run
192.08 KB
2026-03-11 16:18:51
R W Run
11.77 KB
2026-03-11 16:18:51
R W Run
3.2 KB
2026-03-11 16:18:51
R W Run
22.89 KB
2026-03-11 16:18:51
R W Run
12.77 KB
2026-03-11 16:18:51
R W Run
4.08 KB
2026-03-11 16:18:51
R W Run
26.27 KB
2026-03-11 16:18:51
R W Run
4.97 KB
2026-03-11 16:18:51
R W Run
5.57 KB
2026-03-11 16:18:51
R W Run
13.93 KB
2026-03-11 16:18:51
R W Run
4.09 KB
2026-03-11 16:18:51
R W Run
6.79 KB
2026-03-11 16:18:51
R W Run
60.45 KB
2026-03-11 16:18:51
R W Run
32.4 KB
2026-03-11 16:18:51
R W Run
18.24 KB
2026-03-11 16:18:51
R W Run
66.01 KB
2026-03-11 16:18:51
R W Run
23.84 KB
2026-03-11 16:18:51
R W Run
17.72 KB
2026-03-11 16:18:51
R W Run
22.71 KB
2026-03-11 16:18:51
R W Run
18.05 KB
2026-03-11 16:18:51
R W Run
22.76 KB
2026-03-11 16:18:51
R W Run
7.34 KB
2026-03-11 16:18:51
R W Run
4.51 KB
2026-03-11 16:18:51
R W Run
9.02 KB
2026-03-11 16:18:51
R W Run
1.46 KB
2026-03-11 16:18:51
R W Run
51.76 KB
2026-03-11 16:18:51
R W Run
25.29 KB
2026-03-11 16:18:51
R W Run
21.61 KB
2026-03-11 16:18:51
R W Run
27.77 KB
2026-03-11 16:18:51
R W Run
15.35 KB
2026-03-11 16:18:51
R W Run
24.54 KB
2026-03-11 16:18:51
R W Run
56.44 KB
2026-03-11 16:18:51
R W Run
1.42 KB
2026-03-11 16:18:51
R W Run
63.66 KB
2026-03-11 16:18:51
R W Run
31.9 KB
2026-03-11 16:18:51
R W Run
14.44 KB
2026-03-11 16:18:51
R W Run
36.47 KB
2026-03-11 16:18:51
R W Run
14 KB
2026-03-11 16:18:51
R W Run
121.89 KB
2026-03-11 16:18:51
R W Run
6.26 KB
2026-03-11 16:18:51
R W Run
20.73 KB
2026-03-11 16:18:51
R W Run
15.23 KB
2026-03-11 16:18:51
R W Run
10.14 KB
2026-03-11 16:18:51
R W Run
6.94 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
46.85 KB
2026-03-11 16:18:51
R W Run
18.61 KB
2026-03-11 16:18:51
R W Run
6.08 KB
2026-03-11 16:18:51
R W Run
20.06 KB
2026-03-11 16:18:51
R W Run
5.73 KB
2026-03-11 16:18:51
R W Run
68.18 KB
2026-03-11 16:18:51
R W Run
40.8 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
25.26 KB
2026-03-11 16:18:51
R W Run
95.94 KB
2026-03-11 16:18:51
R W Run
43.12 KB
2026-03-11 16:18:51
R W Run
41.73 KB
2026-03-11 16:18:51
R W Run
6.46 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
116.31 KB
2026-03-11 16:18:51
R W Run
9.39 KB
2026-03-11 16:18:51
R W Run
64.34 KB
2026-03-11 16:18:51
R W Run
44.73 KB
2026-03-11 16:18:51
R W Run
1.27 KB
2026-03-11 16:18:51
R W Run
3.68 KB
2026-03-11 16:18:51
R W Run
33.53 KB
2026-03-11 16:18:51
R W Run
48.84 KB
2026-03-11 16:18:51
R W Run
26.35 KB
2026-03-11 16:18:51
R W Run
1.12 KB
2026-03-11 16:18:51
R W Run
4.19 KB
2026-03-11 16:18:51
R W Run
38.19 KB
2026-03-11 16:18:51
R W Run
91.33 KB
2026-03-11 16:18:51
R W Run
80.39 KB
2026-03-11 16:18:51
R W Run
32.67 KB
2026-03-11 16:18:51
R W Run
16.18 KB
2026-03-11 16:18:51
R W Run
44.46 KB
2026-03-11 16:18:51
R W Run
6.23 KB
2026-03-11 16:18:51
R W Run
8.23 KB
2026-03-11 16:18:51
R W Run
96.96 KB
2026-03-11 16:18:51
R W Run
6.83 KB
2026-03-11 16:18:51
R W Run
46.62 KB
2026-03-11 16:18:51
R W Run
10.82 KB
2026-03-11 16:18:51
R W Run
68.86 KB
2026-03-11 16:18:51
R W Run
33.63 KB
2026-03-11 16:18:51
R W Run
113.3 KB
2026-03-11 16:18:51
R W Run
22.98 KB
2026-03-11 16:18:51
R W Run
10.66 KB
2026-03-11 16:18:51
R W Run
error_log
📄post.php
1<?php
2/**
3 * WordPress Post Administration API.
4 *
5 * @package WordPress
6 * @subpackage Administration
7 */
8
9/**
10 * Renames `$_POST` data from form names to DB post columns.
11 *
12 * Manipulates `$_POST` directly.
13 *
14 * @since 2.6.0
15 *
16 * @param bool $update Whether the post already exists.
17 * @param array|null $post_data Optional. The array of post data to process.
18 * Defaults to the `$_POST` superglobal.
19 * @return array|WP_Error Array of post data on success, WP_Error on failure.
20 */
21function _wp_translate_postdata( $update = false, $post_data = null ) {
22
23 if ( empty( $post_data ) ) {
24 $post_data = &$_POST;
25 }
26
27 if ( $update ) {
28 $post_data['ID'] = (int) $post_data['post_ID'];
29 }
30
31 $ptype = get_post_type_object( $post_data['post_type'] );
32
33 if ( $update && ! current_user_can( 'edit_post', $post_data['ID'] ) ) {
34 if ( 'page' === $post_data['post_type'] ) {
35 return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) );
36 } else {
37 return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) );
38 }
39 } elseif ( ! $update && ! current_user_can( $ptype->cap->create_posts ) ) {
40 if ( 'page' === $post_data['post_type'] ) {
41 return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to create pages as this user.' ) );
42 } else {
43 return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to create posts as this user.' ) );
44 }
45 }
46
47 if ( isset( $post_data['content'] ) ) {
48 $post_data['post_content'] = $post_data['content'];
49 }
50
51 if ( isset( $post_data['excerpt'] ) ) {
52 $post_data['post_excerpt'] = $post_data['excerpt'];
53 }
54
55 if ( isset( $post_data['parent_id'] ) ) {
56 $post_data['post_parent'] = (int) $post_data['parent_id'];
57 }
58
59 if ( isset( $post_data['trackback_url'] ) ) {
60 $post_data['to_ping'] = $post_data['trackback_url'];
61 }
62
63 $post_data['user_ID'] = get_current_user_id();
64
65 if ( ! empty( $post_data['post_author_override'] ) ) {
66 $post_data['post_author'] = (int) $post_data['post_author_override'];
67 } else {
68 if ( ! empty( $post_data['post_author'] ) ) {
69 $post_data['post_author'] = (int) $post_data['post_author'];
70 } else {
71 $post_data['post_author'] = (int) $post_data['user_ID'];
72 }
73 }
74
75 if ( isset( $post_data['user_ID'] ) && ( $post_data['post_author'] !== $post_data['user_ID'] )
76 && ! current_user_can( $ptype->cap->edit_others_posts ) ) {
77
78 if ( $update ) {
79 if ( 'page' === $post_data['post_type'] ) {
80 return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) );
81 } else {
82 return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) );
83 }
84 } else {
85 if ( 'page' === $post_data['post_type'] ) {
86 return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to create pages as this user.' ) );
87 } else {
88 return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to create posts as this user.' ) );
89 }
90 }
91 }
92
93 if ( ! empty( $post_data['post_status'] ) ) {
94 $post_data['post_status'] = sanitize_key( $post_data['post_status'] );
95
96 // No longer an auto-draft.
97 if ( 'auto-draft' === $post_data['post_status'] ) {
98 $post_data['post_status'] = 'draft';
99 }
100
101 if ( ! get_post_status_object( $post_data['post_status'] ) ) {
102 unset( $post_data['post_status'] );
103 }
104 }
105
106 // What to do based on which button they pressed.
107 if ( isset( $post_data['saveasdraft'] ) && '' !== $post_data['saveasdraft'] ) {
108 $post_data['post_status'] = 'draft';
109 }
110 if ( isset( $post_data['saveasprivate'] ) && '' !== $post_data['saveasprivate'] ) {
111 $post_data['post_status'] = 'private';
112 }
113 if ( isset( $post_data['publish'] ) && ( '' !== $post_data['publish'] )
114 && ( ! isset( $post_data['post_status'] ) || 'private' !== $post_data['post_status'] )
115 ) {
116 $post_data['post_status'] = 'publish';
117 }
118 if ( isset( $post_data['advanced'] ) && '' !== $post_data['advanced'] ) {
119 $post_data['post_status'] = 'draft';
120 }
121 if ( isset( $post_data['pending'] ) && '' !== $post_data['pending'] ) {
122 $post_data['post_status'] = 'pending';
123 }
124
125 if ( isset( $post_data['ID'] ) ) {
126 $post_id = $post_data['ID'];
127 } else {
128 $post_id = false;
129 }
130 $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
131
132 if ( isset( $post_data['post_status'] ) && 'private' === $post_data['post_status'] && ! current_user_can( $ptype->cap->publish_posts ) ) {
133 $post_data['post_status'] = $previous_status ? $previous_status : 'pending';
134 }
135
136 $published_statuses = array( 'publish', 'future' );
137
138 /*
139 * Posts 'submitted for approval' are submitted to $_POST the same as if they were being published.
140 * Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
141 */
142 if ( isset( $post_data['post_status'] )
143 && ( in_array( $post_data['post_status'], $published_statuses, true )
144 && ! current_user_can( $ptype->cap->publish_posts ) )
145 ) {
146 if ( ! in_array( $previous_status, $published_statuses, true ) || ! current_user_can( 'edit_post', $post_id ) ) {
147 $post_data['post_status'] = 'pending';
148 }
149 }
150
151 if ( ! isset( $post_data['post_status'] ) ) {
152 $post_data['post_status'] = 'auto-draft' === $previous_status ? 'draft' : $previous_status;
153 }
154
155 if ( isset( $post_data['post_password'] ) && ! current_user_can( $ptype->cap->publish_posts ) ) {
156 unset( $post_data['post_password'] );
157 }
158
159 if ( ! isset( $post_data['comment_status'] ) ) {
160 $post_data['comment_status'] = 'closed';
161 }
162
163 if ( ! isset( $post_data['ping_status'] ) ) {
164 $post_data['ping_status'] = 'closed';
165 }
166
167 foreach ( array( 'aa', 'mm', 'jj', 'hh', 'mn' ) as $timeunit ) {
168 if ( ! empty( $post_data[ 'hidden_' . $timeunit ] ) && $post_data[ 'hidden_' . $timeunit ] !== $post_data[ $timeunit ] ) {
169 $post_data['edit_date'] = '1';
170 break;
171 }
172 }
173
174 if ( ! empty( $post_data['edit_date'] ) ) {
175 $aa = $post_data['aa'];
176 $mm = $post_data['mm'];
177 $jj = $post_data['jj'];
178 $hh = $post_data['hh'];
179 $mn = $post_data['mn'];
180 $ss = $post_data['ss'];
181 $aa = ( $aa <= 0 ) ? gmdate( 'Y' ) : $aa;
182 $mm = ( $mm <= 0 ) ? gmdate( 'n' ) : $mm;
183 $jj = ( $jj > 31 ) ? 31 : $jj;
184 $jj = ( $jj <= 0 ) ? gmdate( 'j' ) : $jj;
185 $hh = ( $hh > 23 ) ? $hh - 24 : $hh;
186 $mn = ( $mn > 59 ) ? $mn - 60 : $mn;
187 $ss = ( $ss > 59 ) ? $ss - 60 : $ss;
188
189 $post_data['post_date'] = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $aa, $mm, $jj, $hh, $mn, $ss );
190
191 $valid_date = wp_checkdate( $mm, $jj, $aa, $post_data['post_date'] );
192 if ( ! $valid_date ) {
193 return new WP_Error( 'invalid_date', __( 'Invalid date.' ) );
194 }
195
196 /*
197 * Only assign a post date if the user has explicitly set a new value.
198 * See #59125 and #19907.
199 */
200 $previous_date = $post_id ? get_post_field( 'post_date', $post_id ) : false;
201 if ( $previous_date && $previous_date !== $post_data['post_date'] ) {
202 $post_data['edit_date'] = true;
203 $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
204 } else {
205 $post_data['edit_date'] = false;
206 unset( $post_data['post_date'] );
207 unset( $post_data['post_date_gmt'] );
208 }
209 }
210
211 if ( isset( $post_data['post_category'] ) ) {
212 $category_object = get_taxonomy( 'category' );
213 if ( ! current_user_can( $category_object->cap->assign_terms ) ) {
214 unset( $post_data['post_category'] );
215 }
216 }
217
218 return $post_data;
219}
220
221/**
222 * Returns only allowed post data fields.
223 *
224 * @since 5.0.1
225 *
226 * @param array|WP_Error|null $post_data The array of post data to process, or an error object.
227 * Defaults to the `$_POST` superglobal.
228 * @return array|WP_Error Array of post data on success, WP_Error on failure.
229 */
230function _wp_get_allowed_postdata( $post_data = null ) {
231 if ( empty( $post_data ) ) {
232 $post_data = $_POST;
233 }
234
235 // Pass through errors.
236 if ( is_wp_error( $post_data ) ) {
237 return $post_data;
238 }
239
240 return array_diff_key( $post_data, array_flip( array( 'meta_input', 'file', 'guid' ) ) );
241}
242
243/**
244 * Updates an existing post with values provided in `$_POST`.
245 *
246 * If post data is passed as an argument, it is treated as an array of data
247 * keyed appropriately for turning into a post object.
248 *
249 * If post data is not passed, the `$_POST` global variable is used instead.
250 *
251 * @since 1.5.0
252 *
253 * @global wpdb $wpdb WordPress database abstraction object.
254 *
255 * @param array|null $post_data Optional. The array of post data to process.
256 * Defaults to the `$_POST` superglobal.
257 * @return int Post ID.
258 */
259function edit_post( $post_data = null ) {
260 global $wpdb;
261
262 if ( empty( $post_data ) ) {
263 $post_data = &$_POST;
264 }
265
266 // Clear out any data in internal vars.
267 unset( $post_data['filter'] );
268
269 $post_id = (int) $post_data['post_ID'];
270 $post = get_post( $post_id );
271
272 $post_data['post_type'] = $post->post_type;
273 $post_data['post_mime_type'] = $post->post_mime_type;
274
275 if ( ! empty( $post_data['post_status'] ) ) {
276 $post_data['post_status'] = sanitize_key( $post_data['post_status'] );
277
278 if ( 'inherit' === $post_data['post_status'] ) {
279 unset( $post_data['post_status'] );
280 }
281 }
282
283 $ptype = get_post_type_object( $post_data['post_type'] );
284 if ( ! current_user_can( 'edit_post', $post_id ) ) {
285 if ( 'page' === $post_data['post_type'] ) {
286 wp_die( __( 'Sorry, you are not allowed to edit this page.' ) );
287 } else {
288 wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
289 }
290 }
291
292 if ( post_type_supports( $ptype->name, 'revisions' ) ) {
293 $revisions = wp_get_post_revisions(
294 $post_id,
295 array(
296 'order' => 'ASC',
297 'posts_per_page' => 1,
298 )
299 );
300 $revision = current( $revisions );
301
302 // Check if the revisions have been upgraded.
303 if ( $revisions && _wp_get_post_revision_version( $revision ) < 1 ) {
304 _wp_upgrade_revisions_of_post( $post, wp_get_post_revisions( $post_id ) );
305 }
306 }
307
308 if ( isset( $post_data['visibility'] ) ) {
309 switch ( $post_data['visibility'] ) {
310 case 'public':
311 $post_data['post_password'] = '';
312 break;
313 case 'password':
314 unset( $post_data['sticky'] );
315 break;
316 case 'private':
317 $post_data['post_status'] = 'private';
318 $post_data['post_password'] = '';
319 unset( $post_data['sticky'] );
320 break;
321 }
322 }
323
324 $post_data = _wp_translate_postdata( true, $post_data );
325 if ( is_wp_error( $post_data ) ) {
326 wp_die( $post_data->get_error_message() );
327 }
328 $translated = _wp_get_allowed_postdata( $post_data );
329
330 // Post formats.
331 if ( isset( $post_data['post_format'] ) ) {
332 set_post_format( $post_id, $post_data['post_format'] );
333 }
334
335 $format_meta_urls = array( 'url', 'link_url', 'quote_source_url' );
336 foreach ( $format_meta_urls as $format_meta_url ) {
337 $keyed = '_format_' . $format_meta_url;
338 if ( isset( $post_data[ $keyed ] ) ) {
339 update_post_meta( $post_id, $keyed, wp_slash( sanitize_url( wp_unslash( $post_data[ $keyed ] ) ) ) );
340 }
341 }
342
343 $format_keys = array( 'quote', 'quote_source_name', 'image', 'gallery', 'audio_embed', 'video_embed' );
344
345 foreach ( $format_keys as $key ) {
346 $keyed = '_format_' . $key;
347 if ( isset( $post_data[ $keyed ] ) ) {
348 if ( current_user_can( 'unfiltered_html' ) ) {
349 update_post_meta( $post_id, $keyed, $post_data[ $keyed ] );
350 } else {
351 update_post_meta( $post_id, $keyed, wp_filter_post_kses( $post_data[ $keyed ] ) );
352 }
353 }
354 }
355
356 if ( 'attachment' === $post_data['post_type'] && preg_match( '#^(audio|video)/#', $post_data['post_mime_type'] ) ) {
357 $id3data = wp_get_attachment_metadata( $post_id );
358 if ( ! is_array( $id3data ) ) {
359 $id3data = array();
360 }
361
362 foreach ( wp_get_attachment_id3_keys( $post, 'edit' ) as $key => $label ) {
363 if ( isset( $post_data[ 'id3_' . $key ] ) ) {
364 $id3data[ $key ] = sanitize_text_field( wp_unslash( $post_data[ 'id3_' . $key ] ) );
365 }
366 }
367 wp_update_attachment_metadata( $post_id, $id3data );
368 }
369
370 // Meta stuff.
371 if ( isset( $post_data['meta'] ) && $post_data['meta'] ) {
372 foreach ( $post_data['meta'] as $key => $value ) {
373 $meta = get_post_meta_by_id( $key );
374 if ( ! $meta ) {
375 continue;
376 }
377
378 if ( (int) $meta->post_id !== $post_id ) {
379 continue;
380 }
381
382 if ( is_protected_meta( $meta->meta_key, 'post' )
383 || ! current_user_can( 'edit_post_meta', $post_id, $meta->meta_key )
384 ) {
385 continue;
386 }
387
388 if ( is_protected_meta( $value['key'], 'post' )
389 || ! current_user_can( 'edit_post_meta', $post_id, $value['key'] )
390 ) {
391 continue;
392 }
393
394 update_meta( $key, $value['key'], $value['value'] );
395 }
396 }
397
398 if ( isset( $post_data['deletemeta'] ) && $post_data['deletemeta'] ) {
399 foreach ( $post_data['deletemeta'] as $key => $value ) {
400 $meta = get_post_meta_by_id( $key );
401 if ( ! $meta ) {
402 continue;
403 }
404
405 if ( (int) $meta->post_id !== $post_id ) {
406 continue;
407 }
408
409 if ( is_protected_meta( $meta->meta_key, 'post' )
410 || ! current_user_can( 'delete_post_meta', $post_id, $meta->meta_key )
411 ) {
412 continue;
413 }
414
415 delete_meta( $key );
416 }
417 }
418
419 // Attachment stuff.
420 if ( 'attachment' === $post_data['post_type'] ) {
421 if ( isset( $post_data['_wp_attachment_image_alt'] ) ) {
422 $image_alt = wp_unslash( $post_data['_wp_attachment_image_alt'] );
423
424 if ( get_post_meta( $post_id, '_wp_attachment_image_alt', true ) !== $image_alt ) {
425 $image_alt = wp_strip_all_tags( $image_alt, true );
426
427 // update_post_meta() expects slashed.
428 update_post_meta( $post_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
429 }
430 }
431
432 $attachment_data = isset( $post_data['attachments'][ $post_id ] ) ? $post_data['attachments'][ $post_id ] : array();
433
434 /** This filter is documented in wp-admin/includes/media.php */
435 $translated = apply_filters( 'attachment_fields_to_save', $translated, $attachment_data );
436 }
437
438 // Convert taxonomy input to term IDs, to avoid ambiguity.
439 if ( isset( $post_data['tax_input'] ) ) {
440 foreach ( (array) $post_data['tax_input'] as $taxonomy => $terms ) {
441 $tax_object = get_taxonomy( $taxonomy );
442
443 if ( $tax_object && isset( $tax_object->meta_box_sanitize_cb ) ) {
444 $translated['tax_input'][ $taxonomy ] = call_user_func_array( $tax_object->meta_box_sanitize_cb, array( $taxonomy, $terms ) );
445 }
446 }
447 }
448
449 add_meta( $post_id );
450
451 update_post_meta( $post_id, '_edit_last', get_current_user_id() );
452
453 $success = wp_update_post( $translated );
454
455 // If the save failed, see if we can confidence check the main fields and try again.
456 if ( ! $success && is_callable( array( $wpdb, 'strip_invalid_text_for_column' ) ) ) {
457 $fields = array( 'post_title', 'post_content', 'post_excerpt' );
458
459 foreach ( $fields as $field ) {
460 if ( isset( $translated[ $field ] ) ) {
461 $translated[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->posts, $field, $translated[ $field ] );
462 }
463 }
464
465 wp_update_post( $translated );
466 }
467
468 // Now that we have an ID we can fix any attachment anchor hrefs.
469 _fix_attachment_links( $post_id );
470
471 wp_set_post_lock( $post_id );
472
473 if ( current_user_can( $ptype->cap->edit_others_posts ) && current_user_can( $ptype->cap->publish_posts ) ) {
474 if ( ! empty( $post_data['sticky'] ) ) {
475 stick_post( $post_id );
476 } else {
477 unstick_post( $post_id );
478 }
479 }
480
481 return $post_id;
482}
483
484/**
485 * Processes the post data for the bulk editing of posts.
486 *
487 * Updates all bulk edited posts/pages, adding (but not removing) tags and
488 * categories. Skips pages when they would be their own parent or child.
489 *
490 * @since 2.7.0
491 *
492 * @global wpdb $wpdb WordPress database abstraction object.
493 *
494 * @param array|null $post_data Optional. The array of post data to process.
495 * Defaults to the `$_POST` superglobal.
496 * @return array {
497 * An array of updated, skipped, and locked post IDs.
498 *
499 * @type int[] $updated An array of updated post IDs.
500 * @type int[] $skipped An array of skipped post IDs.
501 * @type int[] $locked An array of locked post IDs.
502 * }
503 */
504function bulk_edit_posts( $post_data = null ) {
505 global $wpdb;
506
507 if ( empty( $post_data ) ) {
508 $post_data = &$_POST;
509 }
510
511 if ( isset( $post_data['post_type'] ) ) {
512 $ptype = get_post_type_object( $post_data['post_type'] );
513 } else {
514 $ptype = get_post_type_object( 'post' );
515 }
516
517 if ( ! current_user_can( $ptype->cap->edit_posts ) ) {
518 if ( 'page' === $ptype->name ) {
519 wp_die( __( 'Sorry, you are not allowed to edit pages.' ) );
520 } else {
521 wp_die( __( 'Sorry, you are not allowed to edit posts.' ) );
522 }
523 }
524
525 if ( '-1' === $post_data['_status'] ) {
526 $post_data['post_status'] = null;
527 unset( $post_data['post_status'] );
528 } else {
529 $post_data['post_status'] = $post_data['_status'];
530 }
531 unset( $post_data['_status'] );
532
533 if ( ! empty( $post_data['post_status'] ) ) {
534 $post_data['post_status'] = sanitize_key( $post_data['post_status'] );
535
536 if ( 'inherit' === $post_data['post_status'] ) {
537 unset( $post_data['post_status'] );
538 }
539 }
540
541 $post_ids = array_map( 'intval', (array) $post_data['post'] );
542
543 $reset = array(
544 'post_author',
545 'post_status',
546 'post_password',
547 'post_parent',
548 'page_template',
549 'comment_status',
550 'ping_status',
551 'keep_private',
552 'tax_input',
553 'post_category',
554 'sticky',
555 'post_format',
556 );
557
558 foreach ( $reset as $field ) {
559 if ( isset( $post_data[ $field ] ) && ( '' === $post_data[ $field ] || '-1' === $post_data[ $field ] ) ) {
560 unset( $post_data[ $field ] );
561 }
562 }
563
564 if ( isset( $post_data['post_category'] ) ) {
565 if ( is_array( $post_data['post_category'] ) && ! empty( $post_data['post_category'] ) ) {
566 $new_cats = array_map( 'absint', $post_data['post_category'] );
567 } else {
568 unset( $post_data['post_category'] );
569 }
570 }
571
572 $tax_input = array();
573 if ( isset( $post_data['tax_input'] ) ) {
574 foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
575 if ( empty( $terms ) ) {
576 continue;
577 }
578
579 if ( is_taxonomy_hierarchical( $tax_name ) ) {
580 $tax_input[ $tax_name ] = array_map( 'absint', $terms );
581 } else {
582 $comma = _x( ',', 'tag delimiter' );
583 if ( ',' !== $comma ) {
584 $terms = str_replace( $comma, ',', $terms );
585 }
586 $tax_input[ $tax_name ] = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
587 }
588 }
589 }
590
591 if ( isset( $post_data['post_parent'] ) && (int) $post_data['post_parent'] ) {
592 $parent = (int) $post_data['post_parent'];
593 $pages = $wpdb->get_results( "SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'" );
594 $children = array();
595
596 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
597 $children[] = $parent;
598
599 foreach ( $pages as $page ) {
600 if ( (int) $page->ID === $parent ) {
601 $parent = (int) $page->post_parent;
602 break;
603 }
604 }
605 }
606 }
607
608 $updated = array();
609 $skipped = array();
610 $locked = array();
611 $shared_post_data = $post_data;
612
613 foreach ( $post_ids as $post_id ) {
614 // Start with fresh post data with each iteration.
615 $post_data = $shared_post_data;
616
617 $post_type_object = get_post_type_object( get_post_type( $post_id ) );
618
619 if ( ! isset( $post_type_object )
620 || ( isset( $children ) && in_array( $post_id, $children, true ) )
621 || ! current_user_can( 'edit_post', $post_id )
622 ) {
623 $skipped[] = $post_id;
624 continue;
625 }
626
627 if ( wp_check_post_lock( $post_id ) ) {
628 $locked[] = $post_id;
629 continue;
630 }
631
632 $post = get_post( $post_id );
633 $tax_names = get_object_taxonomies( $post );
634
635 foreach ( $tax_names as $tax_name ) {
636 $taxonomy_obj = get_taxonomy( $tax_name );
637
638 if ( ! $taxonomy_obj->show_in_quick_edit ) {
639 continue;
640 }
641
642 if ( isset( $tax_input[ $tax_name ] ) && current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
643 $new_terms = $tax_input[ $tax_name ];
644 } else {
645 $new_terms = array();
646 }
647
648 if ( $taxonomy_obj->hierarchical ) {
649 $current_terms = (array) wp_get_object_terms( $post_id, $tax_name, array( 'fields' => 'ids' ) );
650 } else {
651 $current_terms = (array) wp_get_object_terms( $post_id, $tax_name, array( 'fields' => 'names' ) );
652 }
653
654 $post_data['tax_input'][ $tax_name ] = array_merge( $current_terms, $new_terms );
655 }
656
657 if ( isset( $new_cats ) && in_array( 'category', $tax_names, true ) ) {
658 $cats = (array) wp_get_post_categories( $post_id );
659
660 if (
661 isset( $post_data['indeterminate_post_category'] )
662 && is_array( $post_data['indeterminate_post_category'] )
663 ) {
664 $indeterminate_post_category = $post_data['indeterminate_post_category'];
665 } else {
666 $indeterminate_post_category = array();
667 }
668
669 $indeterminate_cats = array_intersect( $cats, $indeterminate_post_category );
670 $determinate_cats = array_diff( $new_cats, $indeterminate_post_category );
671 $post_data['post_category'] = array_unique( array_merge( $indeterminate_cats, $determinate_cats ) );
672
673 unset( $post_data['tax_input']['category'] );
674 }
675
676 $post_data['post_ID'] = $post_id;
677 $post_data['post_type'] = $post->post_type;
678 $post_data['post_mime_type'] = $post->post_mime_type;
679
680 foreach ( array( 'comment_status', 'ping_status', 'post_author' ) as $field ) {
681 if ( ! isset( $post_data[ $field ] ) ) {
682 $post_data[ $field ] = $post->$field;
683 }
684 }
685
686 $post_data = _wp_translate_postdata( true, $post_data );
687 if ( is_wp_error( $post_data ) ) {
688 $skipped[] = $post_id;
689 continue;
690 }
691 $post_data = _wp_get_allowed_postdata( $post_data );
692
693 if ( isset( $shared_post_data['post_format'] ) ) {
694 set_post_format( $post_id, $shared_post_data['post_format'] );
695 }
696
697 // Prevent wp_insert_post() from overwriting post format with the old data.
698 unset( $post_data['tax_input']['post_format'] );
699
700 // Reset post date of scheduled post to be published.
701 if (
702 in_array( $post->post_status, array( 'future', 'draft' ), true ) &&
703 'publish' === $post_data['post_status']
704 ) {
705 $post_data['post_date'] = current_time( 'mysql' );
706 $post_data['post_date_gmt'] = '';
707 }
708
709 $post_id = wp_update_post( $post_data );
710 update_post_meta( $post_id, '_edit_last', get_current_user_id() );
711 $updated[] = $post_id;
712
713 if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
714 if ( 'sticky' === $post_data['sticky'] ) {
715 stick_post( $post_id );
716 } else {
717 unstick_post( $post_id );
718 }
719 }
720 }
721
722 /**
723 * Fires after processing the post data for bulk edit.
724 *
725 * @since 6.3.0
726 *
727 * @param int[] $updated An array of updated post IDs.
728 * @param array $shared_post_data Associative array containing the post data.
729 */
730 do_action( 'bulk_edit_posts', $updated, $shared_post_data );
731
732 return array(
733 'updated' => $updated,
734 'skipped' => $skipped,
735 'locked' => $locked,
736 );
737}
738
739/**
740 * Returns default post information to use when populating the "Write Post" form.
741 *
742 * @since 2.0.0
743 *
744 * @param string $post_type Optional. A post type string. Default 'post'.
745 * @param bool $create_in_db Optional. Whether to insert the post into database. Default false.
746 * @return WP_Post Post object containing all the default post data as attributes
747 */
748function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
749 $post_title = '';
750 if ( ! empty( $_REQUEST['post_title'] ) ) {
751 $post_title = esc_html( wp_unslash( $_REQUEST['post_title'] ) );
752 }
753
754 $post_content = '';
755 if ( ! empty( $_REQUEST['content'] ) ) {
756 $post_content = esc_html( wp_unslash( $_REQUEST['content'] ) );
757 }
758
759 $post_excerpt = '';
760 if ( ! empty( $_REQUEST['excerpt'] ) ) {
761 $post_excerpt = esc_html( wp_unslash( $_REQUEST['excerpt'] ) );
762 }
763
764 if ( $create_in_db ) {
765 $post_id = wp_insert_post(
766 array(
767 'post_title' => __( 'Auto Draft' ),
768 'post_type' => $post_type,
769 'post_status' => 'auto-draft',
770 ),
771 true,
772 false
773 );
774
775 if ( is_wp_error( $post_id ) ) {
776 wp_die( $post_id->get_error_message() );
777 }
778
779 $post = get_post( $post_id );
780
781 if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) ) {
782 set_post_format( $post, get_option( 'default_post_format' ) );
783 }
784
785 wp_after_insert_post( $post, false, null );
786
787 // Schedule auto-draft cleanup.
788 if ( ! wp_next_scheduled( 'wp_scheduled_auto_draft_delete' ) ) {
789 wp_schedule_event( time(), 'daily', 'wp_scheduled_auto_draft_delete' );
790 }
791 } else {
792 $post = new stdClass();
793 $post->ID = 0;
794 $post->post_author = '';
795 $post->post_date = '';
796 $post->post_date_gmt = '';
797 $post->post_password = '';
798 $post->post_name = '';
799 $post->post_type = $post_type;
800 $post->post_status = 'draft';
801 $post->to_ping = '';
802 $post->pinged = '';
803 $post->comment_status = get_default_comment_status( $post_type );
804 $post->ping_status = get_default_comment_status( $post_type, 'pingback' );
805 $post->post_pingback = get_option( 'default_pingback_flag' );
806 $post->post_category = get_option( 'default_category' );
807 $post->page_template = 'default';
808 $post->post_parent = 0;
809 $post->menu_order = 0;
810 $post = new WP_Post( $post );
811 }
812
813 /**
814 * Filters the default post content initially used in the "Write Post" form.
815 *
816 * @since 1.5.0
817 *
818 * @param string $post_content Default post content.
819 * @param WP_Post $post Post object.
820 */
821 $post->post_content = (string) apply_filters( 'default_content', $post_content, $post );
822
823 /**
824 * Filters the default post title initially used in the "Write Post" form.
825 *
826 * @since 1.5.0
827 *
828 * @param string $post_title Default post title.
829 * @param WP_Post $post Post object.
830 */
831 $post->post_title = (string) apply_filters( 'default_title', $post_title, $post );
832
833 /**
834 * Filters the default post excerpt initially used in the "Write Post" form.
835 *
836 * @since 1.5.0
837 *
838 * @param string $post_excerpt Default post excerpt.
839 * @param WP_Post $post Post object.
840 */
841 $post->post_excerpt = (string) apply_filters( 'default_excerpt', $post_excerpt, $post );
842
843 return $post;
844}
845
846/**
847 * Determines if a post exists based on title, content, date and type.
848 *
849 * @since 2.0.0
850 * @since 5.2.0 Added the `$type` parameter.
851 * @since 5.8.0 Added the `$status` parameter.
852 *
853 * @global wpdb $wpdb WordPress database abstraction object.
854 *
855 * @param string $title Post title.
856 * @param string $content Optional. Post content.
857 * @param string $date Optional. Post date.
858 * @param string $type Optional. Post type.
859 * @param string $status Optional. Post status.
860 * @return int Post ID if post exists, 0 otherwise.
861 */
862function post_exists( $title, $content = '', $date = '', $type = '', $status = '' ) {
863 global $wpdb;
864
865 $post_title = wp_unslash( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
866 $post_content = wp_unslash( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
867 $post_date = wp_unslash( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
868 $post_type = wp_unslash( sanitize_post_field( 'post_type', $type, 0, 'db' ) );
869 $post_status = wp_unslash( sanitize_post_field( 'post_status', $status, 0, 'db' ) );
870
871 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
872 $args = array();
873
874 if ( ! empty( $date ) ) {
875 $query .= ' AND post_date = %s';
876 $args[] = $post_date;
877 }
878
879 if ( ! empty( $title ) ) {
880 $query .= ' AND post_title = %s';
881 $args[] = $post_title;
882 }
883
884 if ( ! empty( $content ) ) {
885 $query .= ' AND post_content = %s';
886 $args[] = $post_content;
887 }
888
889 if ( ! empty( $type ) ) {
890 $query .= ' AND post_type = %s';
891 $args[] = $post_type;
892 }
893
894 if ( ! empty( $status ) ) {
895 $query .= ' AND post_status = %s';
896 $args[] = $post_status;
897 }
898
899 if ( ! empty( $args ) ) {
900 return (int) $wpdb->get_var( $wpdb->prepare( $query, $args ) );
901 }
902
903 return 0;
904}
905
906/**
907 * Creates a new post from the "Write Post" form using `$_POST` information.
908 *
909 * @since 2.1.0
910 *
911 * @global WP_User $current_user
912 *
913 * @return int|WP_Error Post ID on success, WP_Error on failure.
914 */
915function wp_write_post() {
916 if ( isset( $_POST['post_type'] ) ) {
917 $ptype = get_post_type_object( $_POST['post_type'] );
918 } else {
919 $ptype = get_post_type_object( 'post' );
920 }
921
922 if ( ! current_user_can( $ptype->cap->edit_posts ) ) {
923 if ( 'page' === $ptype->name ) {
924 return new WP_Error( 'edit_pages', __( 'Sorry, you are not allowed to create pages on this site.' ) );
925 } else {
926 return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to create posts or drafts on this site.' ) );
927 }
928 }
929
930 $_POST['post_mime_type'] = '';
931
932 // Clear out any data in internal vars.
933 unset( $_POST['filter'] );
934
935 // Edit, don't write, if we have a post ID.
936 if ( isset( $_POST['post_ID'] ) ) {
937 return edit_post();
938 }
939
940 if ( isset( $_POST['visibility'] ) ) {
941 switch ( $_POST['visibility'] ) {
942 case 'public':
943 $_POST['post_password'] = '';
944 break;
945 case 'password':
946 unset( $_POST['sticky'] );
947 break;
948 case 'private':
949 $_POST['post_status'] = 'private';
950 $_POST['post_password'] = '';
951 unset( $_POST['sticky'] );
952 break;
953 }
954 }
955
956 $translated = _wp_translate_postdata( false );
957 if ( is_wp_error( $translated ) ) {
958 return $translated;
959 }
960 $translated = _wp_get_allowed_postdata( $translated );
961
962 // Create the post.
963 $post_id = wp_insert_post( $translated );
964 if ( is_wp_error( $post_id ) ) {
965 return $post_id;
966 }
967
968 if ( empty( $post_id ) ) {
969 return 0;
970 }
971
972 add_meta( $post_id );
973
974 add_post_meta( $post_id, '_edit_last', $GLOBALS['current_user']->ID );
975
976 // Now that we have an ID we can fix any attachment anchor hrefs.
977 _fix_attachment_links( $post_id );
978
979 wp_set_post_lock( $post_id );
980
981 return $post_id;
982}
983
984/**
985 * Calls wp_write_post() and handles the errors.
986 *
987 * @since 2.0.0
988 *
989 * @return int|void Post ID on success, void on failure.
990 */
991function write_post() {
992 $result = wp_write_post();
993 if ( is_wp_error( $result ) ) {
994 wp_die( $result->get_error_message() );
995 } else {
996 return $result;
997 }
998}
999
1000//
1001// Post Meta.
1002//
1003
1004/**
1005 * Adds post meta data defined in the `$_POST` superglobal for a post with given ID.
1006 *
1007 * @since 1.2.0
1008 *
1009 * @param int $post_id
1010 * @return int|bool
1011 */
1012function add_meta( $post_id ) {
1013 $post_id = (int) $post_id;
1014
1015 $metakeyselect = isset( $_POST['metakeyselect'] ) ? wp_unslash( trim( $_POST['metakeyselect'] ) ) : '';
1016 $metakeyinput = isset( $_POST['metakeyinput'] ) ? wp_unslash( trim( $_POST['metakeyinput'] ) ) : '';
1017 $metavalue = isset( $_POST['metavalue'] ) ? $_POST['metavalue'] : '';
1018 if ( is_string( $metavalue ) ) {
1019 $metavalue = trim( $metavalue );
1020 }
1021
1022 if ( ( ( '#NONE#' !== $metakeyselect ) && ! empty( $metakeyselect ) ) || ! empty( $metakeyinput ) ) {
1023 /*
1024 * We have a key/value pair. If both the select and the input
1025 * for the key have data, the input takes precedence.
1026 */
1027 if ( '#NONE#' !== $metakeyselect ) {
1028 $metakey = $metakeyselect;
1029 }
1030
1031 if ( $metakeyinput ) {
1032 $metakey = $metakeyinput; // Default.
1033 }
1034
1035 if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_id, $metakey ) ) {
1036 return false;
1037 }
1038
1039 $metakey = wp_slash( $metakey );
1040
1041 return add_post_meta( $post_id, $metakey, $metavalue );
1042 }
1043
1044 return false;
1045}
1046
1047/**
1048 * Deletes post meta data by meta ID.
1049 *
1050 * @since 1.2.0
1051 *
1052 * @param int $mid
1053 * @return bool
1054 */
1055function delete_meta( $mid ) {
1056 return delete_metadata_by_mid( 'post', $mid );
1057}
1058
1059/**
1060 * Returns a list of previously defined keys.
1061 *
1062 * @since 1.2.0
1063 *
1064 * @global wpdb $wpdb WordPress database abstraction object.
1065 *
1066 * @return string[] Array of meta key names.
1067 */
1068function get_meta_keys() {
1069 global $wpdb;
1070
1071 $keys = $wpdb->get_col(
1072 "SELECT meta_key
1073 FROM $wpdb->postmeta
1074 GROUP BY meta_key
1075 ORDER BY meta_key"
1076 );
1077
1078 return $keys;
1079}
1080
1081/**
1082 * Returns post meta data by meta ID.
1083 *
1084 * @since 2.1.0
1085 *
1086 * @param int $mid
1087 * @return object|bool
1088 */
1089function get_post_meta_by_id( $mid ) {
1090 return get_metadata_by_mid( 'post', $mid );
1091}
1092
1093/**
1094 * Returns meta data for the given post ID.
1095 *
1096 * @since 1.2.0
1097 *
1098 * @global wpdb $wpdb WordPress database abstraction object.
1099 *
1100 * @param int $post_id A post ID.
1101 * @return array[] {
1102 * Array of meta data arrays for the given post ID.
1103 *
1104 * @type array ...$0 {
1105 * Associative array of meta data.
1106 *
1107 * @type string $meta_key Meta key.
1108 * @type mixed $meta_value Meta value.
1109 * @type string $meta_id Meta ID as a numeric string.
1110 * @type string $post_id Post ID as a numeric string.
1111 * }
1112 * }
1113 */
1114function has_meta( $post_id ) {
1115 global $wpdb;
1116
1117 return $wpdb->get_results(
1118 $wpdb->prepare(
1119 "SELECT meta_key, meta_value, meta_id, post_id
1120 FROM $wpdb->postmeta WHERE post_id = %d
1121 ORDER BY meta_key,meta_id",
1122 $post_id
1123 ),
1124 ARRAY_A
1125 );
1126}
1127
1128/**
1129 * Updates post meta data by meta ID.
1130 *
1131 * @since 1.2.0
1132 *
1133 * @param int $meta_id Meta ID.
1134 * @param string $meta_key Meta key. Expect slashed.
1135 * @param string $meta_value Meta value. Expect slashed.
1136 * @return bool
1137 */
1138function update_meta( $meta_id, $meta_key, $meta_value ) {
1139 $meta_key = wp_unslash( $meta_key );
1140 $meta_value = wp_unslash( $meta_value );
1141
1142 return update_metadata_by_mid( 'post', $meta_id, $meta_value, $meta_key );
1143}
1144
1145//
1146// Private.
1147//
1148
1149/**
1150 * Replaces hrefs of attachment anchors with up-to-date permalinks.
1151 *
1152 * @since 2.3.0
1153 * @access private
1154 *
1155 * @param int|WP_Post $post Post ID or post object.
1156 * @return void|int|WP_Error Void if nothing fixed. 0 or WP_Error on update failure. The post ID on update success.
1157 */
1158function _fix_attachment_links( $post ) {
1159 $post = get_post( $post, ARRAY_A );
1160 $content = $post['post_content'];
1161
1162 // Don't run if no pretty permalinks or post is not published, scheduled, or privately published.
1163 if ( ! get_option( 'permalink_structure' ) || ! in_array( $post['post_status'], array( 'publish', 'future', 'private' ), true ) ) {
1164 return;
1165 }
1166
1167 // Short if there aren't any links or no '?attachment_id=' strings (strpos cannot be zero).
1168 if ( ! strpos( $content, '?attachment_id=' ) || ! preg_match_all( '/<a ([^>]+)>[\s\S]+?<\/a>/', $content, $link_matches ) ) {
1169 return;
1170 }
1171
1172 $site_url = get_bloginfo( 'url' );
1173 $site_url = substr( $site_url, (int) strpos( $site_url, '://' ) ); // Remove the http(s).
1174 $replace = '';
1175
1176 foreach ( $link_matches[1] as $key => $value ) {
1177 if ( ! strpos( $value, '?attachment_id=' ) || ! strpos( $value, 'wp-att-' )
1178 || ! preg_match( '/href=(["\'])[^"\']*\?attachment_id=(\d+)[^"\']*\\1/', $value, $url_match )
1179 || ! preg_match( '/rel=["\'][^"\']*wp-att-(\d+)/', $value, $rel_match ) ) {
1180 continue;
1181 }
1182
1183 $quote = $url_match[1]; // The quote (single or double).
1184 $url_id = (int) $url_match[2];
1185 $rel_id = (int) $rel_match[1];
1186
1187 if ( ! $url_id || ! $rel_id || $url_id !== $rel_id || ! str_contains( $url_match[0], $site_url ) ) {
1188 continue;
1189 }
1190
1191 $link = $link_matches[0][ $key ];
1192 $replace = str_replace( $url_match[0], 'href=' . $quote . get_attachment_link( $url_id ) . $quote, $link );
1193
1194 $content = str_replace( $link, $replace, $content );
1195 }
1196
1197 if ( $replace ) {
1198 $post['post_content'] = $content;
1199 // Escape data pulled from DB.
1200 $post = add_magic_quotes( $post );
1201
1202 return wp_update_post( $post );
1203 }
1204}
1205
1206/**
1207 * Returns all the possible statuses for a post type.
1208 *
1209 * @since 2.5.0
1210 *
1211 * @param string $type The post_type you want the statuses for. Default 'post'.
1212 * @return string[] An array of all the statuses for the supplied post type.
1213 */
1214function get_available_post_statuses( $type = 'post' ) {
1215 $statuses = wp_count_posts( $type );
1216
1217 return array_keys( get_object_vars( $statuses ) );
1218}
1219
1220/**
1221 * Runs the query to fetch the posts for listing on the edit posts page.
1222 *
1223 * @since 2.5.0
1224 *
1225 * @param array|false $q Optional. Array of query variables to use to build the query.
1226 * Defaults to the `$_GET` superglobal.
1227 * @return string[] An array of all the statuses for the queried post type.
1228 */
1229function wp_edit_posts_query( $q = false ) {
1230 if ( false === $q ) {
1231 $q = $_GET;
1232 }
1233
1234 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
1235 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
1236
1237 $post_statuses = get_post_stati();
1238
1239 if ( isset( $q['post_type'] ) && in_array( $q['post_type'], get_post_types(), true ) ) {
1240 $post_type = $q['post_type'];
1241 } else {
1242 $post_type = 'post';
1243 }
1244
1245 $avail_post_stati = get_available_post_statuses( $post_type );
1246 $post_status = '';
1247 $perm = '';
1248
1249 if ( isset( $q['post_status'] ) && in_array( $q['post_status'], $post_statuses, true ) ) {
1250 $post_status = $q['post_status'];
1251 $perm = 'readable';
1252 }
1253
1254 $orderby = '';
1255
1256 if ( isset( $q['orderby'] ) ) {
1257 $orderby = $q['orderby'];
1258 } elseif ( isset( $q['post_status'] ) && in_array( $q['post_status'], array( 'pending', 'draft' ), true ) ) {
1259 $orderby = 'modified';
1260 }
1261
1262 $order = '';
1263
1264 if ( isset( $q['order'] ) ) {
1265 $order = $q['order'];
1266 } elseif ( isset( $q['post_status'] ) && 'pending' === $q['post_status'] ) {
1267 $order = 'ASC';
1268 }
1269
1270 $per_page = "edit_{$post_type}_per_page";
1271 $posts_per_page = (int) get_user_option( $per_page );
1272 if ( empty( $posts_per_page ) || $posts_per_page < 1 ) {
1273 $posts_per_page = 20;
1274 }
1275
1276 /**
1277 * Filters the number of items per page to show for a specific 'per_page' type.
1278 *
1279 * The dynamic portion of the hook name, `$post_type`, refers to the post type.
1280 *
1281 * Possible hook names include:
1282 *
1283 * - `edit_post_per_page`
1284 * - `edit_page_per_page`
1285 * - `edit_attachment_per_page`
1286 *
1287 * @since 3.0.0
1288 *
1289 * @param int $posts_per_page Number of posts to display per page for the given post
1290 * type. Default 20.
1291 */
1292 $posts_per_page = apply_filters( "edit_{$post_type}_per_page", $posts_per_page );
1293
1294 /**
1295 * Filters the number of posts displayed per page when specifically listing "posts".
1296 *
1297 * @since 2.8.0
1298 *
1299 * @param int $posts_per_page Number of posts to be displayed. Default 20.
1300 * @param string $post_type The post type.
1301 */
1302 $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
1303
1304 $query = compact( 'post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page' );
1305
1306 // Hierarchical types require special args.
1307 if ( is_post_type_hierarchical( $post_type ) && empty( $orderby ) ) {
1308 $query['orderby'] = 'menu_order title';
1309 $query['order'] = 'asc';
1310 $query['posts_per_page'] = -1;
1311 $query['posts_per_archive_page'] = -1;
1312 $query['fields'] = 'id=>parent';
1313 }
1314
1315 if ( ! empty( $q['show_sticky'] ) ) {
1316 $query['post__in'] = (array) get_option( 'sticky_posts' );
1317 }
1318
1319 wp( $query );
1320
1321 return $avail_post_stati;
1322}
1323
1324/**
1325 * Returns the query variables for the current attachments request.
1326 *
1327 * @since 4.2.0
1328 *
1329 * @param array|false $q Optional. Array of query variables to use to build the query.
1330 * Defaults to the `$_GET` superglobal.
1331 * @return array The parsed query vars.
1332 */
1333function wp_edit_attachments_query_vars( $q = false ) {
1334 if ( false === $q ) {
1335 $q = $_GET;
1336 }
1337 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
1338 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
1339 $q['post_type'] = 'attachment';
1340 $post_type = get_post_type_object( 'attachment' );
1341 $states = 'inherit';
1342 if ( current_user_can( $post_type->cap->read_private_posts ) ) {
1343 $states .= ',private';
1344 }
1345
1346 $q['post_status'] = isset( $q['status'] ) && 'trash' === $q['status'] ? 'trash' : $states;
1347 $q['post_status'] = isset( $q['attachment-filter'] ) && 'trash' === $q['attachment-filter'] ? 'trash' : $states;
1348
1349 $media_per_page = (int) get_user_option( 'upload_per_page' );
1350 if ( empty( $media_per_page ) || $media_per_page < 1 ) {
1351 $media_per_page = 20;
1352 }
1353
1354 /**
1355 * Filters the number of items to list per page when listing media items.
1356 *
1357 * @since 2.9.0
1358 *
1359 * @param int $media_per_page Number of media to list. Default 20.
1360 */
1361 $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
1362
1363 $post_mime_types = get_post_mime_types();
1364 if ( isset( $q['post_mime_type'] ) && ! array_intersect( (array) $q['post_mime_type'], array_keys( $post_mime_types ) ) ) {
1365 unset( $q['post_mime_type'] );
1366 }
1367
1368 foreach ( array_keys( $post_mime_types ) as $type ) {
1369 if ( isset( $q['attachment-filter'] ) && "post_mime_type:$type" === $q['attachment-filter'] ) {
1370 $q['post_mime_type'] = $type;
1371 break;
1372 }
1373 }
1374
1375 if ( isset( $q['detached'] ) || ( isset( $q['attachment-filter'] ) && 'detached' === $q['attachment-filter'] ) ) {
1376 $q['post_parent'] = 0;
1377 }
1378
1379 if ( isset( $q['mine'] ) || ( isset( $q['attachment-filter'] ) && 'mine' === $q['attachment-filter'] ) ) {
1380 $q['author'] = get_current_user_id();
1381 }
1382
1383 // Filter query clauses to include filenames.
1384 if ( isset( $q['s'] ) ) {
1385 add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
1386 }
1387
1388 return $q;
1389}
1390
1391/**
1392 * Executes a query for attachments. An array of WP_Query arguments
1393 * can be passed in, which will override the arguments set by this function.
1394 *
1395 * @since 2.5.0
1396 *
1397 * @param array|false $q Optional. Array of query variables to use to build the query.
1398 * Defaults to the `$_GET` superglobal.
1399 * @return array {
1400 * Array containing the post mime types and available post mime types.
1401 *
1402 * @type array[] $post_mime_types Post mime types.
1403 * @type string[] $avail_post_mime_types Available post mime types.
1404 * }
1405 */
1406function wp_edit_attachments_query( $q = false ) {
1407 wp( wp_edit_attachments_query_vars( $q ) );
1408
1409 $post_mime_types = get_post_mime_types();
1410 $avail_post_mime_types = get_available_post_mime_types( 'attachment' );
1411
1412 return array( $post_mime_types, $avail_post_mime_types );
1413}
1414
1415/**
1416 * Returns the list of classes to be used by a meta box.
1417 *
1418 * @since 2.5.0
1419 *
1420 * @param string $box_id Meta box ID (used in the 'id' attribute for the meta box).
1421 * @param string $screen_id The screen on which the meta box is shown.
1422 * @return string Space-separated string of class names.
1423 */
1424function postbox_classes( $box_id, $screen_id ) {
1425 if ( isset( $_GET['edit'] ) && $_GET['edit'] === $box_id ) {
1426 $classes = array( '' );
1427 } elseif ( get_user_option( 'closedpostboxes_' . $screen_id ) ) {
1428 $closed = get_user_option( 'closedpostboxes_' . $screen_id );
1429 if ( ! is_array( $closed ) ) {
1430 $classes = array( '' );
1431 } else {
1432 $classes = in_array( $box_id, $closed, true ) ? array( 'closed' ) : array( '' );
1433 }
1434 } else {
1435 $classes = array( '' );
1436 }
1437
1438 /**
1439 * Filters the postbox classes for a specific screen and box ID combo.
1440 *
1441 * The dynamic portions of the hook name, `$screen_id` and `$box_id`, refer to
1442 * the screen ID and meta box ID, respectively.
1443 *
1444 * @since 3.2.0
1445 *
1446 * @param string[] $classes An array of postbox classes.
1447 */
1448 $classes = apply_filters( "postbox_classes_{$screen_id}_{$box_id}", $classes );
1449
1450 return implode( ' ', $classes );
1451}
1452
1453/**
1454 * Returns a sample permalink based on the post name.
1455 *
1456 * @since 2.5.0
1457 *
1458 * @param int|WP_Post $post Post ID or post object.
1459 * @param string|null $title Optional. Title to override the post's current title
1460 * when generating the post name. Default null.
1461 * @param string|null $name Optional. Name to override the post name. Default null.
1462 * @return array {
1463 * Array containing the sample permalink with placeholder for the post name, and the post name.
1464 *
1465 * @type string $0 The permalink with placeholder for the post name.
1466 * @type string $1 The post name.
1467 * }
1468 */
1469function get_sample_permalink( $post, $title = null, $name = null ) {
1470 $post = get_post( $post );
1471
1472 if ( ! $post ) {
1473 return array( '', '' );
1474 }
1475
1476 $ptype = get_post_type_object( $post->post_type );
1477
1478 $original_status = $post->post_status;
1479 $original_date = $post->post_date;
1480 $original_name = $post->post_name;
1481 $original_filter = $post->filter;
1482
1483 // Hack: get_permalink() would return plain permalink for drafts, so we will fake that our post is published.
1484 if ( in_array( $post->post_status, array( 'auto-draft', 'draft', 'pending', 'future' ), true ) ) {
1485 $post->post_status = 'publish';
1486 $post->post_name = sanitize_title( $post->post_name ? $post->post_name : $post->post_title, $post->ID );
1487 }
1488
1489 /*
1490 * If the user wants to set a new name -- override the current one.
1491 * Note: if empty name is supplied -- use the title instead, see #6072.
1492 */
1493 if ( ! is_null( $name ) ) {
1494 $post->post_name = sanitize_title( $name ? $name : $title, $post->ID );
1495 }
1496
1497 $post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent );
1498
1499 $post->filter = 'sample';
1500
1501 $permalink = get_permalink( $post, true );
1502
1503 // Replace custom post_type token with generic pagename token for ease of use.
1504 $permalink = str_replace( "%$post->post_type%", '%pagename%', $permalink );
1505
1506 // Handle page hierarchy.
1507 if ( $ptype->hierarchical ) {
1508 $uri = get_page_uri( $post );
1509 if ( $uri ) {
1510 $uri = untrailingslashit( $uri );
1511 $uri = strrev( stristr( strrev( $uri ), '/' ) );
1512 $uri = untrailingslashit( $uri );
1513 }
1514
1515 /** This filter is documented in wp-admin/edit-tag-form.php */
1516 $uri = apply_filters( 'editable_slug', $uri, $post );
1517 if ( ! empty( $uri ) ) {
1518 $uri .= '/';
1519 }
1520 $permalink = str_replace( '%pagename%', "{$uri}%pagename%", $permalink );
1521 }
1522
1523 /** This filter is documented in wp-admin/edit-tag-form.php */
1524 $permalink = array( $permalink, apply_filters( 'editable_slug', $post->post_name, $post ) );
1525 $post->post_status = $original_status;
1526 $post->post_date = $original_date;
1527 $post->post_name = $original_name;
1528 $post->filter = $original_filter;
1529
1530 /**
1531 * Filters the sample permalink.
1532 *
1533 * @since 4.4.0
1534 *
1535 * @param array $permalink {
1536 * Array containing the sample permalink with placeholder for the post name, and the post name.
1537 *
1538 * @type string $0 The permalink with placeholder for the post name.
1539 * @type string $1 The post name.
1540 * }
1541 * @param int $post_id Post ID.
1542 * @param string $title Post title.
1543 * @param string $name Post name (slug).
1544 * @param WP_Post $post Post object.
1545 */
1546 return apply_filters( 'get_sample_permalink', $permalink, $post->ID, $title, $name, $post );
1547}
1548
1549/**
1550 * Returns the HTML of the sample permalink slug editor.
1551 *
1552 * @since 2.5.0
1553 *
1554 * @param int|WP_Post $post Post ID or post object.
1555 * @param string|null $new_title Optional. New title. Default null.
1556 * @param string|null $new_slug Optional. New slug. Default null.
1557 * @return string The HTML of the sample permalink slug editor.
1558 */
1559function get_sample_permalink_html( $post, $new_title = null, $new_slug = null ) {
1560 $post = get_post( $post );
1561
1562 if ( ! $post ) {
1563 return '';
1564 }
1565
1566 list($permalink, $post_name) = get_sample_permalink( $post->ID, $new_title, $new_slug );
1567
1568 $view_link = false;
1569 $preview_target = '';
1570
1571 if ( current_user_can( 'read_post', $post->ID ) ) {
1572 if ( 'draft' === $post->post_status || empty( $post->post_name ) ) {
1573 $view_link = get_preview_post_link( $post );
1574 $preview_target = " target='wp-preview-{$post->ID}'";
1575 } else {
1576 if ( 'publish' === $post->post_status || 'attachment' === $post->post_type ) {
1577 $view_link = get_permalink( $post );
1578 } else {
1579 // Allow non-published (private, future) to be viewed at a pretty permalink, in case $post->post_name is set.
1580 $view_link = str_replace( array( '%pagename%', '%postname%' ), $post->post_name, $permalink );
1581 }
1582 }
1583 }
1584
1585 // Permalinks without a post/page name placeholder don't have anything to edit.
1586 if ( ! str_contains( $permalink, '%postname%' ) && ! str_contains( $permalink, '%pagename%' ) ) {
1587 $return = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
1588
1589 if ( false !== $view_link ) {
1590 $display_link = urldecode( $view_link );
1591 $return .= '<a id="sample-permalink" href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . esc_html( $display_link ) . "</a>\n";
1592 } else {
1593 $return .= '<span id="sample-permalink">' . $permalink . "</span>\n";
1594 }
1595
1596 // Encourage a pretty permalink setting.
1597 if ( ! get_option( 'permalink_structure' ) && current_user_can( 'manage_options' )
1598 && ! ( 'page' === get_option( 'show_on_front' ) && (int) get_option( 'page_on_front' ) === $post->ID )
1599 ) {
1600 $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button button-small">' . __( 'Change Permalink Structure' ) . "</a></span>\n";
1601 }
1602 } else {
1603 if ( mb_strlen( $post_name ) > 34 ) {
1604 $post_name_abridged = mb_substr( $post_name, 0, 16 ) . '&hellip;' . mb_substr( $post_name, -16 );
1605 } else {
1606 $post_name_abridged = $post_name;
1607 }
1608
1609 $post_name_html = '<span id="editable-post-name">' . esc_html( $post_name_abridged ) . '</span>';
1610 $display_link = str_replace( array( '%pagename%', '%postname%' ), $post_name_html, esc_html( urldecode( $permalink ) ) );
1611
1612 $return = '<strong>' . __( 'Permalink:' ) . "</strong>\n";
1613 $return .= '<span id="sample-permalink"><a href="' . esc_url( $view_link ) . '"' . $preview_target . '>' . $display_link . "</a></span>\n";
1614 $return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
1615 $return .= '<span id="edit-slug-buttons"><button type="button" class="edit-slug button button-small hide-if-no-js" aria-label="' . __( 'Edit permalink' ) . '">' . __( 'Edit' ) . "</button></span>\n";
1616 $return .= '<span id="editable-post-name-full">' . esc_html( $post_name ) . "</span>\n";
1617 }
1618
1619 /**
1620 * Filters the sample permalink HTML markup.
1621 *
1622 * @since 2.9.0
1623 * @since 4.4.0 Added `$post` parameter.
1624 *
1625 * @param string $return Sample permalink HTML markup.
1626 * @param int $post_id Post ID.
1627 * @param string|null $new_title New sample permalink title.
1628 * @param string|null $new_slug New sample permalink slug.
1629 * @param WP_Post $post Post object.
1630 */
1631 $return = apply_filters( 'get_sample_permalink_html', $return, $post->ID, $new_title, $new_slug, $post );
1632
1633 return $return;
1634}
1635
1636/**
1637 * Returns HTML for the post thumbnail meta box.
1638 *
1639 * @since 2.9.0
1640 *
1641 * @param int|null $thumbnail_id Optional. Thumbnail attachment ID. Default null.
1642 * @param int|WP_Post|null $post Optional. The post ID or object associated
1643 * with the thumbnail. Defaults to global $post.
1644 * @return string The post thumbnail HTML.
1645 */
1646function _wp_post_thumbnail_html( $thumbnail_id = null, $post = null ) {
1647 $_wp_additional_image_sizes = wp_get_additional_image_sizes();
1648
1649 $post = get_post( $post );
1650 $post_type_object = get_post_type_object( $post->post_type );
1651 $set_thumbnail_link = '<p class="hide-if-no-js"><a href="%s" id="set-post-thumbnail"%s class="thickbox">%s</a></p>';
1652 $upload_iframe_src = get_upload_iframe_src( 'image', $post->ID );
1653
1654 $content = sprintf(
1655 $set_thumbnail_link,
1656 esc_url( $upload_iframe_src ),
1657 '', // Empty when there's no featured image set, `aria-describedby` attribute otherwise.
1658 esc_html( $post_type_object->labels->set_featured_image )
1659 );
1660
1661 if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
1662 $size = isset( $_wp_additional_image_sizes['post-thumbnail'] ) ? 'post-thumbnail' : array( 266, 266 );
1663
1664 /**
1665 * Filters the size used to display the post thumbnail image in the 'Featured image' meta box.
1666 *
1667 * Note: When a theme adds 'post-thumbnail' support, a special 'post-thumbnail'
1668 * image size is registered, which differs from the 'thumbnail' image size
1669 * managed via the Settings > Media screen.
1670 *
1671 * @since 4.4.0
1672 *
1673 * @param string|int[] $size Requested image size. Can be any registered image size name, or
1674 * an array of width and height values in pixels (in that order).
1675 * @param int $thumbnail_id Post thumbnail attachment ID.
1676 * @param WP_Post $post The post object associated with the thumbnail.
1677 */
1678 $size = apply_filters( 'admin_post_thumbnail_size', $size, $thumbnail_id, $post );
1679
1680 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, $size );
1681
1682 if ( ! empty( $thumbnail_html ) ) {
1683 $content = sprintf(
1684 $set_thumbnail_link,
1685 esc_url( $upload_iframe_src ),
1686 ' aria-describedby="set-post-thumbnail-desc"',
1687 $thumbnail_html
1688 );
1689 $content .= '<p class="hide-if-no-js howto" id="set-post-thumbnail-desc">' . __( 'Click the image to edit or update' ) . '</p>';
1690 $content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail">' . esc_html( $post_type_object->labels->remove_featured_image ) . '</a></p>';
1691 }
1692 }
1693
1694 $content .= '<input type="hidden" id="_thumbnail_id" name="_thumbnail_id" value="' . esc_attr( $thumbnail_id ? $thumbnail_id : '-1' ) . '" />';
1695
1696 /**
1697 * Filters the admin post thumbnail HTML markup to return.
1698 *
1699 * @since 2.9.0
1700 * @since 3.5.0 Added the `$post_id` parameter.
1701 * @since 4.6.0 Added the `$thumbnail_id` parameter.
1702 *
1703 * @param string $content Admin post thumbnail HTML markup.
1704 * @param int $post_id Post ID.
1705 * @param int|null $thumbnail_id Thumbnail attachment ID, or null if there isn't one.
1706 */
1707 return apply_filters( 'admin_post_thumbnail_html', $content, $post->ID, $thumbnail_id );
1708}
1709
1710/**
1711 * Determines whether the post is currently being edited by another user.
1712 *
1713 * @since 2.5.0
1714 *
1715 * @param int|WP_Post $post ID or object of the post to check for editing.
1716 * @return int|false ID of the user with lock. False if the post does not exist, post is not locked,
1717 * the user with lock does not exist, or the post is locked by current user.
1718 */
1719function wp_check_post_lock( $post ) {
1720 $post = get_post( $post );
1721
1722 if ( ! $post ) {
1723 return false;
1724 }
1725
1726 $lock = get_post_meta( $post->ID, '_edit_lock', true );
1727
1728 if ( ! $lock ) {
1729 return false;
1730 }
1731
1732 $lock = explode( ':', $lock );
1733 $time = $lock[0];
1734 $user = isset( $lock[1] ) ? (int) $lock[1] : (int) get_post_meta( $post->ID, '_edit_last', true );
1735
1736 if ( ! get_userdata( $user ) ) {
1737 return false;
1738 }
1739
1740 /** This filter is documented in wp-admin/includes/ajax-actions.php */
1741 $time_window = apply_filters( 'wp_check_post_lock_window', 150 );
1742
1743 if ( $time && $time > time() - $time_window && get_current_user_id() !== $user ) {
1744 return $user;
1745 }
1746
1747 return false;
1748}
1749
1750/**
1751 * Marks the post as currently being edited by the current user.
1752 *
1753 * @since 2.5.0
1754 *
1755 * @param int|WP_Post $post ID or object of the post being edited.
1756 * @return array|false {
1757 * Array of the lock time and user ID. False if the post does not exist, or there
1758 * is no current user.
1759 *
1760 * @type int $0 The current time as a Unix timestamp.
1761 * @type int $1 The ID of the current user.
1762 * }
1763 */
1764function wp_set_post_lock( $post ) {
1765 $post = get_post( $post );
1766
1767 if ( ! $post ) {
1768 return false;
1769 }
1770
1771 $user_id = get_current_user_id();
1772
1773 if ( 0 === $user_id ) {
1774 return false;
1775 }
1776
1777 $now = time();
1778 $lock = "$now:$user_id";
1779
1780 update_post_meta( $post->ID, '_edit_lock', $lock );
1781
1782 return array( $now, $user_id );
1783}
1784
1785/**
1786 * Outputs the HTML for the notice to say that someone else is editing or has taken over editing of this post.
1787 *
1788 * @since 2.8.5
1789 */
1790function _admin_notice_post_locked() {
1791 $post = get_post();
1792
1793 if ( ! $post ) {
1794 return;
1795 }
1796
1797 $user = null;
1798 $user_id = wp_check_post_lock( $post->ID );
1799
1800 if ( $user_id ) {
1801 $user = get_userdata( $user_id );
1802 }
1803
1804 if ( $user ) {
1805 /**
1806 * Filters whether to show the post locked dialog.
1807 *
1808 * Returning false from the filter will prevent the dialog from being displayed.
1809 *
1810 * @since 3.6.0
1811 *
1812 * @param bool $display Whether to display the dialog. Default true.
1813 * @param WP_Post $post Post object.
1814 * @param WP_User $user The user with the lock for the post.
1815 */
1816 if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) ) {
1817 return;
1818 }
1819
1820 $locked = true;
1821 } else {
1822 $locked = false;
1823 }
1824
1825 $sendback = wp_get_referer();
1826 $sendback_text = __( 'Go back' );
1827
1828 if ( ! $locked || ! $sendback || str_contains( $sendback, 'post.php' ) || str_contains( $sendback, 'post-new.php' ) ) {
1829 $sendback = admin_url( 'edit.php' );
1830
1831 if ( 'post' !== $post->post_type ) {
1832 $sendback = add_query_arg( 'post_type', $post->post_type, $sendback );
1833 }
1834
1835 $post_type_object = get_post_type_object( $post->post_type );
1836
1837 if ( $post_type_object ) {
1838 $sendback_text = $post_type_object->labels->all_items;
1839 }
1840 }
1841
1842 $hidden = $locked ? '' : ' hidden';
1843
1844 ?>
1845 <div id="post-lock-dialog" class="notification-dialog-wrap<?php echo $hidden; ?>">
1846 <div class="notification-dialog-background"></div>
1847 <div class="notification-dialog">
1848 <?php
1849
1850 if ( $locked ) {
1851 $query_args = array();
1852 if ( get_post_type_object( $post->post_type )->public ) {
1853 if ( 'publish' === $post->post_status || $user->ID !== (int) $post->post_author ) {
1854 // Latest content is in autosave.
1855 $nonce = wp_create_nonce( 'post_preview_' . $post->ID );
1856 $query_args['preview_id'] = $post->ID;
1857 $query_args['preview_nonce'] = $nonce;
1858 }
1859 }
1860
1861 $preview_link = get_preview_post_link( $post->ID, $query_args );
1862
1863 /**
1864 * Filters whether to allow the post lock to be overridden.
1865 *
1866 * Returning false from the filter will disable the ability
1867 * to override the post lock.
1868 *
1869 * @since 3.6.0
1870 *
1871 * @param bool $override Whether to allow the post lock to be overridden. Default true.
1872 * @param WP_Post $post Post object.
1873 * @param WP_User $user The user with the lock for the post.
1874 */
1875 $override = apply_filters( 'override_post_lock', true, $post, $user );
1876 $tab_last = $override ? '' : ' wp-tab-last';
1877
1878 ?>
1879 <div class="post-locked-message">
1880 <div class="post-locked-avatar"><?php echo get_avatar( $user->ID, 64 ); ?></div>
1881 <p class="currently-editing wp-tab-first" tabindex="0">
1882 <?php
1883 if ( $override ) {
1884 /* translators: %s: User's display name. */
1885 printf( __( '%s is currently editing this post. Do you want to take over?' ), esc_html( $user->display_name ) );
1886 } else {
1887 /* translators: %s: User's display name. */
1888 printf( __( '%s is currently editing this post.' ), esc_html( $user->display_name ) );
1889 }
1890 ?>
1891 </p>
1892 <?php
1893 /**
1894 * Fires inside the post locked dialog before the buttons are displayed.
1895 *
1896 * @since 3.6.0
1897 * @since 5.4.0 The $user parameter was added.
1898 *
1899 * @param WP_Post $post Post object.
1900 * @param WP_User $user The user with the lock for the post.
1901 */
1902 do_action( 'post_locked_dialog', $post, $user );
1903 ?>
1904 <p>
1905 <a class="button" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a>
1906 <?php if ( $preview_link ) { ?>
1907 <a class="button<?php echo $tab_last; ?>" href="<?php echo esc_url( $preview_link ); ?>"><?php _e( 'Preview' ); ?></a>
1908 <?php
1909 }
1910
1911 // Allow plugins to prevent some users overriding the post lock.
1912 if ( $override ) {
1913 ?>
1914 <a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', wp_nonce_url( get_edit_post_link( $post->ID, 'url' ), 'lock-post_' . $post->ID ) ) ); ?>"><?php _e( 'Take over' ); ?></a>
1915 <?php
1916 }
1917
1918 ?>
1919 </p>
1920 </div>
1921 <?php
1922 } else {
1923 ?>
1924 <div class="post-taken-over">
1925 <div class="post-locked-avatar"></div>
1926 <p class="wp-tab-first" tabindex="0">
1927 <span class="currently-editing"></span><br />
1928 <span class="locked-saving hidden"><img src="<?php echo esc_url( admin_url( 'images/spinner-2x.gif' ) ); ?>" width="16" height="16" alt="" /> <?php _e( 'Saving revision&hellip;' ); ?></span>
1929 <span class="locked-saved hidden"><?php _e( 'Your latest changes were saved as a revision.' ); ?></span>
1930 </p>
1931 <?php
1932 /**
1933 * Fires inside the dialog displayed when a user has lost the post lock.
1934 *
1935 * @since 3.6.0
1936 *
1937 * @param WP_Post $post Post object.
1938 */
1939 do_action( 'post_lock_lost_dialog', $post );
1940 ?>
1941 <p><a class="button button-primary wp-tab-last" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a></p>
1942 </div>
1943 <?php
1944 }
1945
1946 ?>
1947 </div>
1948 </div>
1949 <?php
1950}
1951
1952/**
1953 * Creates autosave data for the specified post from `$_POST` data.
1954 *
1955 * @since 2.6.0
1956 *
1957 * @param array|int $post_data Associative array containing the post data, or integer post ID.
1958 * If a numeric post ID is provided, will use the `$_POST` superglobal.
1959 * @return int|WP_Error The autosave revision ID. WP_Error or 0 on error.
1960 */
1961function wp_create_post_autosave( $post_data ) {
1962 if ( is_numeric( $post_data ) ) {
1963 $post_id = $post_data;
1964 $post_data = $_POST;
1965 } else {
1966 $post_id = (int) $post_data['post_ID'];
1967 }
1968
1969 $post_data = _wp_translate_postdata( true, $post_data );
1970 if ( is_wp_error( $post_data ) ) {
1971 return $post_data;
1972 }
1973 $post_data = _wp_get_allowed_postdata( $post_data );
1974
1975 $post_author = get_current_user_id();
1976
1977 // Store one autosave per author. If there is already an autosave, overwrite it.
1978 $old_autosave = wp_get_post_autosave( $post_id, $post_author );
1979 if ( $old_autosave ) {
1980 $new_autosave = _wp_post_revision_data( $post_data, true );
1981 $new_autosave['ID'] = $old_autosave->ID;
1982 $new_autosave['post_author'] = $post_author;
1983
1984 $post = get_post( $post_id );
1985
1986 // If the new autosave has the same content as the post, delete the autosave.
1987 $autosave_is_different = false;
1988 foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
1989 if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) {
1990 $autosave_is_different = true;
1991 break;
1992 }
1993 }
1994
1995 if ( ! $autosave_is_different ) {
1996 wp_delete_post_revision( $old_autosave->ID );
1997 return 0;
1998 }
1999
2000 /**
2001 * Fires before an autosave is stored.
2002 *
2003 * @since 4.1.0
2004 * @since 6.4.0 The `$is_update` parameter was added to indicate if the autosave is being updated or was newly created.
2005 *
2006 * @param array $new_autosave Post array - the autosave that is about to be saved.
2007 * @param bool $is_update Whether this is an existing autosave.
2008 */
2009 do_action( 'wp_creating_autosave', $new_autosave, true );
2010 return wp_update_post( $new_autosave );
2011 }
2012
2013 // _wp_put_post_revision() expects unescaped.
2014 $post_data = wp_unslash( $post_data );
2015
2016 // Otherwise create the new autosave as a special post revision.
2017 $revision = _wp_put_post_revision( $post_data, true );
2018
2019 if ( ! is_wp_error( $revision ) && 0 !== $revision ) {
2020
2021 /** This action is documented in wp-admin/includes/post.php */
2022 do_action( 'wp_creating_autosave', get_post( $revision, ARRAY_A ), false );
2023 }
2024
2025 return $revision;
2026}
2027
2028/**
2029 * Autosaves the revisioned meta fields.
2030 *
2031 * Iterates through the revisioned meta fields and checks each to see if they are set,
2032 * and have a changed value. If so, the meta value is saved and attached to the autosave.
2033 *
2034 * @since 6.4.0
2035 *
2036 * @param array $new_autosave The new post data being autosaved.
2037 */
2038function wp_autosave_post_revisioned_meta_fields( $new_autosave ) {
2039 /*
2040 * The post data arrives as either $_POST['data']['wp_autosave'] or the $_POST
2041 * itself. This sets $posted_data to the correct variable.
2042 *
2043 * Ignoring sanitization to avoid altering meta. Ignoring the nonce check because
2044 * this is hooked on inner core hooks where a valid nonce was already checked.
2045 */
2046 $posted_data = isset( $_POST['data']['wp_autosave'] ) ? $_POST['data']['wp_autosave'] : $_POST;
2047
2048 $post_type = get_post_type( $new_autosave['post_parent'] );
2049
2050 /*
2051 * Go through the revisioned meta keys and save them as part of the autosave,
2052 * if the meta key is part of the posted data, the meta value is not blank,
2053 * and the meta value has changes from the last autosaved value.
2054 */
2055 foreach ( wp_post_revision_meta_keys( $post_type ) as $meta_key ) {
2056
2057 if ( isset( $posted_data[ $meta_key ] )
2058 && get_post_meta( $new_autosave['ID'], $meta_key, true ) !== wp_unslash( $posted_data[ $meta_key ] )
2059 ) {
2060 /*
2061 * Use the underlying delete_metadata() and add_metadata() functions
2062 * vs delete_post_meta() and add_post_meta() to make sure we're working
2063 * with the actual revision meta.
2064 */
2065 delete_metadata( 'post', $new_autosave['ID'], $meta_key );
2066
2067 // One last check to ensure meta value is not empty.
2068 if ( ! empty( $posted_data[ $meta_key ] ) ) {
2069 // Add the revisions meta data to the autosave.
2070 add_metadata( 'post', $new_autosave['ID'], $meta_key, $posted_data[ $meta_key ] );
2071 }
2072 }
2073 }
2074}
2075
2076/**
2077 * Saves a draft or manually autosaves for the purpose of showing a post preview.
2078 *
2079 * @since 2.7.0
2080 *
2081 * @return string URL to redirect to show the preview.
2082 */
2083function post_preview() {
2084
2085 $post_id = (int) $_POST['post_ID'];
2086 $_POST['ID'] = $post_id;
2087
2088 $post = get_post( $post_id );
2089
2090 if ( ! $post ) {
2091 wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
2092 }
2093
2094 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
2095 wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
2096 }
2097
2098 $is_autosave = false;
2099
2100 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() === (int) $post->post_author
2101 && ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status )
2102 ) {
2103 $saved_post_id = edit_post();
2104 } else {
2105 $is_autosave = true;
2106
2107 if ( isset( $_POST['post_status'] ) && 'auto-draft' === $_POST['post_status'] ) {
2108 $_POST['post_status'] = 'draft';
2109 }
2110
2111 $saved_post_id = wp_create_post_autosave( $post->ID );
2112 }
2113
2114 if ( is_wp_error( $saved_post_id ) ) {
2115 wp_die( $saved_post_id->get_error_message() );
2116 }
2117
2118 $query_args = array();
2119
2120 if ( $is_autosave && $saved_post_id ) {
2121 $query_args['preview_id'] = $post->ID;
2122 $query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $post->ID );
2123
2124 if ( isset( $_POST['post_format'] ) ) {
2125 $query_args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] );
2126 }
2127
2128 if ( isset( $_POST['_thumbnail_id'] ) ) {
2129 $query_args['_thumbnail_id'] = ( (int) $_POST['_thumbnail_id'] <= 0 ) ? '-1' : (int) $_POST['_thumbnail_id'];
2130 }
2131 }
2132
2133 return get_preview_post_link( $post, $query_args );
2134}
2135
2136/**
2137 * Saves a post submitted with XHR.
2138 *
2139 * Intended for use with heartbeat and autosave.js
2140 *
2141 * @since 3.9.0
2142 *
2143 * @param array $post_data Associative array of the submitted post data.
2144 * @return mixed The value 0 or WP_Error on failure. The saved post ID on success.
2145 * The ID can be the draft post_id or the autosave revision post_id.
2146 */
2147function wp_autosave( $post_data ) {
2148 // Back-compat.
2149 if ( ! defined( 'DOING_AUTOSAVE' ) ) {
2150 define( 'DOING_AUTOSAVE', true );
2151 }
2152
2153 $post_id = (int) $post_data['post_id'];
2154 $post_data['ID'] = $post_id;
2155 $post_data['post_ID'] = $post_id;
2156
2157 if ( false === wp_verify_nonce( $post_data['_wpnonce'], 'update-post_' . $post_id ) ) {
2158 return new WP_Error( 'invalid_nonce', __( 'Error while saving.' ) );
2159 }
2160
2161 $post = get_post( $post_id );
2162
2163 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
2164 return new WP_Error( 'edit_posts', __( 'Sorry, you are not allowed to edit this item.' ) );
2165 }
2166
2167 if ( 'auto-draft' === $post->post_status ) {
2168 $post_data['post_status'] = 'draft';
2169 }
2170
2171 if ( 'page' !== $post_data['post_type'] && ! empty( $post_data['catslist'] ) ) {
2172 $post_data['post_category'] = explode( ',', $post_data['catslist'] );
2173 }
2174
2175 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() === (int) $post->post_author
2176 && ( 'auto-draft' === $post->post_status || 'draft' === $post->post_status )
2177 ) {
2178 // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked.
2179 return edit_post( wp_slash( $post_data ) );
2180 } else {
2181 /*
2182 * Non-drafts or other users' drafts are not overwritten.
2183 * The autosave is stored in a special post revision for each user.
2184 */
2185 return wp_create_post_autosave( wp_slash( $post_data ) );
2186 }
2187}
2188
2189/**
2190 * Redirects to previous page.
2191 *
2192 * @since 2.7.0
2193 *
2194 * @param int $post_id Optional. Post ID.
2195 */
2196function redirect_post( $post_id = 0 ) {
2197 if ( isset( $_POST['save'] ) || isset( $_POST['publish'] ) ) {
2198 $status = get_post_status( $post_id );
2199
2200 switch ( $status ) {
2201 case 'pending':
2202 $message = 8;
2203 break;
2204 case 'future':
2205 $message = 9;
2206 break;
2207 case 'draft':
2208 $message = 10;
2209 break;
2210 default:
2211 $message = isset( $_POST['publish'] ) ? 6 : 1;
2212 break;
2213 }
2214
2215 $location = add_query_arg( 'message', $message, get_edit_post_link( $post_id, 'url' ) );
2216 } elseif ( isset( $_POST['addmeta'] ) && $_POST['addmeta'] ) {
2217 $location = add_query_arg( 'message', 2, wp_get_referer() );
2218 $location = explode( '#', $location );
2219 $location = $location[0] . '#postcustom';
2220 } elseif ( isset( $_POST['deletemeta'] ) && $_POST['deletemeta'] ) {
2221 $location = add_query_arg( 'message', 3, wp_get_referer() );
2222 $location = explode( '#', $location );
2223 $location = $location[0] . '#postcustom';
2224 } else {
2225 $location = add_query_arg( 'message', 4, get_edit_post_link( $post_id, 'url' ) );
2226 }
2227
2228 /**
2229 * Filters the post redirect destination URL.
2230 *
2231 * @since 2.9.0
2232 *
2233 * @param string $location The destination URL.
2234 * @param int $post_id The post ID.
2235 */
2236 wp_redirect( apply_filters( 'redirect_post_location', $location, $post_id ) );
2237 exit;
2238}
2239
2240/**
2241 * Sanitizes POST values from a checkbox taxonomy metabox.
2242 *
2243 * @since 5.1.0
2244 *
2245 * @param string $taxonomy The taxonomy name.
2246 * @param array $terms Raw term data from the 'tax_input' field.
2247 * @return int[] Array of sanitized term IDs.
2248 */
2249function taxonomy_meta_box_sanitize_cb_checkboxes( $taxonomy, $terms ) {
2250 return array_map( 'intval', $terms );
2251}
2252
2253/**
2254 * Sanitizes POST values from an input taxonomy metabox.
2255 *
2256 * @since 5.1.0
2257 *
2258 * @param string $taxonomy The taxonomy name.
2259 * @param array|string $terms Raw term data from the 'tax_input' field.
2260 * @return array
2261 */
2262function taxonomy_meta_box_sanitize_cb_input( $taxonomy, $terms ) {
2263 /*
2264 * Assume that a 'tax_input' string is a comma-separated list of term names.
2265 * Some languages may use a character other than a comma as a delimiter, so we standardize on
2266 * commas before parsing the list.
2267 */
2268 if ( ! is_array( $terms ) ) {
2269 $comma = _x( ',', 'tag delimiter' );
2270 if ( ',' !== $comma ) {
2271 $terms = str_replace( $comma, ',', $terms );
2272 }
2273 $terms = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
2274 }
2275
2276 $clean_terms = array();
2277 foreach ( $terms as $term ) {
2278 // Empty terms are invalid input.
2279 if ( empty( $term ) ) {
2280 continue;
2281 }
2282
2283 $_term = get_terms(
2284 array(
2285 'taxonomy' => $taxonomy,
2286 'name' => $term,
2287 'fields' => 'ids',
2288 'hide_empty' => false,
2289 )
2290 );
2291
2292 if ( ! empty( $_term ) ) {
2293 $clean_terms[] = (int) $_term[0];
2294 } else {
2295 // No existing term was found, so pass the string. A new term will be created.
2296 $clean_terms[] = $term;
2297 }
2298 }
2299
2300 return $clean_terms;
2301}
2302
2303/**
2304 * Prepares server-registered blocks for the block editor.
2305 *
2306 * Returns an associative array of registered block data keyed by block name. Data includes properties
2307 * of a block relevant for client registration.
2308 *
2309 * @since 5.0.0
2310 * @since 6.3.0 Added `selectors` field.
2311 * @since 6.4.0 Added `block_hooks` field.
2312 *
2313 * @return array An associative array of registered block data.
2314 */
2315function get_block_editor_server_block_settings() {
2316 $block_registry = WP_Block_Type_Registry::get_instance();
2317 $blocks = array();
2318 $fields_to_pick = array(
2319 'api_version' => 'apiVersion',
2320 'title' => 'title',
2321 'description' => 'description',
2322 'icon' => 'icon',
2323 'attributes' => 'attributes',
2324 'provides_context' => 'providesContext',
2325 'uses_context' => 'usesContext',
2326 'block_hooks' => 'blockHooks',
2327 'selectors' => 'selectors',
2328 'supports' => 'supports',
2329 'category' => 'category',
2330 'styles' => 'styles',
2331 'textdomain' => 'textdomain',
2332 'parent' => 'parent',
2333 'ancestor' => 'ancestor',
2334 'keywords' => 'keywords',
2335 'example' => 'example',
2336 'variations' => 'variations',
2337 'allowed_blocks' => 'allowedBlocks',
2338 );
2339
2340 foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
2341 foreach ( $fields_to_pick as $field => $key ) {
2342 if ( ! isset( $block_type->{ $field } ) ) {
2343 continue;
2344 }
2345
2346 if ( ! isset( $blocks[ $block_name ] ) ) {
2347 $blocks[ $block_name ] = array();
2348 }
2349
2350 $blocks[ $block_name ][ $key ] = $block_type->{ $field };
2351 }
2352 }
2353
2354 return $blocks;
2355}
2356
2357/**
2358 * Renders the meta boxes forms.
2359 *
2360 * @since 5.0.0
2361 *
2362 * @global WP_Post $post Global post object.
2363 * @global WP_Screen $current_screen WordPress current screen object.
2364 * @global array $wp_meta_boxes Global meta box state.
2365 */
2366function the_block_editor_meta_boxes() {
2367 global $post, $current_screen, $wp_meta_boxes;
2368
2369 // Handle meta box state.
2370 $_original_meta_boxes = $wp_meta_boxes;
2371
2372 /**
2373 * Fires right before the meta boxes are rendered.
2374 *
2375 * This allows for the filtering of meta box data, that should already be
2376 * present by this point. Do not use as a means of adding meta box data.
2377 *
2378 * @since 5.0.0
2379 *
2380 * @param array $wp_meta_boxes Global meta box state.
2381 */
2382 $wp_meta_boxes = apply_filters( 'filter_block_editor_meta_boxes', $wp_meta_boxes );
2383 $locations = array( 'side', 'normal', 'advanced' );
2384 $priorities = array( 'high', 'sorted', 'core', 'default', 'low' );
2385
2386 // Render meta boxes.
2387 ?>
2388 <form class="metabox-base-form">
2389 <?php the_block_editor_meta_box_post_form_hidden_fields( $post ); ?>
2390 </form>
2391 <form id="toggle-custom-fields-form" method="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>">
2392 <?php wp_nonce_field( 'toggle-custom-fields', 'toggle-custom-fields-nonce' ); ?>
2393 <input type="hidden" name="action" value="toggle-custom-fields" />
2394 </form>
2395 <?php foreach ( $locations as $location ) : ?>
2396 <form class="metabox-location-<?php echo esc_attr( $location ); ?>" onsubmit="return false;">
2397 <div id="poststuff" class="sidebar-open">
2398 <div id="postbox-container-2" class="postbox-container">
2399 <?php
2400 do_meta_boxes(
2401 $current_screen,
2402 $location,
2403 $post
2404 );
2405 ?>
2406 </div>
2407 </div>
2408 </form>
2409 <?php endforeach; ?>
2410 <?php
2411
2412 $meta_boxes_per_location = array();
2413 foreach ( $locations as $location ) {
2414 $meta_boxes_per_location[ $location ] = array();
2415
2416 if ( ! isset( $wp_meta_boxes[ $current_screen->id ][ $location ] ) ) {
2417 continue;
2418 }
2419
2420 foreach ( $priorities as $priority ) {
2421 if ( ! isset( $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ] ) ) {
2422 continue;
2423 }
2424
2425 $meta_boxes = (array) $wp_meta_boxes[ $current_screen->id ][ $location ][ $priority ];
2426 foreach ( $meta_boxes as $meta_box ) {
2427 if ( false === $meta_box || ! $meta_box['title'] ) {
2428 continue;
2429 }
2430
2431 // If a meta box is just here for back compat, don't show it in the block editor.
2432 if ( isset( $meta_box['args']['__back_compat_meta_box'] ) && $meta_box['args']['__back_compat_meta_box'] ) {
2433 continue;
2434 }
2435
2436 $meta_boxes_per_location[ $location ][] = array(
2437 'id' => $meta_box['id'],
2438 'title' => $meta_box['title'],
2439 );
2440 }
2441 }
2442 }
2443
2444 /*
2445 * Sadly we probably cannot add this data directly into editor settings.
2446 *
2447 * Some meta boxes need `admin_head` to fire for meta box registry.
2448 * `admin_head` fires after `admin_enqueue_scripts`, which is where we create
2449 * our editor instance.
2450 */
2451 $script = 'window._wpLoadBlockEditor.then( function() {
2452 wp.data.dispatch( \'core/edit-post\' ).setAvailableMetaBoxesPerLocation( ' . wp_json_encode( $meta_boxes_per_location, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ' );
2453 } );';
2454
2455 wp_add_inline_script( 'wp-edit-post', $script );
2456
2457 /*
2458 * When `wp-edit-post` is output in the `<head>`, the inline script needs to be manually printed.
2459 * Otherwise, meta boxes will not display because inline scripts for `wp-edit-post`
2460 * will not be printed again after this point.
2461 */
2462 if ( wp_script_is( 'wp-edit-post', 'done' ) ) {
2463 printf( "<script type='text/javascript'>\n%s\n</script>\n", trim( $script ) );
2464 }
2465
2466 /*
2467 * If the 'postcustom' meta box is enabled, then we need to perform
2468 * some extra initialization on it.
2469 */
2470 $enable_custom_fields = (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true );
2471
2472 if ( $enable_custom_fields ) {
2473 $script = "( function( $ ) {
2474 if ( $('#postcustom').length ) {
2475 $( '#the-list' ).wpList( {
2476 addBefore: function( s ) {
2477 s.data += '&post_id=$post->ID';
2478 return s;
2479 },
2480 addAfter: function() {
2481 $('table#list-table').show();
2482 }
2483 });
2484 }
2485 } )( jQuery );";
2486 wp_enqueue_script( 'wp-lists' );
2487 wp_add_inline_script( 'wp-lists', $script );
2488 }
2489
2490 /*
2491 * Refresh nonces used by the meta box loader.
2492 *
2493 * The logic is very similar to that provided by post.js for the classic editor.
2494 */
2495 $script = "( function( $ ) {
2496 var check, timeout;
2497
2498 function schedule() {
2499 check = false;
2500 window.clearTimeout( timeout );
2501 timeout = window.setTimeout( function() { check = true; }, 300000 );
2502 }
2503
2504 $( document ).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) {
2505 var post_id, \$authCheck = $( '#wp-auth-check-wrap' );
2506
2507 if ( check || ( \$authCheck.length && ! \$authCheck.hasClass( 'hidden' ) ) ) {
2508 if ( ( post_id = $( '#post_ID' ).val() ) && $( '#_wpnonce' ).val() ) {
2509 data['wp-refresh-metabox-loader-nonces'] = {
2510 post_id: post_id
2511 };
2512 }
2513 }
2514 }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) {
2515 var nonces = data['wp-refresh-metabox-loader-nonces'];
2516
2517 if ( nonces ) {
2518 if ( nonces.replace ) {
2519 if ( nonces.replace.metabox_loader_nonce && window._wpMetaBoxUrl && wp.url ) {
2520 window._wpMetaBoxUrl= wp.url.addQueryArgs( window._wpMetaBoxUrl, { 'meta-box-loader-nonce': nonces.replace.metabox_loader_nonce } );
2521 }
2522
2523 if ( nonces.replace._wpnonce ) {
2524 $( '#_wpnonce' ).val( nonces.replace._wpnonce );
2525 }
2526 }
2527 }
2528 }).ready( function() {
2529 schedule();
2530 });
2531 } )( jQuery );";
2532 wp_add_inline_script( 'heartbeat', $script );
2533
2534 // Reset meta box data.
2535 $wp_meta_boxes = $_original_meta_boxes;
2536}
2537
2538/**
2539 * Renders the hidden form required for the meta boxes form.
2540 *
2541 * @since 5.0.0
2542 *
2543 * @param WP_Post $post Current post object.
2544 */
2545function the_block_editor_meta_box_post_form_hidden_fields( $post ) {
2546 $form_extra = '';
2547 if ( 'auto-draft' === $post->post_status ) {
2548 $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />";
2549 }
2550 $form_action = 'editpost';
2551 $nonce_action = 'update-post_' . $post->ID;
2552 $form_extra .= "<input type='hidden' id='post_ID' name='post_ID' value='" . esc_attr( $post->ID ) . "' />";
2553 $referer = wp_get_referer();
2554 $current_user = wp_get_current_user();
2555 $user_id = $current_user->ID;
2556 wp_nonce_field( $nonce_action );
2557
2558 /*
2559 * Some meta boxes hook into these actions to add hidden input fields in the classic post form.
2560 * For backward compatibility, we can capture the output from these actions,
2561 * and extract the hidden input fields.
2562 */
2563 ob_start();
2564 /** This filter is documented in wp-admin/edit-form-advanced.php */
2565 do_action( 'edit_form_after_title', $post );
2566 /** This filter is documented in wp-admin/edit-form-advanced.php */
2567 do_action( 'edit_form_advanced', $post );
2568 $classic_output = ob_get_clean();
2569
2570 $classic_elements = wp_html_split( $classic_output );
2571 $hidden_inputs = '';
2572 foreach ( $classic_elements as $element ) {
2573 if ( ! str_starts_with( $element, '<input ' ) ) {
2574 continue;
2575 }
2576
2577 if ( preg_match( '/\stype=[\'"]hidden[\'"]\s/', $element ) ) {
2578 echo $element;
2579 }
2580 }
2581 ?>
2582 <input type="hidden" id="user-id" name="user_ID" value="<?php echo (int) $user_id; ?>" />
2583 <input type="hidden" id="hiddenaction" name="action" value="<?php echo esc_attr( $form_action ); ?>" />
2584 <input type="hidden" id="originalaction" name="originalaction" value="<?php echo esc_attr( $form_action ); ?>" />
2585 <input type="hidden" id="post_type" name="post_type" value="<?php echo esc_attr( $post->post_type ); ?>" />
2586 <input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo esc_attr( $post->post_status ); ?>" />
2587 <input type="hidden" id="referredby" name="referredby" value="<?php echo $referer ? esc_url( $referer ) : ''; ?>" />
2588
2589 <?php
2590 if ( 'draft' !== get_post_status( $post ) ) {
2591 wp_original_referer_field( true, 'previous' );
2592 }
2593 echo $form_extra;
2594 wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
2595 wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
2596 // Permalink title nonce.
2597 wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false );
2598
2599 /**
2600 * Adds hidden input fields to the meta box save form.
2601 *
2602 * Hook into this action to print `<input type="hidden" ... />` fields, which will be POSTed back to
2603 * the server when meta boxes are saved.
2604 *
2605 * @since 5.0.0
2606 *
2607 * @param WP_Post $post The post that is being edited.
2608 */
2609 do_action( 'block_editor_meta_box_hidden_fields', $post );
2610}
2611
2612/**
2613 * Disables block editor for wp_navigation type posts so they can be managed via the UI.
2614 *
2615 * @since 5.9.0
2616 * @access private
2617 *
2618 * @param bool $value Whether the CPT supports block editor or not.
2619 * @param string $post_type Post type.
2620 * @return bool Whether the block editor should be disabled or not.
2621 */
2622function _disable_block_editor_for_navigation_post_type( $value, $post_type ) {
2623 if ( 'wp_navigation' === $post_type ) {
2624 return false;
2625 }
2626
2627 return $value;
2628}
2629
2630/**
2631 * This callback disables the content editor for wp_navigation type posts.
2632 * Content editor cannot handle wp_navigation type posts correctly.
2633 * We cannot disable the "editor" feature in the wp_navigation's CPT definition
2634 * because it disables the ability to save navigation blocks via REST API.
2635 *
2636 * @since 5.9.0
2637 * @access private
2638 *
2639 * @param WP_Post $post An instance of WP_Post class.
2640 */
2641function _disable_content_editor_for_navigation_post_type( $post ) {
2642 $post_type = get_post_type( $post );
2643 if ( 'wp_navigation' !== $post_type ) {
2644 return;
2645 }
2646
2647 remove_post_type_support( $post_type, 'editor' );
2648}
2649
2650/**
2651 * This callback enables content editor for wp_navigation type posts.
2652 * We need to enable it back because we disable it to hide
2653 * the content editor for wp_navigation type posts.
2654 *
2655 * @since 5.9.0
2656 * @access private
2657 *
2658 * @see _disable_content_editor_for_navigation_post_type
2659 *
2660 * @param WP_Post $post An instance of WP_Post class.
2661 */
2662function _enable_content_editor_for_navigation_post_type( $post ) {
2663 $post_type = get_post_type( $post );
2664 if ( 'wp_navigation' !== $post_type ) {
2665 return;
2666 }
2667
2668 add_post_type_support( $post_type, 'editor' );
2669}
2670
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1