PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 10.3
Jetpack – WP Security, Backup, Speed, & Growth v10.3
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / custom-post-types / comics.php
comics.php
540 lines 19.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Automattic\Jetpack\Assets;
4
5 class Jetpack_Comic {
6 const POST_TYPE = 'jetpack-comic';
7
8 static function init() {
9 static $instance = false;
10
11 if ( ! $instance )
12 $instance = new Jetpack_Comic();
13
14 return $instance;
15 }
16
17 /**
18 * Conditionally hook into WordPress.
19 *
20 * Themes must declare that they support this module by adding
21 * add_theme_support( 'jetpack-comic' ); during after_setup_theme.
22 *
23 * If no theme support is found there is no need to hook into
24 * WordPress. We'll just return early instead.
25 */
26 function __construct() {
27 // Make sure the post types are loaded for imports
28 add_action( 'import_start', array( $this, 'register_post_types' ) );
29
30 // Add to REST API post type allowed list.
31 add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_type' ) );
32
33 // If called via REST API, we need to register later in lifecycle
34 add_action( 'restapi_theme_init', array( $this, 'maybe_register_post_types' ) );
35
36 // Return early if theme does not support Jetpack Comic.
37 if ( ! ( $this->site_supports_comics() ) )
38 return;
39
40 $this->register_post_types();
41
42 add_action( 'pre_get_posts', array( $this, 'add_posts_to_loop' ) );
43
44 // In order for the Feedbag job to find Comic posts, we need to circumvent any pretty
45 // URLs in the RSS feed given to Feedbag in favor of /?p=123&post_type=jetpack-comic
46 add_filter( 'the_permalink_rss', array( $this, 'custom_permalink_for_feedbag' ) );
47
48 // There are some cases (like when Feedbag is fetching posts) that the comics
49 // post type needs to be registered no matter what, but none of the UI needs to be
50 // available.
51
52 add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
53
54 if ( function_exists( 'queue_publish_post' ) ) {
55 add_action( 'publish_jetpack-comic', 'queue_publish_post', 10, 2 );
56 }
57
58 add_action( 'pre_get_posts', array( $this, 'include_in_feeds' ) );
59
60 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
61
62 add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( $this, 'manage_posts_columns' ) );
63 add_action( 'manage_' . self::POST_TYPE . '_posts_custom_column', array( $this, 'manage_posts_custom_column' ), 10, 2 );
64 add_image_size( 'jetpack-comic-thumb', 150, 0, false );
65
66 // Enable front-end uploading for users special enough.
67 if ( current_user_can( 'upload_files' ) && current_user_can( 'edit_posts' ) ) {
68 add_action( 'wp_ajax_jetpack_comic_upload', array( $this, 'upload' ) );
69 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
70 }
71
72 /**
73 * Add a "Convert to Comic" and "Convert to Post" option to the bulk
74 * edit dropdowns.
75 */
76 add_action( 'admin_footer-edit.php', array( $this, 'admin_footer' ) );
77 add_action( 'load-edit.php', array( $this, 'bulk_edit' ) );
78 add_action( 'admin_notices', array( $this, 'bulk_edit_notices' ) );
79 }
80
81 public function admin_footer() {
82 $post_type = get_post_type();
83
84 ?>
85 <script type="text/javascript">
86 jQuery( document ).ready( function( $ ) {
87 <?php if ( ! $post_type || 'post' == $post_type ) { ?>
88 $( '<option>' )
89 .val( 'post2comic' )
90 .text( <?php echo json_encode( __( 'Convert to Comic', 'jetpack' ) ); ?> )
91 .appendTo( "select[name='action'], select[name='action2']" );
92 <?php } ?>
93 <?php if ( ! $post_type || self::POST_TYPE == $post_type ) { ?>
94 $( '<option>' )
95 .val( 'comic2post' )
96 .text( <?php echo json_encode( __( 'Convert to Post', 'jetpack' ) ); ?> )
97 .appendTo( "select[name='action'], select[name='action2']" );
98 <?php } ?>
99
100 $( '#message.jetpack-comic-post-type-conversion' ).remove().insertAfter( $( '.wrap h2:first' ) ).show();
101 });
102 </script>
103 <?php
104 }
105
106 /**
107 * Handle the "Convert to [Post|Comic]" bulk action.
108 */
109 public function bulk_edit() {
110 if ( empty( $_REQUEST['post'] ) )
111 return;
112
113 $wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
114 $action = $wp_list_table->current_action();
115
116 check_admin_referer( 'bulk-posts' );
117
118 if ( 'post2comic' == $action || 'comic2post' == $action ) {
119 if ( ! current_user_can( 'publish_posts' ) )
120 wp_die( __( 'You are not allowed to make this change.', 'jetpack' ) );
121
122 $post_ids = array_map( 'intval', $_REQUEST['post'] );
123
124 $modified_count = 0;
125
126 foreach ( $post_ids as $post_id ) {
127 $destination_post_type = ( $action == 'post2comic' ) ? self::POST_TYPE : 'post';
128 $origin_post_type = ( $destination_post_type == 'post' ) ? self::POST_TYPE : 'post';
129
130 if ( current_user_can( 'edit_post', $post_id ) ) {
131 $post = get_post( $post_id );
132
133 // Only convert posts that are post => comic or comic => post.
134 // (e.g., Ignore comic => comic, page => post, etc. )
135 if ( $post->post_type != $destination_post_type && $post->post_type == $origin_post_type ) {
136 $post_type_object = get_post_type_object( $destination_post_type );
137
138 if ( current_user_can( $post_type_object->cap->publish_posts ) ) {
139 set_post_type( $post_id, $destination_post_type );
140 $modified_count++;
141 }
142 }
143 }
144 }
145
146 $sendback = remove_query_arg( array( 'exported', 'untrashed', 'deleted', 'ids' ), wp_get_referer() );
147
148 if ( ! $sendback )
149 $sendback = add_query_arg( array( 'post_type', get_post_type() ), admin_url( 'edit.php' ) );
150
151 $pagenum = $wp_list_table->get_pagenum();
152 $sendback = add_query_arg( array( 'paged' => $pagenum, 'post_type_changed' => $modified_count ), $sendback );
153
154 wp_safe_redirect( $sendback );
155 exit();
156 }
157 }
158
159 /**
160 * Show the post conversion success notice.
161 */
162 public function bulk_edit_notices() {
163 global $pagenow;
164
165 if ( 'edit.php' == $pagenow && ! empty( $_GET['post_type_changed'] ) ) {
166 ?><div id="message" class="updated below-h2 jetpack-comic-post-type-conversion" style="display: none;"><p><?php
167 printf( _n( 'Post converted.', '%s posts converted', $_GET['post_type_changed'], 'jetpack' ), number_format_i18n( $_GET['post_type_changed'] ) );
168 ?></p></div><?php
169 }
170 }
171
172 public function register_scripts() {
173 wp_enqueue_style( 'jetpack-comics-style', plugins_url( 'comics/comics.css', __FILE__ ), array(), JETPACK__VERSION );
174 wp_style_add_data( 'jetpack-comics-style', 'rtl', 'replace' );
175
176 $is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
177 if ( ! $is_amp ) {
178 wp_enqueue_script(
179 'jetpack-comics',
180 Assets::get_file_url_for_environment(
181 '_inc/build/custom-post-types/comics/comics.min.js',
182 'modules/custom-post-types/comics/comics.js'
183 ),
184 array( 'jquery' ),
185 JETPACK__VERSION,
186 false
187 );
188
189 $options = array(
190 'nonce' => wp_create_nonce( 'jetpack_comic_upload_nonce' ),
191 'writeURL' => admin_url( 'admin-ajax.php?action=jetpack_comic_upload' ),
192 'labels' => array(
193 'dragging' => __( 'Drop images to upload', 'jetpack' ),
194 'uploading' => __( 'Uploading...', 'jetpack' ),
195 'processing' => __( 'Processing...', 'jetpack' ),
196 'unsupported' => __( "Sorry, your browser isn't supported. Upgrade at browsehappy.com.", 'jetpack' ),
197 'invalidUpload' => __( 'Only images can be uploaded here.', 'jetpack' ),
198 'error' => __( "Your upload didn't complete; try again later or cross your fingers and try again right now.", 'jetpack' ),
199 ),
200 );
201
202 wp_localize_script( 'jetpack-comics', 'Jetpack_Comics_Options', $options );
203 }
204 }
205
206 public function admin_enqueue_scripts() {
207 wp_enqueue_style( 'jetpack-comics-admin', plugins_url( 'comics/admin.css', __FILE__ ) );
208 }
209
210 public function maybe_register_post_types() {
211 // Return early if theme does not support Jetpack Comic.
212 if ( ! ( $this->site_supports_comics() ) )
213 return;
214
215 $this->register_post_types();
216 }
217
218 function register_post_types() {
219 if ( post_type_exists( self::POST_TYPE ) ) {
220 return;
221 }
222
223 register_post_type( self::POST_TYPE, array(
224 'description' => __( 'Comics', 'jetpack' ),
225 'labels' => array(
226 'name' => esc_html__( 'Comics', 'jetpack' ),
227 'singular_name' => esc_html__( 'Comic', 'jetpack' ),
228 'menu_name' => esc_html__( 'Comics', 'jetpack' ),
229 'all_items' => esc_html__( 'All Comics', 'jetpack' ),
230 'add_new' => esc_html__( 'Add New', 'jetpack' ),
231 'add_new_item' => esc_html__( 'Add New Comic', 'jetpack' ),
232 'edit_item' => esc_html__( 'Edit Comic', 'jetpack' ),
233 'new_item' => esc_html__( 'New Comic', 'jetpack' ),
234 'view_item' => esc_html__( 'View Comic', 'jetpack' ),
235 'search_items' => esc_html__( 'Search Comics', 'jetpack' ),
236 'not_found' => esc_html__( 'No Comics found', 'jetpack' ),
237 'not_found_in_trash' => esc_html__( 'No Comics found in Trash', 'jetpack' ),
238 'filter_items_list' => esc_html__( 'Filter comics list', 'jetpack' ),
239 'items_list_navigation' => esc_html__( 'Comics list navigation', 'jetpack' ),
240 'items_list' => esc_html__( 'Comics list', 'jetpack' ),
241 ),
242 'supports' => array(
243 'title',
244 'editor',
245 'thumbnail',
246 'comments',
247 'revisions',
248 'publicize', // Jetpack
249 'subscriptions', // wpcom
250 'shortlinks', // Jetpack
251 ),
252 'rewrite' => array(
253 'slug' => 'comic',
254 'with_front' => false,
255 ),
256 'taxonomies' => array(
257 'category',
258 'post_tag',
259 ),
260 // Only make the type public for sites that support Comics.
261 'public' => true,
262 'menu_position' => 5, // below Posts
263 'map_meta_cap' => true,
264 'has_archive' => true,
265 'query_var' => 'comic',
266 'show_in_rest' => true,
267 ) );
268 }
269
270 public function manage_posts_columns( $columns ) {
271 $new_columns = array(
272 'preview-jetpack-comic' => __( 'Preview', 'jetpack' ),
273 );
274 return array_merge( array_slice( $columns, 0, 2 ), $new_columns, array_slice( $columns, 2 ) );
275 }
276
277 public function manage_posts_custom_column( $column_name, $post_ID ) {
278 if ( 'preview-jetpack-comic' == $column_name && has_post_thumbnail( $post_ID ) ) {
279 echo get_the_post_thumbnail( $post_ID, 'jetpack-comic-thumb' );
280 }
281 }
282
283 /**
284 * The function url_to_postid() doesn't handle pretty permalinks
285 * for CPTs very well. When we're generating an RSS feed to be consumed
286 * for Feedbag (the Reader's feed storage mechanism), eschew
287 * a pretty URL for one that will get the post into the Reader.
288 *
289 * @see https://core.trac.wordpress.org/ticket/19744
290 * @param string $permalink The existing (possibly pretty) permalink.
291 */
292 public function custom_permalink_for_feedbag( $permalink ) {
293 global $post;
294
295 if ( ! empty( $GLOBALS['is_feedbag_rss_script'] ) && self::POST_TYPE == $post->post_type ) {
296 $permalink = home_url( add_query_arg( array( 'p' => $post->ID, 'post_type' => self::POST_TYPE ), '?' ) );
297 }
298
299 return $permalink;
300 }
301
302 /*
303 * Update messages for the Comic admin.
304 */
305 function updated_messages( $messages ) {
306 global $post;
307
308 $messages['jetpack-comic'] = array(
309 0 => '', // Unused. Messages start at index 1.
310 1 => sprintf( __( 'Comic updated. <a href="%s">View comic</a>', 'jetpack'), esc_url( get_permalink( $post->ID ) ) ),
311 2 => esc_html__( 'Custom field updated.', 'jetpack' ),
312 3 => esc_html__( 'Custom field deleted.', 'jetpack' ),
313 4 => esc_html__( 'Comic updated.', 'jetpack' ),
314 /* translators: %s: date and time of the revision */
315 5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Comic restored to revision from %s', 'jetpack'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
316 6 => sprintf( __( 'Comic published. <a href="%s">View comic</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
317 7 => esc_html__( 'Comic saved.', 'jetpack' ),
318 8 => sprintf( __( 'Comic submitted. <a target="_blank" href="%s">Preview comic</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
319 9 => sprintf( __( 'Comic scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview comic</a>', 'jetpack' ),
320 // translators: Publish box date format, see https://php.net/date
321 date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
322 10 => sprintf( __( 'Comic draft updated. <a target="_blank" href="%s">Preview comic</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
323 );
324
325 return $messages;
326 }
327
328 /**
329 * Should this Custom Post Type be made available?
330 */
331 public function site_supports_comics() {
332 /**
333 * @todo: Extract this out into a wpcom only file.
334 */
335 if ( 'blog-rss.php' == substr( $_SERVER['PHP_SELF'], -12 ) && count( $_SERVER['argv'] ) > 1 ) {
336 // blog-rss.php isn't run in the context of the target blog when the init action fires,
337 // so check manually whether the target blog supports comics.
338 switch_to_blog( $_SERVER['argv'][1] );
339 // The add_theme_support( 'jetpack-comic' ) won't fire on switch_to_blog, so check for Panel manually.
340 $supports_comics = ( ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() )
341 || current_theme_supports( self::POST_TYPE )
342 || get_stylesheet() == 'pub/panel' );
343 restore_current_blog();
344
345 /** This action is documented in modules/custom-post-types/nova.php */
346 return (bool) apply_filters( 'jetpack_enable_cpt', $supports_comics, self::POST_TYPE );
347 }
348
349 $supports_comics = false;
350
351 /**
352 * If we're on WordPress.com, and it has the menu site vertical.
353 * @todo: Extract this out into a wpcom only file.
354 */
355 if ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() ) {
356 $supports_comics = true;
357 }
358
359 /**
360 * Else, if the current theme requests it.
361 */
362 if ( current_theme_supports( self::POST_TYPE ) ) {
363 $supports_comics = true;
364 }
365
366 /**
367 * Filter it in case something else knows better.
368 */
369 /** This action is documented in modules/custom-post-types/nova.php */
370 return (bool) apply_filters( 'jetpack_enable_cpt', $supports_comics, self::POST_TYPE );
371 }
372
373 /**
374 * Anywhere that a feed is displaying posts, show comics too.
375 *
376 * @param WP_Query $query
377 */
378 public function include_in_feeds( $query ) {
379 if ( ! $query->is_feed() )
380 return;
381
382 // Don't modify the query if the post type isn't public.
383 if ( ! get_post_type_object( 'jetpack-comic' )->public )
384 return;
385
386 $query_post_types = $query->get( 'post_type' );
387
388 if ( empty( $query_post_types ) )
389 $query_post_types = 'post';
390
391 if ( ! is_array( $query_post_types ) )
392 $query_post_types = array( $query_post_types );
393
394 if ( in_array( 'post', $query_post_types ) ) {
395 $query_post_types[] = self::POST_TYPE;
396 $query->set( 'post_type', $query_post_types );
397 }
398 }
399
400 /**
401 * API endpoint for front-end image uploading.
402 */
403 public function upload() {
404 global $content_width;
405
406 header( 'Content-Type: application/json' );
407
408 if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'jetpack_comic_upload_nonce' ) )
409 die( json_encode( array( 'error' => __( 'Invalid or expired nonce.', 'jetpack' ) ) ) );
410
411 $_POST['action'] = 'wp_handle_upload';
412
413 $image_id_arr = array();
414 $image_error_arr = array();
415
416 $i = 0;
417
418 while ( isset( $_FILES['image_' . $i ] ) ) {
419 // Create attachment for the image.
420 $image_id = media_handle_upload( "image_$i", 0 );
421
422 if ( is_wp_error( $image_id ) ) {
423 $error = array( $image_id, $image_id->get_error_message() );
424 array_push( $image_error_arr, $error );
425 } else {
426 array_push( $image_id_arr, $image_id );
427 }
428
429 $i++;
430 }
431
432 if ( count( $image_id_arr ) == 0 ) {
433 // All image uploads failed.
434 $rv = array( 'error' => '' );
435
436 foreach ( $image_error_arr as $error )
437 $rv['error'] .= $error[1] . "\n";
438 }
439 else {
440 if ( count( $image_id_arr ) == 1 ) {
441 $image_id = $image_id_arr[0];
442
443 // Get the image
444 $image_src = get_the_guid( $image_id );
445 $image_dims = wp_get_attachment_image_src( $image_id, 'full' );
446
447 // Take off 10px of width to account for padding and border. @todo make this smarter.
448 if ( $content_width )
449 $image_width = $content_width - 10;
450 else
451 $image_width = $image_dims[1] - 10;
452
453 $post_content = '<a href="' . esc_attr( $image_src ) .'"><img src="' . esc_attr( $image_src ) . '?w=' . esc_attr( $image_width ) . '" alt="' . esc_attr( $_FILES['image_0']['name'] ) . '" class="size-full wp-image alignnone" id="i-' . esc_attr( $image_id ) . '" data-filename="' . esc_attr( $_FILES['image_0']['name'] ) . '" /></a>';
454 }
455 else {
456 $post_content = '[gallery ids="' . esc_attr( implode( ',', $image_id_arr ) ) . '"]';
457 }
458
459 // Create a new post with the image(s)
460 $post_id = wp_insert_post( array(
461 'post_content' => $post_content,
462 'post_type' => 'jetpack-comic',
463 'post_status' => 'draft',
464 ),
465 true
466 );
467
468 if ( is_wp_error( $post_id, 'WP_Error' ) ) {
469 // Failed to create the post.
470 $rv = array( 'error' => $post_id->get_error_message() );
471
472 // Delete the uploaded images.
473 foreach ( $image_id_arr as $image_id ) {
474 wp_delete_post( $image_id, true );
475 }
476 }
477 else {
478 foreach ( $image_id_arr as $image_id ) {
479 wp_update_post( array(
480 'ID' => $image_id,
481 'post_parent' => $post_id
482 ) );
483 }
484
485 if ( current_theme_supports( 'post-thumbnails' ) && count( $image_id_arr ) == 1 )
486 set_post_thumbnail( $post_id, $image_id_arr[0] );
487
488 $rv = array( 'url' => add_query_arg( array( 'post' => $post_id, 'action' => 'edit' ), admin_url( 'post.php' ) ) );
489 }
490 }
491
492 die( json_encode( $rv ) );
493 }
494
495 public function add_posts_to_loop( $query ) {
496 // Add comic posts to the tag and category pages.
497 if ( ! is_admin() && $query->is_main_query() && ( $query->is_category() || $query->is_tag() ) ) {
498 $post_types = $query->get( 'post_type' );
499
500 if ( ! $post_types || 'post' == $post_types )
501 $post_types = array( 'post', self::POST_TYPE );
502 else if ( is_array( $post_types ) )
503 $post_types[] = self::POST_TYPE;
504
505 $query->set( 'post_type', $post_types );
506 }
507
508 return $query;
509 }
510
511 /**
512 * Add to REST API post type allowed list.
513 */
514 public function allow_rest_api_type( $post_types ) {
515 $post_types[] = self::POST_TYPE;
516 return $post_types;
517 }
518
519 }
520
521 add_action( 'init', array( 'Jetpack_Comic', 'init' ) );
522
523
524 function comics_welcome_email( $welcome_email, $blog_id, $user_id, $password, $title, $meta ) {
525 if ( ( isset( $meta['vertical'] ) && 'comics' == $meta['vertical'] ) || has_blog_sticker( 'vertical-comics', $blog_id ) ) {
526 return __( "Welcome! Ready to publish your first strip?
527
528 Your webcomic's new site is ready to go. Get started by <a href=\"BLOG_URLwp-admin/customize.php#title\">setting your comic's title and tagline</a> so your readers know what it's all about.
529
530 Looking for more help with setting up your site? Check out the WordPress.com <a href=\"https://learn.wordpress.com/\" target=\"_blank\">beginner's tutorial</a> and the <a href=\"https://en.support.wordpress.com/comics/\" target=\"_blank\">guide to comics on WordPress.com</a>. Dive right in by <a href=\"BLOG_URLwp-admin/customize.php#title\">publishing your first strip!</a>
531
532 Lots of laughs,
533 The WordPress.com Team", 'jetpack' );
534 }
535
536 return $welcome_email;
537 }
538
539 add_filter( 'update_welcome_email_pre_replacement', 'comics_welcome_email', 10, 6 );
540