PluginProbe
Bogo / trunk
Bogo vtrunk
3.9.3 trunk 1.0 1.1 2.0 2.0.1 2.1 2.1.1 2.1.2 2.1.3 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5 2.6 2.6.1 2.7 2.8 2.8.1 2.9 3.0 3.0.1 All 52 releases
bogo / includes / post.php

post.php in Bogo trunk, at includes/post.php

709 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /* Post Meta */
4
5 add_action( 'init',
6
7 function() {
8 $post_types = bogo_localizable_post_types();
9
10 $auth_callback = function ( $allowed, $meta_key, $object_id, $user_id ) {
11 return user_can( $user_id, 'edit_post', $object_id );
12 };
13
14 foreach ( $post_types as $post_type ) {
15 register_post_meta( $post_type,
16 '_locale',
17 array(
18 'type' => 'string',
19 'single' => true,
20 'auth_callback' => $auth_callback,
21 'show_in_rest' => true,
22 )
23 );
24
25 register_post_meta( $post_type,
26 '_original_post',
27 array(
28 'type' => 'string',
29 'single' => true,
30 'auth_callback' => $auth_callback,
31 'show_in_rest' => true,
32 )
33 );
34 }
35 },
36
37 10, 0
38 );
39
40 /* Post Template */
41
42 add_filter( 'body_class', 'bogo_body_class', 10, 2 );
43
44 function bogo_body_class( $classes, $classes_to_add ) {
45 $locale = bogo_language_tag( get_locale() );
46 $locale = esc_attr( $locale );
47
48 if ( $locale and ! in_array( $locale, $classes ) ) {
49 $classes[] = $locale;
50 }
51
52 return $classes;
53 }
54
55
56 add_filter( 'post_class', 'bogo_post_class', 10, 3 );
57
58 function bogo_post_class( $classes, $classes_to_add, $post_id ) {
59 $locale = bogo_get_post_locale( $post_id );
60 $locale = bogo_language_tag( $locale );
61 $locale = esc_attr( $locale );
62
63 if ( $locale and ! in_array( $locale, $classes ) ) {
64 $classes[] = $locale;
65 }
66
67 return $classes;
68 }
69
70
71 function bogo_get_post_locale( $post_id ) {
72 $locale = get_post_meta( $post_id, '_locale', true );
73
74 if ( empty( $locale ) ) {
75 $locale = bogo_get_default_locale();
76 }
77
78 return $locale;
79 }
80
81
82 function bogo_localizable_post_types() {
83 $localizable = apply_filters( 'bogo_localizable_post_types',
84 array( 'post', 'page' )
85 );
86
87 $localizable = array_diff(
88 $localizable,
89 array( 'attachment', 'revision', 'nav_menu_item' )
90 );
91
92 return $localizable;
93 }
94
95
96 function bogo_is_localizable_post_type( $post_type ) {
97 return in_array( $post_type, bogo_localizable_post_types(), true );
98 }
99
100
101 function bogo_count_posts( $locale, $post_type = 'post' ) {
102 global $wpdb;
103
104 if (
105 ! bogo_is_available_locale( $locale ) or
106 ! bogo_is_localizable_post_type( $post_type )
107 ) {
108 return false;
109 }
110
111 if ( bogo_is_default_locale( $locale ) ) {
112 $count = $wpdb->get_var( $wpdb->prepare(
113 "SELECT COUNT(1) FROM %i LEFT JOIN %i AS postmeta ON ID = postmeta.post_id AND meta_key = '_locale' WHERE post_type = %s AND post_status = 'publish' AND (meta_value LIKE %s OR meta_id IS NULL)",
114 $wpdb->posts,
115 $wpdb->postmeta,
116 $post_type,
117 $locale
118 ) );
119 } else {
120 $count = $wpdb->get_var( $wpdb->prepare(
121 "SELECT COUNT(1) FROM %i LEFT JOIN %i AS postmeta ON ID = postmeta.post_id AND meta_key = '_locale' WHERE post_type = %s AND post_status = 'publish' AND meta_value LIKE %s",
122 $wpdb->posts,
123 $wpdb->postmeta,
124 $post_type,
125 $locale
126 ) );
127 }
128
129 return (int) $count;
130 }
131
132
133 function bogo_get_post_translations( $post_id = 0 ) {
134 $post = get_post( $post_id );
135
136 if ( ! $post ) {
137 return false;
138 }
139
140 static $translations = array();
141
142 if ( isset( $translations[$post->ID] ) ) {
143 return $translations[$post->ID];
144 }
145
146 $original_post = get_post_meta( $post->ID, '_original_post', true );
147
148 // For back-compat
149 if ( empty( $original_post ) ) {
150 $original_post = $post->ID;
151 }
152
153 $args = array(
154 'bogo_suppress_locale_query' => true,
155 'posts_per_page' => -1,
156 'post_status' => 'any',
157 'post_type' => $post->post_type,
158 'meta_key' => '_original_post',
159 'meta_value' => $original_post,
160 );
161
162 $q = new WP_Query();
163 $posts = $q->query( $args );
164
165 // For back-compat
166 if (
167 is_int( $original_post ) and
168 $p = get_post( $original_post ) and
169 'trash' !== get_post_status( $p )
170 ) {
171 array_unshift( $posts, $p );
172 }
173
174 $translations[$post->ID] = array();
175
176 foreach ( $posts as $p ) {
177 if ( $p->ID === $post->ID ) {
178 continue;
179 }
180
181 $locale = bogo_get_post_locale( $p->ID );
182
183 if ( ! bogo_is_available_locale( $locale ) ) {
184 continue;
185 }
186
187 if ( ! isset( $translations[$post->ID][$locale] ) ) {
188 $translations[$post->ID][$locale] = $p;
189 }
190 }
191
192 $translations[$post->ID] = array_filter( $translations[$post->ID] );
193
194 return $translations[$post->ID];
195 }
196
197
198 function bogo_get_post_translation( $post_id, $locale ) {
199 $translations = bogo_get_post_translations( $post_id );
200
201 if ( isset( $translations[$locale] ) ) {
202 return $translations[$locale];
203 }
204
205 return false;
206 }
207
208
209 function bogo_get_page_by_path( $page_path, $locale = null, $post_type = 'page' ) {
210 global $wpdb;
211
212 if ( ! bogo_is_available_locale( $locale ) ) {
213 $locale = bogo_get_default_locale();
214 }
215
216 $page_path = rawurlencode( urldecode( $page_path ) );
217 $page_path = str_replace( '%2F', '/', $page_path );
218 $page_path = str_replace( '%20', ' ', $page_path );
219
220 $parts = explode( '/', trim( $page_path, '/' ) );
221 $parts = array_map( 'esc_sql', $parts );
222 $parts = array_map( 'sanitize_title_for_query', $parts );
223
224 $in_string = implode( ',', array_map(
225 static function ( $p ) use ( $wpdb ) {
226 return $wpdb->prepare( '%s', $p );
227 },
228 $parts
229 ) );
230
231 if ( bogo_is_default_locale( $locale ) ) {
232 $pages = $wpdb->get_results( $wpdb->prepare(
233 "SELECT ID, post_name, post_parent FROM %i LEFT JOIN %i AS postmeta ON ID = postmeta.post_id AND meta_key = '_locale' WHERE post_name IN ($in_string) AND (post_type = %s OR post_type = 'attachment') AND (meta_value LIKE %s OR meta_id IS NULL)",
234 $wpdb->posts,
235 $wpdb->postmeta,
236 $post_type,
237 $locale
238 ), OBJECT_K );
239 } else {
240 $pages = $wpdb->get_results( $wpdb->prepare(
241 "SELECT ID, post_name, post_parent FROM %i LEFT JOIN %i AS postmeta ON ID = postmeta.post_id AND meta_key = '_locale' WHERE post_name IN ($in_string) AND (post_type = %s OR post_type = 'attachment') AND (meta_value LIKE %s)",
242 $wpdb->posts,
243 $wpdb->postmeta,
244 $post_type,
245 $locale
246 ), OBJECT_K );
247 }
248
249 $revparts = array_reverse( $parts );
250
251 $foundid = 0;
252
253 foreach ( (array) $pages as $page ) {
254 if ( $page->post_name !== $revparts[0] ) {
255 continue;
256 }
257
258 $count = 0;
259 $p = $page;
260
261 while ( ! empty( $p->post_parent ) and isset( $pages[$p->post_parent] ) ) {
262 $count++;
263 $parent = $pages[$p->post_parent];
264
265 if (
266 ! isset( $revparts[$count] ) or
267 $parent->post_name !== $revparts[$count]
268 ) {
269 break;
270 }
271
272 $p = $parent;
273 }
274
275 if (
276 empty( $p->post_parent ) and
277 $count + 1 === count( $revparts ) and
278 $p->post_name === $revparts[$count]
279 ) {
280 $foundid = $page->ID;
281 break;
282 }
283 }
284
285 if ( $foundid ) {
286 return get_page( $foundid );
287 }
288
289 return null;
290 }
291
292
293 function bogo_duplicate_post( $original_post, $locale ) {
294 $original_post = get_post( $original_post );
295
296 if (
297 ! $original_post or
298 ! bogo_is_localizable_post_type( get_post_type( $original_post ) ) or
299 'auto-draft' === get_post_status( $original_post )
300 ) {
301 return false;
302 }
303
304 if (
305 ! bogo_is_available_locale( $locale ) or
306 bogo_get_post_locale( $original_post->ID ) === $locale
307 ) {
308 return false;
309 }
310
311 if ( bogo_get_post_translation( $original_post->ID, $locale ) ) {
312 return false;
313 }
314
315 $postarr = array(
316 'post_content' => $original_post->post_content,
317 'post_title' => $original_post->post_title,
318 'post_name' => $original_post->post_name,
319 'post_excerpt' => $original_post->post_excerpt,
320 'post_status' => 'draft',
321 'post_type' => $original_post->post_type,
322 'comment_status' => $original_post->comment_status,
323 'ping_status' => $original_post->ping_status,
324 'post_password' => $original_post->post_password,
325 'post_content_filtered' => $original_post->post_content_filtered,
326 'post_parent' => $original_post->post_parent,
327 'menu_order' => $original_post->menu_order,
328 'post_mime_type' => $original_post->post_mime_type,
329 'tax_input' => array(),
330 'meta_input' => array(),
331 );
332
333 if ( ! empty( $original_post->post_parent ) ) {
334 $parent_translation = bogo_get_post_translation(
335 $original_post->post_parent, $locale
336 );
337
338 if ( $parent_translation ) {
339 $postarr['post_parent'] = $parent_translation->ID;
340 }
341 }
342
343 if ( $taxonomies = get_object_taxonomies( $original_post ) ) {
344 foreach ( $taxonomies as $taxonomy ) {
345 $terms = wp_get_post_terms( $original_post->ID,
346 $taxonomy, array( 'fields' => 'ids' )
347 );
348
349 if ( $terms and ! is_wp_error( $terms ) ) {
350 $postarr['tax_input'][$taxonomy] = $terms;
351 }
352 }
353 }
354
355 if ( $post_metas = get_post_meta( $original_post->ID ) ) {
356
357 $post_metas = array_map( function ( $post_meta ) {
358 return array_map( 'maybe_unserialize', (array) $post_meta );
359 }, $post_metas );
360
361 $postarr['meta_input'] = $post_metas;
362 }
363
364 $postarr = apply_filters( 'bogo_duplicate_post', $postarr,
365 $original_post, $locale
366 );
367
368 if ( $taxonomies = $postarr['tax_input'] ) {
369 $postarr['tax_input'] = array();
370 }
371
372 if ( $post_metas = $postarr['meta_input'] ) {
373 $postarr['meta_input'] = array();
374 }
375
376 $new_post_id = wp_insert_post( $postarr );
377
378 if ( $new_post_id ) {
379 if ( $taxonomies ) {
380 foreach ( $taxonomies as $taxonomy => $terms ) {
381 wp_set_post_terms( $new_post_id, $terms, $taxonomy );
382 }
383 }
384
385 if ( $post_metas ) {
386 foreach ( $post_metas as $meta_key => $meta_values ) {
387 if ( in_array( $meta_key, array( '_locale', '_original_post' ) ) ) {
388 continue;
389 }
390
391 foreach ( (array) $meta_values as $meta_value ) {
392 add_post_meta( $new_post_id, $meta_key, $meta_value );
393 }
394 }
395 }
396
397 update_post_meta( $new_post_id, '_locale', $locale );
398
399 $meta_original_post = get_post_meta( $original_post->ID,
400 '_original_post', true
401 );
402
403 if ( $meta_original_post ) {
404 update_post_meta( $new_post_id,
405 '_original_post', $meta_original_post
406 );
407 } else {
408 $original_post_guid = get_the_guid( $original_post );
409
410 if ( empty( $original_post_guid ) ) {
411 $original_post_guid = $original_post->ID;
412 }
413
414 $translations = bogo_get_post_translations( $original_post );
415
416 update_post_meta( $original_post->ID,
417 '_original_post', $original_post_guid
418 );
419
420 if ( $translations ) {
421 foreach ( $translations as $tr_locale => $tr_post ) {
422 update_post_meta( $tr_post->ID,
423 '_original_post', $original_post_guid
424 );
425 }
426 }
427
428 update_post_meta( $new_post_id,
429 '_original_post', $original_post_guid
430 );
431 }
432 }
433
434 return $new_post_id;
435 }
436
437
438 add_filter( 'get_pages', 'bogo_get_pages', 10, 2 );
439
440 function bogo_get_pages( $pages, $args ) {
441 if (
442 is_admin() or
443 ! bogo_is_localizable_post_type( $args['post_type'] ) or
444 ! empty( $args['bogo_suppress_locale_query'] )
445 ) {
446 return $pages;
447 }
448
449 $locale = isset( $args['lang'] ) ? $args['lang'] : get_locale();
450
451 if ( ! bogo_is_available_locale( $locale ) ) {
452 return $pages;
453 }
454
455 $new_pages = array();
456
457 foreach ( (array) $pages as $page ) {
458 $post_locale = bogo_get_post_locale( $page->ID );
459
460 if ( $post_locale === $locale ) {
461 $new_pages[] = $page;
462 }
463 }
464
465 return $new_pages;
466 }
467
468
469 add_action( 'save_post', 'bogo_save_post', 10, 2 );
470
471 function bogo_save_post( $post_id, $post ) {
472 if ( did_action( 'import_start' ) and ! did_action( 'import_end' ) ) {
473 // Importing
474 return;
475 }
476
477 if ( ! bogo_is_localizable_post_type( $post->post_type ) ) {
478 return;
479 }
480
481 $current_locales = get_post_meta( $post_id, '_locale' );
482 $locale = null;
483
484 if ( ! empty( $current_locales ) ) {
485 foreach ( $current_locales as $current_locale ) {
486 if ( bogo_is_available_locale( $current_locale ) ) {
487 $locale = $current_locale;
488 break;
489 }
490 }
491
492 if ( empty( $locale ) or 1 < count( $current_locales ) ) {
493 delete_post_meta( $post_id, '_locale' );
494 $current_locales = array();
495 }
496 }
497
498 if ( empty( $current_locales ) ) {
499 if ( bogo_is_available_locale( $locale ) ) {
500 // $locale = $locale;
501 } elseif (
502 ! empty( $_REQUEST['locale'] ) and
503 bogo_is_available_locale( $_REQUEST['locale'] )
504 ) {
505 $locale = $_REQUEST['locale'];
506 } elseif ( 'auto-draft' === get_post_status( $post_id ) ) {
507 $locale = bogo_get_user_locale();
508 } else {
509 $locale = bogo_get_default_locale();
510 }
511
512 add_post_meta( $post_id, '_locale', $locale, true );
513 }
514
515 $original_post = get_post_meta( $post_id, '_original_post', true );
516
517 if ( empty( $original_post ) ) {
518 $post_guid = get_the_guid( $post_id );
519
520 if ( empty( $post_guid ) ) {
521 $post_guid = $post_id;
522 }
523
524 $translations = bogo_get_post_translations( $post_id );
525
526 update_post_meta( $post_id, '_original_post', $post_guid );
527
528 if ( $translations ) {
529 foreach ( $translations as $tr_locale => $tr_post ) {
530 update_post_meta( $tr_post->ID, '_original_post', $post_guid );
531 }
532 }
533 }
534 }
535
536
537 add_filter( 'pre_wp_unique_post_slug', 'bogo_unique_post_slug', 10, 6 );
538
539 function bogo_unique_post_slug( $override_slug, $slug, $post_id, $post_status, $post_type, $post_parent ) {
540
541 if ( ! bogo_is_localizable_post_type( $post_type ) ) {
542 return $override_slug;
543 }
544
545 $locale = bogo_get_post_locale( $post_id );
546
547 if ( ! bogo_is_available_locale( $locale ) ) {
548 return $override_slug;
549 }
550
551 $override_slug = $slug;
552
553 $q = new WP_Query();
554
555 global $wp_rewrite;
556
557 $feeds = is_array( $wp_rewrite->feeds ) ? $wp_rewrite->feeds : array();
558
559 if ( is_post_type_hierarchical( $post_type ) ) {
560 $q_args = array(
561 'name' => $slug,
562 'lang' => $locale,
563 'post_type' => array( $post_type, 'attachment' ),
564 'post_parent' => $post_parent,
565 'post__not_in' => array( $post_id ),
566 'posts_per_page' => 1,
567 );
568
569 $is_bad_slug = in_array( $slug, $feeds ) ||
570 'embed' === $slug ||
571 preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug ) ||
572 apply_filters(
573 'wp_unique_post_slug_is_bad_hierarchical_slug', false,
574 $slug, $post_type, $post_parent
575 );
576
577 if ( ! $is_bad_slug ) {
578 $q_results = $q->query( $q_args );
579 $is_bad_slug = ! empty( $q_results );
580 }
581
582 if ( $is_bad_slug ) {
583 $suffix = 1;
584
585 while ( $is_bad_slug ) {
586 $suffix += 1;
587 $alt_slug = sprintf( '%s-%s',
588 bogo_truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ),
589 $suffix
590 );
591
592 $q_results = $q->query( array_merge(
593 $q_args,
594 array( 'name' => $alt_slug )
595 ) );
596
597 $is_bad_slug = ! empty( $q_results );
598 }
599
600 $override_slug = $alt_slug;
601 }
602
603 } else {
604 $q_args = array(
605 'name' => $slug,
606 'lang' => $locale,
607 'post_type' => $post_type,
608 'post__not_in' => array( $post_id ),
609 'posts_per_page' => 1,
610 );
611
612 $is_bad_slug = in_array( $slug, $feeds ) ||
613 'embed' === $slug ||
614 apply_filters(
615 'wp_unique_post_slug_is_bad_flat_slug', false,
616 $slug, $post_type
617 );
618
619 if ( ! $is_bad_slug ) {
620 $post = get_post( $post_id );
621
622 if (
623 'post' === $post_type and
624 ( ! $post or $post->post_name !== $slug ) and
625 preg_match( '/^[0-9]+$/', $slug )
626 ) {
627 $slug_num = intval( $slug );
628
629 if ( $slug_num ) {
630 $permastructs = array_values( array_filter(
631 explode( '/', get_option( 'permalink_structure' ) )
632 ) );
633 $postname_index = array_search( '%postname%', $permastructs );
634
635 $is_bad_slug = 0 === $postname_index ||
636 (
637 $postname_index &&
638 '%year%' === $permastructs[$postname_index - 1] &&
639 13 > $slug_num
640 ) ||
641 (
642 $postname_index &&
643 '%monthnum%' === $permastructs[$postname_index - 1] &&
644 32 > $slug_num
645 );
646 }
647 }
648 }
649
650 if ( ! $is_bad_slug ) {
651 $q_results = $q->query( $q_args );
652 $is_bad_slug = ! empty( $q_results );
653 }
654
655 if ( $is_bad_slug ) {
656 $suffix = 1;
657
658 while ( $is_bad_slug ) {
659 $suffix += 1;
660 $alt_slug = sprintf( '%s-%s',
661 bogo_truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ),
662 $suffix
663 );
664
665 $q_results = $q->query( array_merge(
666 $q_args,
667 array( 'name' => $alt_slug )
668 ) );
669
670 $is_bad_slug = ! empty( $q_results );
671 }
672
673 $override_slug = $alt_slug;
674 }
675 }
676
677 return $override_slug;
678 }
679
680
681 function bogo_truncate_post_slug( $slug, $length = 200 ) {
682 if ( strlen( $slug ) > $length ) {
683 $decoded_slug = urldecode( $slug );
684
685 if ( $decoded_slug === $slug ) {
686 $slug = substr( $slug, 0, $length );
687 } else {
688 $slug = utf8_uri_encode( $decoded_slug, $length );
689 }
690 }
691
692 return rtrim( $slug, '-' );
693 }
694
695
696 add_filter(
697 'wp_sitemaps_posts_query_args',
698 'bogo_sitemaps_posts_query_args',
699 10, 2
700 );
701
702 function bogo_sitemaps_posts_query_args( $args, $post_type ) {
703 if ( bogo_is_localizable_post_type( $post_type ) ) {
704 $args['bogo_suppress_locale_query'] = true;
705 }
706
707 return $args;
708 }
709