PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 2.7.5
Jetpack – WP Security, Backup, Speed, & Growth v2.7.5
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 / nova.php

nova.php in Jetpack – WP Security, Backup, Speed, & Growth 2.7.5, at modules/custom-post-types/nova.php

1,022 lines 29.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * Plugin Name: Nova - Restaurant Websites Shouldn't Suck
5 * Plugin URI: http://wordpress.org/extend/plugins/nova/
6 * Author: Automattic
7 * Version: 0.1
8 * License: GPL2+
9 * Text Domain: nova
10 * Domain Path: /languages/
11 */
12
13 /*
14 * Put the following code in your themee's Food Menu Page Template to customize the markup of the menu.
15
16 if ( class_exists( 'Nova_Restaurant' ) ) {
17 Nova_Restaurant::init( array(
18 'menu_tag' => 'section',
19 'menu_class' => 'menu-items',
20 'menu_header_tag' => 'header',
21 'menu_header_class' => 'menu-group-header',
22 'menu_title_tag' => 'h1',
23 'menu_title_class' => 'menu-group-title',
24 'menu_description_tag' => 'div',
25 'menu_description_class' => 'menu-group-description',
26 ) );
27 }
28
29 */
30
31 /* @todo
32
33 Bulk/Quick edit response of Menu Item rows is broken.
34
35 Drag and Drop reordering.
36 */
37
38 class Nova_Restaurant {
39 const MENU_ITEM_POST_TYPE = 'nova_menu_item';
40 const MENU_ITEM_LABEL_TAX = 'nova_menu_item_label';
41 const MENU_TAX = 'nova_menu';
42
43 var $version = '0.1';
44
45 protected $default_menu_item_loop_markup = array(
46 'menu_tag' => 'section',
47 'menu_class' => 'menu-items',
48 'menu_header_tag' => 'header',
49 'menu_header_class' => 'menu-group-header',
50 'menu_title_tag' => 'h1',
51 'menu_title_class' => 'menu-group-title',
52 'menu_description_tag' => 'div',
53 'menu_description_class' => 'menu-group-description',
54 );
55
56 protected $menu_item_loop_markup = array();
57 protected $menu_item_loop_last_term_id = false;
58 protected $menu_item_loop_current_term = false;
59
60 static function init( $menu_item_loop_markup = array() ) {
61 static $instance = false;
62
63 if ( !$instance ) {
64 $instance = new Nova_Restaurant;
65 }
66
67 if ( $menu_item_loop_markup ) {
68 $instance->menu_item_loop_markup = wp_parse_args( $menu_item_loop_markup, $this->default_menu_item_loop_markup );
69 }
70
71 return $instance;
72 }
73
74 function __construct() {
75 if ( ! $this->site_supports_nova() )
76 return;
77
78 $this->register_taxonomies();
79 $this->register_post_types();
80 add_action( 'admin_menu', array( $this, 'add_admin_menus' ) );
81
82 // Always sort menu items correctly
83 add_action( 'parse_query', array( $this, 'sort_menu_item_queries_by_menu_order' ) );
84 add_filter( 'posts_results', array( $this, 'sort_menu_item_queries_by_menu_taxonomy' ), 10, 2 );
85
86 add_action( 'wp_insert_post', array( $this, 'add_post_meta' ) );
87
88 $this->menu_item_loop_markup = $this->default_menu_item_loop_markup;
89
90 // Only output our Menu Item Loop Marup on a real blog view. Not feeds, XML-RPC, admin, etc.
91 add_filter( 'template_include', array( $this, 'setup_menu_item_loop_markup__in_filter' ) );
92 }
93
94 /**
95 * Should this Custom Post Type be made available?
96 */
97 function site_supports_nova() {
98 // If we're on WordPress.com, and it has the menu site vertical.
99 if ( function_exists( 'site_vertical' ) && 'nova_menu' == site_vertical() )
100 return true;
101
102 // Else, if the current theme requests it.
103 if ( current_theme_supports( self::MENU_ITEM_POST_TYPE ) )
104 return true;
105
106 // Otherwise, say no unless something wants to filter us to say yes.
107 return (bool) apply_filters( 'jetpack_enable_cpt', false, self::MENU_ITEM_POST_TYPE );
108 }
109
110 /* Setup */
111
112 function register_taxonomies() {
113 register_taxonomy( self::MENU_ITEM_LABEL_TAX, self::MENU_ITEM_POST_TYPE, array(
114 'labels' => array(
115 'name' => __( 'Menu Item Labels', 'nova' ),
116 'singular_name' => __( 'Menu Item Label', 'nova' ),
117 'search_items' => __( 'Search Menu Item Labels', 'nova' ),
118 'popular_items' => __( 'Popular Labels', 'nova' ),
119 'all_items' => __( 'All Menu Item Labels', 'nova' ),
120 'edit_item' => __( 'Edit Menu Item Label', 'nova' ),
121 'view_item' => __( 'View Menu Item Label', 'nova' ),
122 'update_item' => __( 'Update Menu Item Label', 'nova' ),
123 'add_new_item' => __( 'Add New Menu Item Label', 'nova' ),
124 'new_item_name' => __( 'New Menu Item Label Name', 'nova' ),
125 'separate_items_with_commas' => __( 'Separate Labels with commas', 'nova' ),
126 'add_or_remove_items' => __( 'Add or remove Labels', 'nova' ),
127 'choose_from_most_used' => __( 'Choose from the most used Labels', 'nova' ),
128 ),
129 'no_tagcloud' => __( 'No Labels found', 'nova' ),
130
131 'hierarchical' => false,
132 ) );
133
134 register_taxonomy( self::MENU_TAX, self::MENU_ITEM_POST_TYPE, array(
135 'labels' => array(
136 'name' => __( 'Food Menus', 'nova' ),
137 'singular_name' => __( 'Food Menu', 'nova' ),
138 'search_items' => __( 'Search Menus', 'nova' ),
139 'all_items' => __( 'All Menus', 'nova' ),
140 'parent_item' => __( 'Parent Menu', 'nova' ),
141 'parent_item_colon' => __( 'Parent Menu:', 'nova' ),
142 'edit_item' => __( 'Edit Menu', 'nova' ),
143 'view_item' => __( 'View Menu', 'nova' ),
144 'update_item' => __( 'Update Menu', 'nova' ),
145 'add_new_item' => __( 'Add New Menu', 'nova' ),
146 'new_item_name' => __( 'New Menu Name', 'nova' ),
147 ),
148 'rewrite' => array(
149 'slug' => 'menu',
150 'with_front' => false,
151 'hierarchical' => true,
152 ),
153
154 'hierarchical' => true,
155 'show_tagcloud' => false,
156 'query_var' => 'menu',
157 ) );
158 }
159
160 function register_post_types() {
161 register_post_type( self::MENU_ITEM_POST_TYPE, array(
162 'description' => __( "Items on your restaurant's menu", 'nova' ),
163
164 'labels' => array(
165 'name' => __( 'Menu Items', 'nova' ),
166 'singular_name' => __( 'Menu Item', 'nova' ),
167 'menu_name' => __( 'Food Menus', 'nova' ),
168 'all_items' => __( 'Menu Items', 'nova' ),
169 'add_new' => __( 'Add One Item', 'nova' ),
170 'add_new_item' => __( 'Add One Item', 'nova' ),
171 'edit_item' => __( 'Edit Menu Item', 'nova' ),
172 'new_item' => __( 'New Menu Item', 'nova' ),
173 'view_item' => __( 'View Menu Item', 'nova' ),
174 'search_items' => __( 'Search Menu Items', 'nova' ),
175 'not_found' => __( 'No Menu Items found', 'nova' ),
176 'not_found_in_trash' => __( 'No Menu Items found in Trash', 'nova' ),
177 ),
178 'supports' => array(
179 'title',
180 'editor',
181 'thumbnail',
182 'excerpt',
183 ),
184 'rewrite' => array(
185 'slug' => 'item',
186 'with_front' => false,
187 'feeds' => false,
188 'pages' => false,
189 ),
190 'register_meta_box_cb' => array( $this, 'register_menu_item_meta_boxes' ),
191
192 'public' => true,
193 'show_ui' => true, // set to false to replace with custom UI
194 'menu_position' => 20, // below Pages
195 'capability_type' => 'page',
196 'map_meta_cap' => true,
197 'has_archive' => false,
198 'query_var' => 'item',
199 ) );
200 }
201
202 /* Query */
203
204 function is_menu_item_query( $query ) {
205 if (
206 ( isset( $query->query_vars['taxonomy'] ) && self::MENU_TAX == $query->query_vars['taxonomy'] )
207 ||
208 ( isset( $query->query_vars['post_type'] ) && self::MENU_ITEM_POST_TYPE == $query->query_vars['post_type'] )
209 ) {
210 return true;
211 }
212
213 return false;
214 }
215
216 function sort_menu_item_queries_by_menu_order( $query ) {
217 if ( !$this->is_menu_item_query( $query ) ) {
218 return;
219 }
220
221 $query->query_vars['orderby'] = 'menu_order';
222 $query->query_vars['order'] = 'ASC';
223
224 // For now, just turn off paging so we can sort by taxonmy later
225 // If we want paging in the future, we'll need to add the taxonomy sort here (or at least before the DB query is made)
226 $query->query_vars['posts_per_page'] = -1;
227 }
228
229 function sort_menu_item_queries_by_menu_taxonomy( $posts, $query ) {
230 if ( !$posts ) {
231 return $posts;
232 }
233
234 if ( !$this->is_menu_item_query( $query ) ) {
235 return $posts;
236 }
237
238 $grouped_by_term = array();
239
240 foreach ( $posts as $post ) {
241 $term = $this->get_menu_item_menu_leaf( $post->ID );
242 if ( !$term || is_wp_error( $term ) ) {
243 $term_id = 0;
244 } else {
245 $term_id = $term->term_id;
246 }
247
248 if ( !isset( $grouped_by_term["$term_id"] ) ) {
249 $grouped_by_term["$term_id"] = array();
250 }
251
252 $grouped_by_term["$term_id"][] = $post;
253 }
254
255 $term_order = get_option( 'nova_menu_order', array() );
256
257 $return = array();
258 foreach ( $term_order as $term_id ) {
259 if ( isset( $grouped_by_term["$term_id"] ) ) {
260 $return = array_merge( $return, $grouped_by_term["$term_id"] );
261 unset( $grouped_by_term["$term_id"] );
262 }
263 }
264
265 foreach ( $grouped_by_term as $term_id => $posts ) {
266 $return = array_merge( $return, $posts );
267 }
268
269 return $return;
270 }
271
272 /* Admin */
273
274 function add_admin_menus() {
275 $hook = add_submenu_page(
276 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE,
277 __( 'Add Many Items', 'nova' ),
278 __( 'Add Many Items', 'nova' ),
279 'edit_pages',
280 'add_many_nova_items',
281 array( $this, 'add_many_new_items_page' )
282 );
283
284 add_action( "load-$hook", array( $this, 'add_many_new_items_page_load' ) );
285
286 add_action( 'current_screen', array( $this, 'current_screen_load' ) );
287
288 $submenu_item = array_pop( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
289 $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE][11] = $submenu_item;
290
291 ksort( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
292
293 $this->setup_menu_item_columns();
294
295 wp_register_script( 'nova-menu-checkboxes', plugins_url( 'js/menu-checkboxes.js', __FILE__ ), array( 'jquery' ), $this->version, true );
296
297 }
298
299 function current_screen_load() {
300 $screen = get_current_screen();
301 if ( 'edit-nova_menu_item' !== $screen->id ) {
302 return;
303 }
304
305 $this->edit_menu_items_page_load();
306 add_filter( 'admin_notices', array( $this, 'admin_notices' ) );
307 }
308
309 /* Edit Items List */
310
311 function admin_notices() {
312 if ( isset( $_GET['nova_reordered'] ) )
313 printf( '<div class="updated"><p>%s</p></div>', __('Menu Items re-ordered.', 'nova' ) );
314 }
315
316 function no_title_sorting( $columns ) {
317 if ( isset( $columns['title'] ) )
318 unset( $columns['title'] );
319 return $columns;
320 }
321
322 function setup_menu_item_columns() {
323 add_filter( sprintf( 'manage_edit-%s_sortable_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'no_title_sorting' ) );
324 add_filter( sprintf( 'manage_%s_posts_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_columns' ) );
325
326 add_action( sprintf( 'manage_%s_posts_custom_column', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_column_callback' ), 10, 2 );
327 }
328
329 function menu_item_columns( $columns ) {
330 unset( $columns['date'], $columns['likes'] );
331
332 $columns['labels'] = __( 'Labels', 'nova' );
333 $columns['price'] = __( 'Price', 'nova' );
334 $columns['order'] = __( 'Order', 'nova' );
335
336 return $columns;
337 }
338
339 function menu_item_column_callback( $column, $post_id ) {
340 $screen = get_current_screen();
341
342 switch ( $column ) {
343 case 'labels' :
344 $this->list_admin_labels( $post_id );
345 break;
346 case 'price' :
347 $this->display_price( $post_id );
348 break;
349 case 'order' :
350 $url = admin_url( $screen->parent_file );
351
352 $up_url = add_query_arg( array(
353 'action' => 'move-item-up',
354 'post_id' => (int) $post_id,
355 ), wp_nonce_url( $url, 'nova_move_item_up_' . $post_id ) );
356
357 $down_url = add_query_arg( array(
358 'action' => 'move-item-down',
359 'post_id' => (int) $post_id,
360 ), wp_nonce_url( $url, 'nova_move_item_down_' . $post_id ) );
361 $menu_item = get_post($post_id);
362 $this->get_menu_by_post_id( $post_id );
363 ?>
364 <input type="hidden" class="menu-order-value" name="nova_order[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $menu_item->menu_order ) ?>" />
365 <input type="hidden" class='nova-menu-term' name="nova_menu_term[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $this->get_menu_by_post_id( $post_id )->term_id ); ?>">
366
367 <span class="hide-if-js">
368 &nbsp; &nbsp; &mdash; <a class="nova-move-item-up" data-post-id="<?php echo (int) $post_id; ?>" href="<?php echo esc_url( $up_url ); ?>">up</a>
369 <br />
370 &nbsp; &nbsp; &mdash; <a class="nova-move-item-down" data-post-id="<?php echo (int) $post_id; ?>" href="<?php echo esc_url( $down_url ); ?>">down</a>
371 </span>
372 <?php
373 break;
374 }
375 }
376
377 function get_menu_by_post_id( $post_id = null ) {
378 if ( ! $post_id )
379 return false;
380
381 $terms = get_the_terms( $post_id, self::MENU_TAX );
382 return array_pop( $terms );
383 }
384
385 /**
386 * Fires on a menu edit page. We might have drag-n-drop reordered
387 */
388 function maybe_reorder_menu_items() {
389 // make sure we clicked our button
390 if ( ! ( isset( $_REQUEST['menu_reorder_submit'] ) && $_REQUEST['menu_reorder_submit'] === __( 'Re-order', 'nova' ) ) )
391 return;
392 ;
393
394 // make sure we have the nonce
395 if ( ! ( isset( $_REQUEST['drag-drop-reorder'] ) && wp_verify_nonce( $_REQUEST['drag-drop-reorder'], 'drag-drop-reorder' ) ) )
396 return;
397
398 $term_pairs = array_map( 'absint', $_REQUEST['nova_menu_term'] );
399 $order_pairs = array_map( 'absint', $_REQUEST['nova_order'] );
400
401 foreach( $order_pairs as $ID => $menu_order ) {
402 $ID = absint( $ID );
403 unset( $order_pairs[$ID] );
404 if ( $ID < 0 )
405 continue;
406
407 $post = get_post( $ID );
408 if ( ! $post )
409 continue;
410
411 // save a write if the order hasn't changed
412 if ( $menu_order != $post->menu_order )
413 wp_update_post( compact( 'ID', 'menu_order' ) );
414
415 // save a write if the term hasn't changed
416 if ( $term_pairs[$ID] != $this->get_menu_by_post_id( $ID )->term_id )
417 wp_set_object_terms( $ID, $term_pairs[$ID], self::MENU_TAX );
418
419 }
420
421 $redirect = add_query_arg( array(
422 'post_type' => self::MENU_ITEM_POST_TYPE,
423 'nova_reordered' => '1'
424 ), admin_url( 'edit.php' ) );
425 wp_safe_redirect( $redirect );
426 exit;
427
428 }
429
430 function edit_menu_items_page_load() {
431 if ( isset( $_GET['action'] ) ) {
432 $this->handle_menu_item_actions();
433 }
434
435 $this->maybe_reorder_menu_items();
436
437 wp_enqueue_style( 'nova-edit-items', plugins_url( 'css/edit-items.css', __FILE__ ), array(), $this->version );
438 wp_enqueue_script( 'nova-drag-drop', plugins_url( 'js/nova-drag-drop.js', __FILE__ ), array( 'jquery-ui-sortable' ), $this->version, true );
439 wp_localize_script( 'nova-drag-drop', '_novaDragDrop', array(
440 'nonce' => wp_create_nonce( 'drag-drop-reorder' ),
441 'nonceName' => 'drag-drop-reorder',
442 'reorder' => __( 'Re-order', 'nova' ),
443 'reorderName' => 'menu_reorder_submit'
444 ) );
445 add_action( 'the_post', array( $this, 'show_menu_titles_in_menu_item_list' ) );
446 }
447
448 function handle_menu_item_actions() {
449 $action = (string) $_GET['action'];
450
451 switch ( $action ) {
452 case 'move-item-up' :
453 case 'move-item-down' :
454 $reorder = false;
455
456 $post_id = (int) $_GET['post_id'];
457
458 $term = $this->get_menu_item_menu_leaf( $post_id );
459
460 // Get all posts in that term
461 $query = new WP_Query( array(
462 'taxonomy' => self::MENU_TAX,
463 'term' => $term->slug,
464 ) );
465
466 $order = array();
467 foreach ( $query->posts as $post ) {
468 $order[] = $post->ID;
469 }
470
471 if ( 'move-item-up' == $action ) {
472 check_admin_referer( 'nova_move_item_up_' . $post_id );
473
474 $first_post_id = $order[0];
475 if ( $post_id == $first_post_id ) {
476 break;
477 }
478
479 foreach ( $order as $menu_order => $order_post_id ) {
480 if ( $post_id != $order_post_id ) {
481 continue;
482 }
483
484 $swap_post_id = $order[$menu_order - 1];
485 $order[$menu_order - 1] = $post_id;
486 $order[$menu_order] = $swap_post_id;
487
488 $reorder = true;
489 break;
490 }
491 } else {
492 check_admin_referer( 'nova_move_item_down_' . $post_id );
493
494 $last_post_id = end( $order );
495 if ( $post_id == $last_post_id ) {
496 break;
497 }
498
499 foreach ( $order as $menu_order => $order_post_id ) {
500 if ( $post_id != $order_post_id ) {
501 continue;
502 }
503
504 $swap_post_id = $order[$menu_order + 1];
505 $order[$menu_order + 1] = $post_id;
506 $order[$menu_order] = $swap_post_id;
507
508 $reorder = true;
509 }
510 }
511
512 if ( $reorder ) {
513 foreach ( $order as $menu_order => $ID ) {
514 wp_update_post( compact( 'ID', 'menu_order' ) );
515 }
516 }
517
518 break;
519 case 'move-menu-up' :
520 case 'move-menu-down' :
521 $reorder = false;
522
523 $term_id = (int) $_GET['term_id'];
524
525 $terms = $this->get_menus();
526
527 $order = array();
528 foreach ( $terms as $term ) {
529 $order[] = $term->term_id;
530 }
531
532 if ( 'move-menu-up' == $action ) {
533 check_admin_referer( 'nova_move_menu_up_' . $term_id );
534
535 $first_term_id = $order[0];
536 if ( $term_id == $first_term_id ) {
537 break;
538 }
539
540 foreach ( $order as $menu_order => $order_term_id ) {
541 if ( $term_id != $order_term_id ) {
542 continue;
543 }
544
545 $swap_term_id = $order[$menu_order - 1];
546 $order[$menu_order - 1] = $term_id;
547 $order[$menu_order] = $swap_term_id;
548
549 $reorder = true;
550 break;
551 }
552 } else {
553 check_admin_referer( 'nova_move_menu_down_' . $term_id );
554
555 $last_term_id = end( $order );
556 if ( $term_id == $last_term_id ) {
557 break;
558 }
559
560 foreach ( $order as $menu_order => $order_term_id ) {
561 if ( $term_id != $order_term_id ) {
562 continue;
563 }
564
565 $swap_term_id = $order[$menu_order + 1];
566 $order[$menu_order + 1] = $term_id;
567 $order[$menu_order] = $swap_term_id;
568
569 $reorder = true;
570 }
571 }
572
573 if ( $reorder ) {
574 update_option( 'nova_menu_order', $order );
575 }
576
577 break;
578 default :
579 return;
580 }
581
582 $redirect = add_query_arg( array(
583 'post_type' => self::MENU_ITEM_POST_TYPE,
584 'nova_reordered' => '1'
585 ), admin_url( 'edit.php' ) );
586 wp_safe_redirect( $redirect );
587 exit;
588 }
589
590 /*
591 * Add menu title rows to the list table
592 */
593 function show_menu_titles_in_menu_item_list( $post ) {
594 global $wp_list_table;
595
596 static $last_term_id = false;
597
598 $term = $this->get_menu_item_menu_leaf( $post->ID );
599 if ( false !== $last_term_id && $last_term_id === $term->term_id ) {
600 return;
601 }
602
603 $last_term_id = $term->term_id;
604
605 $parent_count = 0;
606 $current_term = $term;
607 while ( $current_term->parent ) {
608 $parent_count++;
609 $current_term = get_term( $current_term->parent, self::MENU_TAX );
610 }
611
612 $non_order_column_count = $wp_list_table->get_column_count() - 1;
613
614 $screen = get_current_screen();
615
616 $url = admin_url( $screen->parent_file );
617
618 $up_url = add_query_arg( array(
619 'action' => 'move-menu-up',
620 'term_id' => (int) $term->term_id,
621 ), wp_nonce_url( $url, 'nova_move_menu_up_' . $term->term_id ) );
622
623 $down_url = add_query_arg( array(
624 'action' => 'move-menu-down',
625 'term_id' => (int) $term->term_id,
626 ), wp_nonce_url( $url, 'nova_move_menu_down_' . $term->term_id ) );
627
628 ?>
629 <tr class="no-items menu-label-row" data-term_id="<?php echo esc_attr( $term->term_id ) ?>">
630 <td class="colspanchange" colspan="<?php echo (int) $non_order_column_count; ?>">
631 <h3><?php
632 echo str_repeat( ' &mdash; ', (int) $parent_count );
633 echo esc_html( sanitize_term_field( 'name', $term->name, $term->term_id, self::MENU_TAX, 'display' ) );
634 ?></h3>
635 </td>
636 <td>
637 <a class="nova-move-menu-up" title="<?php esc_attr_e( 'Move menu section up' ); ?>" href="<?php echo esc_url( $up_url ); ?>"><?php esc_html_e( 'UP' ); ?></a>
638 <br />
639 <a class="nova-move-menu-down" title="<?php esc_attr_e( 'Move menu section down' ); ?>" href="<?php echo esc_url( $down_url ); ?>"><?php esc_html_e( 'DOWN' ); ?></a>
640 </td>
641 </tr>
642 <?php
643 }
644
645 /* Edit Many Items */
646
647 function add_many_new_items_page_load() {
648 if ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
649 $this->process_form_request();
650 exit;
651 }
652
653 $this->enqueue_many_items_styles();
654 $this->enqueue_many_items_scripts();
655 }
656
657 function enqueue_many_items_styles() {
658 wp_enqueue_style( 'nova-many-items', plugins_url( 'css/many-items.css', __FILE__ ), array(), $this->version );
659 }
660
661 function enqueue_many_items_scripts() {
662 wp_enqueue_script( 'nova-many-items', plugins_url( 'js/many-items.js', __FILE__ ), array( 'jquery' ), $this->version, true );
663 }
664
665 function process_form_request() {
666 if ( !isset( $_POST['nova_title'] ) || !is_array( $_POST['nova_title'] ) ) {
667 return;
668 }
669
670 $is_ajax = !empty( $_POST['ajax'] );
671
672 if ( $is_ajax ) {
673 check_ajax_referer( 'nova_many_items' );
674 } else {
675 check_admin_referer( 'nova_many_items' );
676 }
677
678 foreach ( array_keys( $_POST['nova_title'] ) as $key ) :
679 // $_POST is already slashed
680 $post_details = array(
681 'post_status' => 'publish',
682 'post_type' => self::MENU_ITEM_POST_TYPE,
683 'post_content' => $_POST['nova_content'][$key],
684 'post_title' => $_POST['nova_title'][$key],
685 'tax_input' => array(
686 self::MENU_ITEM_LABEL_TAX => $_POST['nova_labels'][$key],
687 self::MENU_TAX => $_POST['nova_menu_tax'],
688 ),
689 );
690
691 $post_id = wp_insert_post( $post_details );
692 if ( !$post_id || is_wp_error( $post_id ) ) {
693 continue;
694 }
695
696 $this->set_price( $post_id, isset( $_POST['nova_price'][$key] ) ? stripslashes( $_POST['nova_price'][$key] ) : '' );
697
698 if ( $is_ajax ) :
699 $post = get_post( $post_id );
700 $GLOBALS['post'] = $post;
701 setup_postdata( $post );
702
703 ?>
704 <td><?php the_title(); ?></td>
705 <td><?php the_content(); ?></td>
706 <td><?php $this->display_price(); ?></td>
707 <td><?php $this->list_labels( $post_id ); ?></td>
708 <?php
709 endif;
710
711 endforeach;
712
713 if ( $is_ajax ) {
714 exit;
715 }
716
717 wp_safe_redirect( admin_url( 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) );
718 exit;
719 }
720
721 function add_many_new_items_page() {
722 ?>
723 <div class="wrap">
724 <h2><?php esc_html_e( 'Add Many Items', 'nova' ); ?></h2>
725
726 <p><?php _e( 'Use the <kbd>TAB</kbd> key on your keyboard to move between colums and the <kbd>ENTER</kbd> or <kbd>RETURN</kbd> key to save each row and move on to the next.', 'nova' ); ?></p>
727
728 <form method="post" action="" enctype="multipart/form-data">
729 <p><?php wp_dropdown_categories( array(
730 'id' => 'nova-menu-tax',
731 'name' => 'nova_menu_tax',
732 'taxonomy' => self::MENU_TAX,
733 'hide_empty' => false,
734 'hierarchical' => true,
735 ) ); ?></p>
736
737 <table class="many-items-table wp-list-table widefat">
738 <thead>
739 <tr>
740 <th scope="col"><?php esc_html_e( 'Name', 'nova' ); ?></th>
741 <th scope="col"><?php esc_html_e( 'Description', 'nova' ); ?></th>
742 <th scope="col"><?php esc_html_e( 'Price', 'nova' ); ?></th>
743 <th scope="col"><?php _e( 'Labels: <small>spicy, favorite, etc.</small>', 'nova' ); ?></th>
744 </tr>
745 </thead>
746 <tbody>
747 <tr>
748 <td><input type="text" name="nova_title[]" aria-required="true" /></td>
749 <td><textarea name="nova_content[]" cols="20" rows="2"></textarea>
750 <td><input type="text" name="nova_price[]" /></td>
751 <td><input type="text" name="nova_labels[]" /></td>
752 </tr>
753 </tbody>
754 <tfoot>
755 <tr>
756 <th></th>
757 <th></th>
758 <th></th>
759 <th scope="col"><em><?php esc_html_e( 'Separate Labels with commas', 'nova' ); ?></em></th>
760 </tr>
761 </tfoot>
762 </table>
763
764 <p class="submit">
765 <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Add These New Menu Items', 'nova' ); ?>" />
766 <?php wp_nonce_field( 'nova_many_items' ); ?>
767 </p>
768 </form>
769 </div>
770 <?php
771 }
772
773 /* Edit One Item */
774
775 function register_menu_item_meta_boxes() {
776 wp_enqueue_script( 'nova-menu-checkboxes' );
777
778 add_meta_box( 'menu_item_price', __( 'Price', 'nova' ), array( $this, 'menu_item_price_meta_box' ), null, 'side', 'high' );
779 }
780
781 function menu_item_price_meta_box( $post, $meta_box ) {
782 $price = $this->get_price( $post->ID );
783 ?>
784 <label for="nova-price-<?php echo (int) $post->ID; ?>" class="screen-reader-text"><?php esc_html_e( 'Price', 'nova' ); ?></label>
785 <input type="text" id="nova-price-<?php echo (int) $post->ID; ?>" class="widefat" name="nova_price[<?php echo (int) $post->ID; ?>]" value="<?php echo esc_attr( $price ); ?>" />
786 <?php
787 }
788
789 function add_post_meta( $post_id ) {
790 if ( !isset( $_POST['nova_price'][$post_id] ) ) {
791 return;
792 }
793
794 $this->set_price( $post_id, stripslashes( $_POST['nova_price'][$post_id] ) );
795 }
796
797 /* Data */
798
799 function get_menus( $args = array() ) {
800 $args = wp_parse_args( $args, array(
801 'hide_empty' => false,
802 ) );
803
804 $terms = get_terms( self::MENU_TAX, $args );
805 if ( !$terms || is_wp_error( $terms ) ) {
806 return array();
807 }
808
809 $terms_by_id = array();
810 foreach ( $terms as $term ) {
811 $terms_by_id["{$term->term_id}"] = $term;
812 }
813
814 $term_order = get_option( 'nova_menu_order', array() );
815
816 $return = array();
817 foreach ( $term_order as $term_id ) {
818 if ( isset( $terms_by_id["$term_id"] ) ) {
819 $return[] = $terms_by_id["$term_id"];
820 unset( $terms_by_id["$term_id"] );
821 }
822 }
823
824 foreach ( $terms_by_id as $term_id => $term ) {
825 $return[] = $term;
826 }
827
828 return $return;
829 }
830
831 function get_menu_item_menu_leaf( $post_id ) {
832 // Get first menu taxonomy "leaf"
833 $term_ids = wp_get_object_terms( $post_id, self::MENU_TAX, array( 'fields' => 'ids' ) );
834
835 foreach ( $term_ids as $term_id ) {
836 $children = get_term_children( $term_id, self::MENU_TAX );
837 if ( !$children ) {
838 break;
839 }
840 }
841
842 return get_term( $term_id, self::MENU_TAX );
843 }
844
845 function list_labels( $post_id = 0 ) {
846 $post = get_post( $post_id );
847 echo get_the_term_list( $post->ID, self::MENU_ITEM_LABEL_TAX, '', _x( ', ', 'Nova label separator', 'nova' ), '' );
848 }
849
850 function list_admin_labels( $post_id = 0 ) {
851 $post = get_post( $post_id );
852 $labels = get_the_terms( $post->ID, self::MENU_ITEM_LABEL_TAX );
853 if ( !empty( $labels ) ) {
854 $out = array();
855 foreach ( $labels as $label ) {
856 $out[] = sprintf( '<a href="%s">%s</a>',
857 esc_url( add_query_arg( array(
858 'post_type' => self::MENU_ITEM_POST_TYPE,
859 'taxonomy' => self::MENU_ITEM_LABEL_TAX,
860 'term' => $label->slug
861 ), 'edit.php' ) ),
862 esc_html( sanitize_term_field( 'name', $label->name, $label->term_id, self::MENU_ITEM_LABEL_TAX, 'display' ) )
863 );
864 }
865
866 echo join( _x( ', ', 'Nova label separator', 'nova' ), $out );
867 } else {
868 esc_html_e( 'No Labels', 'nova' );
869 }
870 }
871
872 function set_price( $post_id = 0, $price = '' ) {
873 $post = get_post( $post_id );
874
875 return update_post_meta( $post->ID, 'nova_price', $price );
876 }
877
878 function get_price( $post_id = 0 ) {
879 $post = get_post( $post_id );
880
881 return get_post_meta( $post->ID, 'nova_price', true );
882 }
883
884 function display_price( $post_id = 0 ) {
885 echo esc_html( $this->get_price( $post_id ) );
886 }
887
888 /* Menu Item Loop Markup */
889
890 /* Does not support nested loops */
891
892 function get_menu_item_loop_markup( $field = null ) {
893 return $this->menu_item_loop_markup;
894 }
895
896 /**
897 * Sets up the loop markup.
898 * Attached to the 'template_include' *filter*,
899 * which fires only during a real blog view (not in admin, feeds, etc.)
900 *
901 * @param string Template File
902 * @return string Template File. VERY Important.
903 */
904 function setup_menu_item_loop_markup__in_filter( $template ) {
905 add_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
906
907 return $template;
908 }
909
910 /**
911 * If the Query is a Menu Item Query, start outputing the Menu Item Loop Marku
912 * Attached to the 'loop_start' action.
913 *
914 * @param WP_Query
915 */
916 function start_menu_item_loop( $query ) {
917 if ( !$this->is_menu_item_query( $query ) ) {
918 return;
919 }
920
921 $this->menu_item_loop_last_term_id = false;
922 $this->menu_item_loop_current_term = false;
923
924 add_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
925 add_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
926 }
927
928 /**
929 * Outputs the Menu Item Loop Marku
930 * Attached to the 'the_post' action.
931 *
932 * @param WP_Post
933 */
934 function menu_item_loop_each_post( $post ) {
935 $this->menu_item_loop_current_term = $this->get_menu_item_menu_leaf( $post->ID );
936
937 if ( false === $this->menu_item_loop_last_term_id ) {
938 // We're at the very beginning of the loop
939
940 $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
941 $this->menu_item_loop_header(); // Output the menu's header
942 } elseif ( $this->menu_item_loop_last_term_id != $this->menu_item_loop_current_term->term_id ) {
943 // We're not at the very beginning but still need to start a new menu section. End the previous menu section first.
944
945 $this->menu_item_loop_close_element( 'menu' ); // End the previous menu section
946 $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
947 $this->menu_item_loop_header(); // Output the menu's header
948 }
949
950 $this->menu_item_loop_last_term_id = $this->menu_item_loop_current_term->term_id;
951 }
952
953 /**
954 * If the Query is a Menu Item Query, stop outputing the Menu Item Loop Marku
955 * Attached to the 'loop_end' action.
956 *
957 * @param WP_Query
958 */
959 function stop_menu_item_loop( $query ) {
960 if ( !$this->is_menu_item_query( $query ) ) {
961 return;
962 }
963
964 remove_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
965 remove_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
966 remove_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
967
968 $this->menu_item_loop_close_element( 'menu' ); // End the last menu section
969 }
970
971 /**
972 * Outputs the Menu Group Header
973 */
974 function menu_item_loop_header() {
975 $this->menu_item_loop_open_element( 'menu_header' );
976 $this->menu_item_loop_open_element( 'menu_title' );
977 echo esc_html( $this->menu_item_loop_current_term->name ); // @todo tax filter
978 $this->menu_item_loop_close_element( 'menu_title' );
979 if ( $this->menu_item_loop_current_term->description ) :
980 $this->menu_item_loop_open_element( 'menu_description' );
981 echo esc_html( $this->menu_item_loop_current_term->description ); // @todo kses, tax filter
982 $this->menu_item_loop_close_element( 'menu_description' );
983 endif;
984 $this->menu_item_loop_close_element( 'menu_header' );
985 }
986
987 /**
988 * Outputs a Menu Item Markup element opening tag
989 *
990 * @param string $field - Menu Item Markup settings field
991 */
992 function menu_item_loop_open_element( $field ) {
993 $markup = $this->get_menu_item_loop_markup();
994 echo '<' . tag_escape( $markup["{$field}_tag"] ) . $this->menu_item_loop_class( $markup["{$field}_class"] ) . ">\n";
995 }
996
997 /**
998 * Outputs a Menu Item Markup element closing tag
999 *
1000 * @param string $field - Menu Item Markup settings field
1001 */
1002 function menu_item_loop_close_element( $field ) {
1003 $markup = $this->get_menu_item_loop_markup();
1004 echo '</' . tag_escape( $markup["{$field}_tag"] ) . ">\n";
1005 }
1006
1007 /**
1008 * Returns a Menu Item Markup element's class attribute
1009 *
1010 * @param string $class
1011 * @return string HTML class attribute with leading whitespace
1012 */
1013 function menu_item_loop_class( $class ) {
1014 if ( !$class ) {
1015 return '';
1016 }
1017
1018 return ' class="' . esc_attr( $class ) . '"';
1019 }
1020 }
1021
1022 add_action( 'init', array( 'Nova_Restaurant', 'init' ) );