PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 8.8
Jetpack – WP Security, Backup, Speed, & Growth v8.8
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 8.8, at modules/custom-post-types/nova.php

1,301 lines 40.2 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 /*
6 * Put the following code in your theme's Food Menu Page Template to customize the markup of the menu.
7
8 if ( class_exists( 'Nova_Restaurant' ) ) {
9 Nova_Restaurant::init( array(
10 'menu_tag' => 'section',
11 'menu_class' => 'menu-items',
12 'menu_header_tag' => 'header',
13 'menu_header_class' => 'menu-group-header',
14 'menu_title_tag' => 'h1',
15 'menu_title_class' => 'menu-group-title',
16 'menu_description_tag' => 'div',
17 'menu_description_class' => 'menu-group-description',
18 ) );
19 }
20
21 */
22
23 /* @todo
24
25 Bulk/Quick edit response of Menu Item rows is broken.
26
27 Drag and Drop reordering.
28 */
29
30 class Nova_Restaurant {
31 const MENU_ITEM_POST_TYPE = 'nova_menu_item';
32 const MENU_ITEM_LABEL_TAX = 'nova_menu_item_label';
33 const MENU_TAX = 'nova_menu';
34
35 public $version = '0.1';
36
37 protected $default_menu_item_loop_markup = array(
38 'menu_tag' => 'section',
39 'menu_class' => 'menu-items',
40 'menu_header_tag' => 'header',
41 'menu_header_class' => 'menu-group-header',
42 'menu_title_tag' => 'h1',
43 'menu_title_class' => 'menu-group-title',
44 'menu_description_tag' => 'div',
45 'menu_description_class' => 'menu-group-description',
46 );
47
48 protected $menu_item_loop_markup = array();
49 protected $menu_item_loop_last_term_id = false;
50 protected $menu_item_loop_current_term = false;
51
52 static function init( $menu_item_loop_markup = array() ) {
53 static $instance = false;
54
55 if ( !$instance ) {
56 $instance = new Nova_Restaurant();
57 }
58
59 if ( $menu_item_loop_markup ) {
60 $instance->menu_item_loop_markup = wp_parse_args( $menu_item_loop_markup, $instance->default_menu_item_loop_markup );
61 }
62
63 return $instance;
64 }
65
66 function __construct() {
67 if ( ! $this->site_supports_nova() )
68 return;
69
70 $this->register_taxonomies();
71 $this->register_post_types();
72 add_action( 'admin_menu', array( $this, 'add_admin_menus' ) );
73 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_nova_styles' ) );
74 add_action( 'admin_head', array( $this, 'set_custom_font_icon' ) );
75
76 // Always sort menu items correctly
77 add_action( 'parse_query', array( $this, 'sort_menu_item_queries_by_menu_order' ) );
78 add_filter( 'posts_results', array( $this, 'sort_menu_item_queries_by_menu_taxonomy' ), 10, 2 );
79
80 add_action( 'wp_insert_post', array( $this, 'add_post_meta' ) );
81
82 $this->menu_item_loop_markup = $this->default_menu_item_loop_markup;
83
84 // Only output our Menu Item Loop Markup on a real blog view. Not feeds, XML-RPC, admin, etc.
85 add_filter( 'template_include', array( $this, 'setup_menu_item_loop_markup__in_filter' ) );
86
87 add_filter( 'enter_title_here', array( $this, 'change_default_title' ) );
88 add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
89 add_filter( 'dashboard_glance_items', array( $this, 'add_to_dashboard' ) );
90 }
91
92 /**
93 * Should this Custom Post Type be made available?
94 */
95 function site_supports_nova() {
96 // If we're on WordPress.com, and it has the menu site vertical.
97 if ( function_exists( 'site_vertical' ) && 'nova_menu' == site_vertical() )
98 return true;
99
100 // Else, if the current theme requests it.
101 if ( current_theme_supports( self::MENU_ITEM_POST_TYPE ) )
102 return true;
103
104 // Otherwise, say no unless something wants to filter us to say yes.
105 /**
106 * Allow something else to hook in and enable this CPT.
107 *
108 * @module custom-content-types
109 *
110 * @since 2.6.0
111 *
112 * @param bool false Whether or not to enable this CPT.
113 * @param string $var The slug for this CPT.
114 */
115 return (bool) apply_filters( 'jetpack_enable_cpt', false, self::MENU_ITEM_POST_TYPE );
116 }
117
118 /* Setup */
119
120 /**
121 * Register Taxonomies and Post Type
122 */
123 function register_taxonomies() {
124 if ( ! taxonomy_exists( self::MENU_ITEM_LABEL_TAX ) ) {
125 register_taxonomy( self::MENU_ITEM_LABEL_TAX, self::MENU_ITEM_POST_TYPE, array(
126 'labels' => array(
127 /* translators: this is about a food menu */
128 'name' => __( 'Menu Item Labels', 'jetpack' ),
129 /* translators: this is about a food menu */
130 'singular_name' => __( 'Menu Item Label', 'jetpack' ),
131 /* translators: this is about a food menu */
132 'search_items' => __( 'Search Menu Item Labels', 'jetpack' ),
133 'popular_items' => __( 'Popular Labels', 'jetpack' ),
134 /* translators: this is about a food menu */
135 'all_items' => __( 'All Menu Item Labels', 'jetpack' ),
136 /* translators: this is about a food menu */
137 'edit_item' => __( 'Edit Menu Item Label', 'jetpack' ),
138 /* translators: this is about a food menu */
139 'view_item' => __( 'View Menu Item Label', 'jetpack' ),
140 /* translators: this is about a food menu */
141 'update_item' => __( 'Update Menu Item Label', 'jetpack' ),
142 /* translators: this is about a food menu */
143 'add_new_item' => __( 'Add New Menu Item Label', 'jetpack' ),
144 /* translators: this is about a food menu */
145 'new_item_name' => __( 'New Menu Item Label Name', 'jetpack' ),
146 'separate_items_with_commas' => __( 'For example, spicy, favorite, etc. <br /> Separate Labels with commas', 'jetpack' ),
147 'add_or_remove_items' => __( 'Add or remove Labels', 'jetpack' ),
148 'choose_from_most_used' => __( 'Choose from the most used Labels', 'jetpack' ),
149 'items_list_navigation' => __( 'Menu item label list navigation', 'jetpack' ),
150 'items_list' => __( 'Menu item labels list', 'jetpack' ),
151 ),
152 'no_tagcloud' => __( 'No Labels found', 'jetpack' ),
153 'hierarchical' => false,
154 ) );
155 }
156
157 if ( ! taxonomy_exists( self::MENU_TAX ) ) {
158 register_taxonomy( self::MENU_TAX, self::MENU_ITEM_POST_TYPE, array(
159 'labels' => array(
160 /* translators: this is about a food menu */
161 'name' => __( 'Menu Sections', 'jetpack' ),
162 /* translators: this is about a food menu */
163 'singular_name' => __( 'Menu Section', 'jetpack' ),
164 /* translators: this is about a food menu */
165 'search_items' => __( 'Search Menu Sections', 'jetpack' ),
166 /* translators: this is about a food menu */
167 'all_items' => __( 'All Menu Sections', 'jetpack' ),
168 /* translators: this is about a food menu */
169 'parent_item' => __( 'Parent Menu Section', 'jetpack' ),
170 /* translators: this is about a food menu */
171 'parent_item_colon' => __( 'Parent Menu Section:', 'jetpack' ),
172 /* translators: this is about a food menu */
173 'edit_item' => __( 'Edit Menu Section', 'jetpack' ),
174 /* translators: this is about a food menu */
175 'view_item' => __( 'View Menu Section', 'jetpack' ),
176 /* translators: this is about a food menu */
177 'update_item' => __( 'Update Menu Section', 'jetpack' ),
178 /* translators: this is about a food menu */
179 'add_new_item' => __( 'Add New Menu Section', 'jetpack' ),
180 /* translators: this is about a food menu */
181 'new_item_name' => __( 'New Menu Sections Name', 'jetpack' ),
182 'items_list_navigation' => __( 'Menu section list navigation', 'jetpack' ),
183 'items_list' => __( 'Menu section list', 'jetpack' ),
184 ),
185 'rewrite' => array(
186 'slug' => 'menu',
187 'with_front' => false,
188 'hierarchical' => true,
189 ),
190 'hierarchical' => true,
191 'show_tagcloud' => false,
192 'query_var' => 'menu',
193 ) );
194 }
195 }
196
197 function register_post_types() {
198 if ( post_type_exists( self::MENU_ITEM_POST_TYPE ) ) {
199 return;
200 }
201
202 register_post_type( self::MENU_ITEM_POST_TYPE, array(
203 'description' => __( "Items on your restaurant's menu", 'jetpack' ),
204
205 'labels' => array(
206 /* translators: this is about a food menu */
207 'name' => __( 'Menu Items', 'jetpack' ),
208 /* translators: this is about a food menu */
209 'singular_name' => __( 'Menu Item', 'jetpack' ),
210 /* translators: this is about a food menu */
211 'menu_name' => __( 'Food Menus', 'jetpack' ),
212 /* translators: this is about a food menu */
213 'all_items' => __( 'Menu Items', 'jetpack' ),
214 /* translators: this is about a food menu */
215 'add_new' => __( 'Add One Item', 'jetpack' ),
216 /* translators: this is about a food menu */
217 'add_new_item' => __( 'Add Menu Item', 'jetpack' ),
218 /* translators: this is about a food menu */
219 'edit_item' => __( 'Edit Menu Item', 'jetpack' ),
220 /* translators: this is about a food menu */
221 'new_item' => __( 'New Menu Item', 'jetpack' ),
222 /* translators: this is about a food menu */
223 'view_item' => __( 'View Menu Item', 'jetpack' ),
224 /* translators: this is about a food menu */
225 'search_items' => __( 'Search Menu Items', 'jetpack' ),
226 /* translators: this is about a food menu */
227 'not_found' => __( 'No Menu Items found', 'jetpack' ),
228 /* translators: this is about a food menu */
229 'not_found_in_trash' => __( 'No Menu Items found in Trash', 'jetpack' ),
230 'filter_items_list' => __( 'Filter menu items list', 'jetpack' ),
231 'items_list_navigation' => __( 'Menu item list navigation', 'jetpack' ),
232 'items_list' => __( 'Menu items list', 'jetpack' ),
233 ),
234 'supports' => array(
235 'title',
236 'editor',
237 'thumbnail',
238 'excerpt',
239 ),
240 'rewrite' => array(
241 'slug' => 'item',
242 'with_front' => false,
243 'feeds' => false,
244 'pages' => false,
245 ),
246 'register_meta_box_cb' => array( $this, 'register_menu_item_meta_boxes' ),
247
248 'public' => true,
249 'show_ui' => true, // set to false to replace with custom UI
250 'menu_position' => 20, // below Pages
251 'capability_type' => 'page',
252 'map_meta_cap' => true,
253 'has_archive' => false,
254 'query_var' => 'item',
255 ) );
256 }
257
258
259 /**
260 * Update messages for the Menu Item admin.
261 */
262 function updated_messages( $messages ) {
263 global $post;
264
265 $messages[self::MENU_ITEM_POST_TYPE] = array(
266 0 => '', // Unused. Messages start at index 1.
267 /* translators: this is about a food menu */
268 1 => sprintf( __( 'Menu item updated. <a href="%s">View item</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
269 2 => esc_html__( 'Custom field updated.', 'jetpack' ),
270 3 => esc_html__( 'Custom field deleted.', 'jetpack' ),
271 /* translators: this is about a food menu */
272 4 => esc_html__( 'Menu item updated.', 'jetpack' ),
273 /* translators: %s: date and time of the revision */
274 5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Menu item restored to revision from %s', 'jetpack' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
275 /* translators: this is about a food menu */
276 6 => sprintf( __( 'Menu item published. <a href="%s">View item</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
277 /* translators: this is about a food menu */
278 7 => esc_html__( 'Menu item saved.', 'jetpack' ),
279 /* translators: this is about a food menu */
280 8 => sprintf( __( 'Menu item submitted. <a target="_blank" href="%s">Preview item</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
281 /* translators: this is about a food menu */
282 9 => sprintf( __( 'Menu item scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview item</a>', 'jetpack' ),
283 // translators: Publish box date format, see https://php.net/date
284 date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
285 /* translators: this is about a food menu */
286 10 => sprintf( __( 'Menu item draft updated. <a target="_blank" href="%s">Preview item</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
287 );
288
289 return $messages;
290 }
291
292
293 /**
294 * Nova Styles and Scripts
295 */
296 function enqueue_nova_styles( $hook ) {
297 global $post_type;
298 $pages = array( 'edit.php', 'post.php', 'post-new.php' );
299
300 if ( in_array( $hook, $pages ) && $post_type == self::MENU_ITEM_POST_TYPE ) {
301 wp_enqueue_style( 'nova-style', plugins_url( 'css/nova.css', __FILE__ ), array(), $this->version );
302 }
303
304 wp_enqueue_style( 'nova-font', plugins_url( 'css/nova-font.css', __FILE__ ), array(), $this->version );
305 }
306
307
308 /**
309 * Change ‘Enter Title Here’ text for the Menu Item.
310 */
311 function change_default_title( $title ) {
312 if ( self::MENU_ITEM_POST_TYPE == get_post_type() ) {
313 /* translators: this is about a food menu */
314 $title = esc_html__( "Enter the menu item's name here", 'jetpack' );
315 }
316
317 return $title;
318 }
319
320
321 /**
322 * Add to Dashboard At A Glance
323 */
324 function add_to_dashboard() {
325 $number_menu_items = wp_count_posts( self::MENU_ITEM_POST_TYPE );
326
327 if ( current_user_can( 'administrator' ) ) {
328 $number_menu_items_published = sprintf( '<a href="%1$s">%2$s</a>',
329 esc_url( get_admin_url( get_current_blog_id(), 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) ),
330 sprintf( _n( '%1$d Food Menu Item', '%1$d Food Menu Items', intval( $number_menu_items->publish ), 'jetpack' ), number_format_i18n( $number_menu_items->publish ) )
331 );
332 }
333 else {
334 $number_menu_items_published = sprintf( '<span>%1$s</span>',
335 sprintf( _n( '%1$d Food Menu Item', '%1$d Food Menu Items', intval( $number_menu_items->publish ), 'jetpack' ), number_format_i18n( $number_menu_items->publish ) )
336 );
337 }
338
339 echo '<li class="nova-menu-count">' . $number_menu_items_published . '</li>';
340 }
341
342
343 /**
344 * Query
345 */
346 function is_menu_item_query( $query ) {
347 if (
348 ( isset( $query->query_vars['taxonomy'] ) && self::MENU_TAX == $query->query_vars['taxonomy'] )
349 ||
350 ( isset( $query->query_vars['post_type'] ) && self::MENU_ITEM_POST_TYPE == $query->query_vars['post_type'] )
351 ) {
352 return true;
353 }
354
355 return false;
356 }
357
358 function sort_menu_item_queries_by_menu_order( $query ) {
359 if ( ! $this->is_menu_item_query( $query ) ) {
360 return;
361 }
362
363 $query->query_vars['orderby'] = 'menu_order';
364 $query->query_vars['order'] = 'ASC';
365
366 // For now, just turn off paging so we can sort by taxonmy later
367 // 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)
368 $query->query_vars['posts_per_page'] = -1;
369 }
370
371 function sort_menu_item_queries_by_menu_taxonomy( $posts, $query ) {
372 if ( !$posts ) {
373 return $posts;
374 }
375
376 if ( !$this->is_menu_item_query( $query ) ) {
377 return $posts;
378 }
379
380 $grouped_by_term = array();
381
382 foreach ( $posts as $post ) {
383 $term = $this->get_menu_item_menu_leaf( $post->ID );
384 if ( !$term || is_wp_error( $term ) ) {
385 $term_id = 0;
386 } else {
387 $term_id = $term->term_id;
388 }
389
390 if ( !isset( $grouped_by_term["$term_id"] ) ) {
391 $grouped_by_term["$term_id"] = array();
392 }
393
394 $grouped_by_term["$term_id"][] = $post;
395 }
396
397 $term_order = get_option( 'nova_menu_order', array() );
398
399 $return = array();
400 foreach ( $term_order as $term_id ) {
401 if ( isset( $grouped_by_term["$term_id"] ) ) {
402 $return = array_merge( $return, $grouped_by_term["$term_id"] );
403 unset( $grouped_by_term["$term_id"] );
404 }
405 }
406
407 foreach ( $grouped_by_term as $term_id => $posts ) {
408 $return = array_merge( $return, $posts );
409 }
410
411 return $return;
412 }
413
414
415 /**
416 * Add Many Items
417 */
418 function add_admin_menus() {
419 $hook = add_submenu_page(
420 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE,
421 __( 'Add Many Items', 'jetpack' ),
422 __( 'Add Many Items', 'jetpack' ),
423 'edit_pages',
424 'add_many_nova_items',
425 array( $this, 'add_many_new_items_page' )
426 );
427
428 add_action( "load-$hook", array( $this, 'add_many_new_items_page_load' ) );
429
430 add_action( 'current_screen', array( $this, 'current_screen_load' ) );
431
432 //Adjust 'Add Many Items' submenu position
433 if ( isset( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] ) ) {
434 $submenu_item = array_pop( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
435 $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE][11] = $submenu_item;
436 ksort( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
437 }
438
439
440 $this->setup_menu_item_columns();
441
442 wp_register_script(
443 'nova-menu-checkboxes',
444 Assets::get_file_url_for_environment(
445 '_inc/build/custom-post-types/js/menu-checkboxes.min.js',
446 'modules/custom-post-types/js/menu-checkboxes.js'
447 ),
448 array( 'jquery' ),
449 $this->version,
450 true
451 );
452 }
453
454
455 /**
456 * Custom Nova Icon CSS
457 */
458 function set_custom_font_icon() {
459 ?>
460 <style type="text/css">
461 #menu-posts-nova_menu_item .wp-menu-image:before {
462 font-family: 'nova-font' !important;
463 content: '\e603' !important;
464 }
465 </style>
466 <?php
467 }
468
469 function current_screen_load() {
470 $screen = get_current_screen();
471 if ( 'edit-nova_menu_item' !== $screen->id ) {
472 return;
473 }
474
475 $this->edit_menu_items_page_load();
476 add_filter( 'admin_notices', array( $this, 'admin_notices' ) );
477 }
478
479 /* Edit Items List */
480
481 function admin_notices() {
482 if ( isset( $_GET['nova_reordered'] ) )
483 /* translators: this is about a food menu */
484 printf( '<div class="updated"><p>%s</p></div>', __( 'Menu Items re-ordered.', 'jetpack' ) );
485 }
486
487 function no_title_sorting( $columns ) {
488 if ( isset( $columns['title'] ) )
489 unset( $columns['title'] );
490 return $columns;
491 }
492
493 function setup_menu_item_columns() {
494 add_filter( sprintf( 'manage_edit-%s_sortable_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'no_title_sorting' ) );
495 add_filter( sprintf( 'manage_%s_posts_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_columns' ) );
496
497 add_action( sprintf( 'manage_%s_posts_custom_column', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_column_callback' ), 10, 2 );
498 }
499
500 function menu_item_columns( $columns ) {
501 unset( $columns['date'], $columns['likes'] );
502
503 $columns['thumbnail'] = __( 'Thumbnail', 'jetpack' );
504 $columns['labels'] = __( 'Labels', 'jetpack' );
505 $columns['price'] = __( 'Price', 'jetpack' );
506 $columns['order'] = __( 'Order', 'jetpack' );
507
508 return $columns;
509 }
510
511 function menu_item_column_callback( $column, $post_id ) {
512 $screen = get_current_screen();
513
514 switch ( $column ) {
515 case 'thumbnail':
516 echo get_the_post_thumbnail( $post_id, array( 50, 50 ) );
517 break;
518 case 'labels' :
519 $this->list_admin_labels( $post_id );
520 break;
521 case 'price' :
522 $this->display_price( $post_id );
523 break;
524 case 'order' :
525 $url = admin_url( $screen->parent_file );
526
527 $up_url = add_query_arg( array(
528 'action' => 'move-item-up',
529 'post_id' => (int) $post_id,
530 ), wp_nonce_url( $url, 'nova_move_item_up_' . $post_id ) );
531
532 $down_url = add_query_arg( array(
533 'action' => 'move-item-down',
534 'post_id' => (int) $post_id,
535 ), wp_nonce_url( $url, 'nova_move_item_down_' . $post_id ) );
536 $menu_item = get_post($post_id);
537 $this->get_menu_by_post_id( $post_id );
538 if ( $term_id = $this->get_menu_by_post_id( $post_id ) ) {
539 $term_id = $term_id->term_id;
540 }
541 ?>
542 <input type="hidden" class="menu-order-value" name="nova_order[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $menu_item->menu_order ) ?>" />
543 <input type="hidden" class='nova-menu-term' name="nova_menu_term[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $term_id ); ?>">
544
545 <span class="hide-if-js">
546 &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>
547 <br />
548 &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>
549 </span>
550 <?php
551 break;
552 }
553 }
554
555 function get_menu_by_post_id( $post_id = null ) {
556 if ( ! $post_id )
557 return false;
558
559 $terms = get_the_terms( $post_id, self::MENU_TAX );
560
561 if ( ! is_array( $terms ) )
562 return false;
563
564 return array_pop( $terms );
565 }
566
567 /**
568 * Fires on a menu edit page. We might have drag-n-drop reordered
569 */
570 function maybe_reorder_menu_items() {
571 // make sure we clicked our button
572 if ( ! ( isset( $_REQUEST['menu_reorder_submit'] ) && $_REQUEST['menu_reorder_submit'] === __( 'Save New Order', 'jetpack' ) ) )
573 return;
574 ;
575
576 // make sure we have the nonce
577 if ( ! ( isset( $_REQUEST['drag-drop-reorder'] ) && wp_verify_nonce( $_REQUEST['drag-drop-reorder'], 'drag-drop-reorder' ) ) )
578 return;
579
580 $term_pairs = array_map( 'absint', $_REQUEST['nova_menu_term'] );
581 $order_pairs = array_map( 'absint', $_REQUEST['nova_order'] );
582
583 foreach( $order_pairs as $ID => $menu_order ) {
584 $ID = absint( $ID );
585 unset( $order_pairs[$ID] );
586 if ( $ID < 0 )
587 continue;
588
589 $post = get_post( $ID );
590 if ( ! $post )
591 continue;
592
593 // save a write if the order hasn't changed
594 if ( $menu_order != $post->menu_order )
595 wp_update_post( compact( 'ID', 'menu_order' ) );
596
597 // save a write if the term hasn't changed
598 if ( $term_pairs[$ID] != $this->get_menu_by_post_id( $ID )->term_id )
599 wp_set_object_terms( $ID, $term_pairs[$ID], self::MENU_TAX );
600
601 }
602
603 $redirect = add_query_arg( array(
604 'post_type' => self::MENU_ITEM_POST_TYPE,
605 'nova_reordered' => '1'
606 ), admin_url( 'edit.php' ) );
607 wp_safe_redirect( $redirect );
608 exit;
609
610 }
611
612 function edit_menu_items_page_load() {
613 if ( isset( $_GET['action'] ) ) {
614 $this->handle_menu_item_actions();
615 }
616
617 $this->maybe_reorder_menu_items();
618
619 wp_enqueue_script(
620 'nova-drag-drop',
621 Assets::get_file_url_for_environment(
622 '_inc/build/custom-post-types/js/nova-drag-drop.min.js',
623 'modules/custom-post-types/js/nova-drag-drop.js'
624 ),
625 array( 'jquery-ui-sortable' ),
626 $this->version,
627 true
628 );
629
630 wp_localize_script( 'nova-drag-drop', '_novaDragDrop', array(
631 'nonce' => wp_create_nonce( 'drag-drop-reorder' ),
632 'nonceName' => 'drag-drop-reorder',
633 'reorder' => __( 'Save New Order', 'jetpack' ),
634 'reorderName' => 'menu_reorder_submit'
635 ) );
636 add_action( 'the_post', array( $this, 'show_menu_titles_in_menu_item_list' ) );
637 }
638
639 function handle_menu_item_actions() {
640 $action = (string) $_GET['action'];
641
642 switch ( $action ) {
643 case 'move-item-up' :
644 case 'move-item-down' :
645 $reorder = false;
646
647 $post_id = (int) $_GET['post_id'];
648
649 $term = $this->get_menu_item_menu_leaf( $post_id );
650
651 // Get all posts in that term
652 $query = new WP_Query( array(
653 'taxonomy' => self::MENU_TAX,
654 'term' => $term->slug,
655 ) );
656
657 $order = array();
658 foreach ( $query->posts as $post ) {
659 $order[] = $post->ID;
660 }
661
662 if ( 'move-item-up' == $action ) {
663 check_admin_referer( 'nova_move_item_up_' . $post_id );
664
665 $first_post_id = $order[0];
666 if ( $post_id == $first_post_id ) {
667 break;
668 }
669
670 foreach ( $order as $menu_order => $order_post_id ) {
671 if ( $post_id != $order_post_id ) {
672 continue;
673 }
674
675 $swap_post_id = $order[$menu_order - 1];
676 $order[$menu_order - 1] = $post_id;
677 $order[$menu_order] = $swap_post_id;
678
679 $reorder = true;
680 break;
681 }
682 } else {
683 check_admin_referer( 'nova_move_item_down_' . $post_id );
684
685 $last_post_id = end( $order );
686 if ( $post_id == $last_post_id ) {
687 break;
688 }
689
690 foreach ( $order as $menu_order => $order_post_id ) {
691 if ( $post_id != $order_post_id ) {
692 continue;
693 }
694
695 $swap_post_id = $order[$menu_order + 1];
696 $order[$menu_order + 1] = $post_id;
697 $order[$menu_order] = $swap_post_id;
698
699 $reorder = true;
700 }
701 }
702
703 if ( $reorder ) {
704 foreach ( $order as $menu_order => $ID ) {
705 wp_update_post( compact( 'ID', 'menu_order' ) );
706 }
707 }
708
709 break;
710 case 'move-menu-up' :
711 case 'move-menu-down' :
712 $reorder = false;
713
714 $term_id = (int) $_GET['term_id'];
715
716 $terms = $this->get_menus();
717
718 $order = array();
719 foreach ( $terms as $term ) {
720 $order[] = $term->term_id;
721 }
722
723 if ( 'move-menu-up' == $action ) {
724 check_admin_referer( 'nova_move_menu_up_' . $term_id );
725
726 $first_term_id = $order[0];
727 if ( $term_id == $first_term_id ) {
728 break;
729 }
730
731 foreach ( $order as $menu_order => $order_term_id ) {
732 if ( $term_id != $order_term_id ) {
733 continue;
734 }
735
736 $swap_term_id = $order[$menu_order - 1];
737 $order[$menu_order - 1] = $term_id;
738 $order[$menu_order] = $swap_term_id;
739
740 $reorder = true;
741 break;
742 }
743 } else {
744 check_admin_referer( 'nova_move_menu_down_' . $term_id );
745
746 $last_term_id = end( $order );
747 if ( $term_id == $last_term_id ) {
748 break;
749 }
750
751 foreach ( $order as $menu_order => $order_term_id ) {
752 if ( $term_id != $order_term_id ) {
753 continue;
754 }
755
756 $swap_term_id = $order[$menu_order + 1];
757 $order[$menu_order + 1] = $term_id;
758 $order[$menu_order] = $swap_term_id;
759
760 $reorder = true;
761 }
762 }
763
764 if ( $reorder ) {
765 update_option( 'nova_menu_order', $order );
766 }
767
768 break;
769 default :
770 return;
771 }
772
773 $redirect = add_query_arg( array(
774 'post_type' => self::MENU_ITEM_POST_TYPE,
775 'nova_reordered' => '1'
776 ), admin_url( 'edit.php' ) );
777 wp_safe_redirect( $redirect );
778 exit;
779 }
780
781 /*
782 * Add menu title rows to the list table
783 */
784 function show_menu_titles_in_menu_item_list( $post ) {
785 global $wp_list_table;
786
787 static $last_term_id = false;
788
789 $term = $this->get_menu_item_menu_leaf( $post->ID );
790
791 $term_id = $term instanceof WP_Term ? $term->term_id : null;
792
793 if ( false !== $last_term_id && $last_term_id === $term_id ) {
794 return;
795 }
796
797 if ( is_null( $term_id ) ) {
798 $last_term_id = null;
799 $term_name = '';
800 $parent_count = 0;
801 } else {
802 $last_term_id = $term->term_id;
803 $term_name = $term->name;
804 $parent_count = 0;
805 $current_term = $term;
806 while ( $current_term->parent ) {
807 $parent_count++;
808 $current_term = get_term( $current_term->parent, self::MENU_TAX );
809 }
810 }
811
812 $non_order_column_count = $wp_list_table->get_column_count() - 1;
813
814 $screen = get_current_screen();
815
816 $url = admin_url( $screen->parent_file );
817
818 $up_url = add_query_arg( array(
819 'action' => 'move-menu-up',
820 'term_id' => (int) $term_id,
821 ), wp_nonce_url( $url, 'nova_move_menu_up_' . $term_id ) );
822
823 $down_url = add_query_arg( array(
824 'action' => 'move-menu-down',
825 'term_id' => (int) $term_id,
826 ), wp_nonce_url( $url, 'nova_move_menu_down_' . $term_id ) );
827
828 ?>
829 <tr class="no-items menu-label-row" data-term_id="<?php echo esc_attr( $term_id ) ?>">
830 <td class="colspanchange" colspan="<?php echo (int) $non_order_column_count; ?>">
831 <h3><?php
832 echo str_repeat( ' &mdash; ', (int) $parent_count );
833
834 if ( $term instanceof WP_Term ) {
835 echo esc_html( sanitize_term_field( 'name', $term_name, $term_id, self::MENU_TAX, 'display' ) );
836 edit_term_link( __( 'edit', 'jetpack' ), '<span class="edit-nova-section"><span class="dashicon dashicon-edit"></span>', '</span>', $term );
837
838 } else {
839 _e( 'Uncategorized' , 'jetpack' );
840 }
841 ?></h3>
842 </td>
843 <td>
844 <?php if ( $term instanceof WP_Term ) { ?>
845 <a class="nova-move-menu-up" title="<?php esc_attr_e( 'Move menu section up', 'jetpack' ); ?>" href="<?php echo esc_url( $up_url ); ?>"><?php esc_html_e( 'UP', 'jetpack' ); ?></a>
846 <br />
847 <a class="nova-move-menu-down" title="<?php esc_attr_e( 'Move menu section down', 'jetpack' ); ?>" href="<?php echo esc_url( $down_url ); ?>"><?php esc_html_e( 'DOWN', 'jetpack' ); ?></a>
848 <?php } ?>
849 </td>
850 </tr>
851 <?php
852 }
853
854 /* Edit Many Items */
855
856 function add_many_new_items_page_load() {
857 if ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
858 $this->process_form_request();
859 exit;
860 }
861
862 $this->enqueue_many_items_scripts();
863 }
864
865 function enqueue_many_items_scripts() {
866 wp_enqueue_script(
867 'nova-many-items',
868 Assets::get_file_url_for_environment(
869 '_inc/build/custom-post-types/js/many-items.min.js',
870 'modules/custom-post-types/js/many-items.js'
871 ),
872 array( 'jquery' ),
873 $this->version,
874 true
875 );
876 }
877
878 function process_form_request() {
879 if ( !isset( $_POST['nova_title'] ) || !is_array( $_POST['nova_title'] ) ) {
880 return;
881 }
882
883 $is_ajax = !empty( $_POST['ajax'] );
884
885 if ( $is_ajax ) {
886 check_ajax_referer( 'nova_many_items' );
887 } else {
888 check_admin_referer( 'nova_many_items' );
889 }
890
891 foreach ( array_keys( $_POST['nova_title'] ) as $key ) :
892 // $_POST is already slashed
893 $post_details = array(
894 'post_status' => 'publish',
895 'post_type' => self::MENU_ITEM_POST_TYPE,
896 'post_content' => $_POST['nova_content'][$key],
897 'post_title' => $_POST['nova_title'][$key],
898 'tax_input' => array(
899 self::MENU_ITEM_LABEL_TAX => $_POST['nova_labels'][$key],
900 self::MENU_TAX => isset( $_POST['nova_menu_tax'] ) ? $_POST['nova_menu_tax'] : null,
901 ),
902 );
903
904 $post_id = wp_insert_post( $post_details );
905 if ( !$post_id || is_wp_error( $post_id ) ) {
906 continue;
907 }
908
909 $this->set_price( $post_id, isset( $_POST['nova_price'][$key] ) ? stripslashes( $_POST['nova_price'][$key] ) : '' );
910
911 if ( $is_ajax ) :
912 $post = get_post( $post_id );
913 $GLOBALS['post'] = $post;
914 setup_postdata( $post );
915
916 ?>
917 <td><?php the_title(); ?></td>
918 <td class="nova-price"><?php $this->display_price(); ?></td>
919 <td><?php $this->list_labels( $post_id ); ?></td>
920 <td><?php the_content(); ?></td>
921 <?php
922 endif;
923
924 endforeach;
925
926 if ( $is_ajax ) {
927 exit;
928 }
929
930 wp_safe_redirect( admin_url( 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) );
931 exit;
932 }
933
934 function add_many_new_items_page() {
935 ?>
936 <div class="wrap">
937 <h2><?php esc_html_e( 'Add Many Items', 'jetpack' ); ?></h2>
938
939 <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.', 'jetpack' ); ?></p>
940
941 <form method="post" action="" enctype="multipart/form-data">
942 <p><h3><?php esc_html_e( 'Add to section:', 'jetpack' ); ?> <?php wp_dropdown_categories( array(
943 'id' => 'nova-menu-tax',
944 'name' => 'nova_menu_tax',
945 'taxonomy' => self::MENU_TAX,
946 'hide_empty' => false,
947 'hierarchical' => true,
948 ) ); ?></h3></p>
949
950 <table class="many-items-table wp-list-table widefat">
951 <thead>
952 <tr>
953 <th scope="col"><?php esc_html_e( 'Name', 'jetpack' ); ?></th>
954 <th scope="col" class="nova-price"><?php esc_html_e( 'Price', 'jetpack' ); ?></th>
955 <th scope="col"><?php _e( 'Labels: <small>spicy, favorite, etc. <em>Separate Labels with commas</em></small>', 'jetpack' ); ?></th>
956 <th scope="col"><?php esc_html_e( 'Description', 'jetpack' ); ?></th>
957 </tr>
958 </thead>
959 <tbody>
960 <tr>
961 <td><input type="text" name="nova_title[]" aria-required="true" /></td>
962 <td class="nova-price"><input type="text" name="nova_price[]" /></td>
963 <td><input type="text" name="nova_labels[]" /></td>
964 <td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
965 </tr>
966 </tbody>
967 <tbody>
968 <tr>
969 <td><input type="text" name="nova_title[]" aria-required="true" /></td>
970 <td class="nova-price"><input type="text" name="nova_price[]" /></td>
971 <td><input type="text" name="nova_labels[]" /></td>
972 <td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
973 </tr>
974 </tbody>
975 <tfoot>
976 <tr>
977 <th><a class="button button-secondary nova-new-row"><span class="dashicon dashicon-plus"></span> <?php esc_html_e( 'New Row' , 'jetpack' ); ?></a></th>
978 <th class="nova-price"></th>
979 <th></th>
980 <th></th>
981 </tr>
982 </tfoot>
983 </table>
984
985 <p class="submit">
986 <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Add These New Menu Items', 'jetpack' ); ?>" />
987 <?php wp_nonce_field( 'nova_many_items' ); ?>
988 </p>
989 </form>
990 </div>
991 <?php
992 }
993
994 /* Edit One Item */
995
996 function register_menu_item_meta_boxes() {
997 wp_enqueue_script( 'nova-menu-checkboxes' );
998
999 add_meta_box( 'menu_item_price', __( 'Price', 'jetpack' ), array( $this, 'menu_item_price_meta_box' ), null, 'side', 'high' );
1000 }
1001
1002 function menu_item_price_meta_box( $post, $meta_box ) {
1003 $price = $this->get_price( $post->ID );
1004 ?>
1005 <label for="nova-price-<?php echo (int) $post->ID; ?>" class="screen-reader-text"><?php esc_html_e( 'Price', 'jetpack' ); ?></label>
1006 <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 ); ?>" />
1007 <?php
1008 }
1009
1010 function add_post_meta( $post_id ) {
1011 if ( !isset( $_POST['nova_price'][$post_id] ) ) {
1012 return;
1013 }
1014
1015 $this->set_price( $post_id, stripslashes( $_POST['nova_price'][$post_id] ) );
1016 }
1017
1018 /* Data */
1019
1020 function get_menus( $args = array() ) {
1021 $args = wp_parse_args( $args, array(
1022 'hide_empty' => false,
1023 ) );
1024
1025 $terms = get_terms( self::MENU_TAX, $args );
1026 if ( !$terms || is_wp_error( $terms ) ) {
1027 return array();
1028 }
1029
1030 $terms_by_id = array();
1031 foreach ( $terms as $term ) {
1032 $terms_by_id["{$term->term_id}"] = $term;
1033 }
1034
1035 $term_order = get_option( 'nova_menu_order', array() );
1036
1037 $return = array();
1038 foreach ( $term_order as $term_id ) {
1039 if ( isset( $terms_by_id["$term_id"] ) ) {
1040 $return[] = $terms_by_id["$term_id"];
1041 unset( $terms_by_id["$term_id"] );
1042 }
1043 }
1044
1045 foreach ( $terms_by_id as $term_id => $term ) {
1046 $return[] = $term;
1047 }
1048
1049 return $return;
1050 }
1051
1052 function get_menu_item_menu_leaf( $post_id ) {
1053 // Get first menu taxonomy "leaf"
1054 $term_ids = wp_get_object_terms( $post_id, self::MENU_TAX, array( 'fields' => 'ids' ) );
1055
1056 foreach ( $term_ids as $term_id ) {
1057 $children = get_term_children( $term_id, self::MENU_TAX );
1058 if ( ! $children ) {
1059 break;
1060 }
1061 }
1062
1063 if ( ! isset( $term_id ) ) {
1064 return false;
1065 }
1066
1067 return get_term( $term_id, self::MENU_TAX );
1068
1069 }
1070
1071 function list_labels( $post_id = 0 ) {
1072 $post = get_post( $post_id );
1073 echo get_the_term_list( $post->ID, self::MENU_ITEM_LABEL_TAX, '', _x( ', ', 'Nova label separator', 'jetpack' ), '' );
1074 }
1075
1076 function list_admin_labels( $post_id = 0 ) {
1077 $post = get_post( $post_id );
1078 $labels = get_the_terms( $post->ID, self::MENU_ITEM_LABEL_TAX );
1079 if ( !empty( $labels ) ) {
1080 $out = array();
1081 foreach ( $labels as $label ) {
1082 $out[] = sprintf( '<a href="%s">%s</a>',
1083 esc_url( add_query_arg( array(
1084 'post_type' => self::MENU_ITEM_POST_TYPE,
1085 'taxonomy' => self::MENU_ITEM_LABEL_TAX,
1086 'term' => $label->slug
1087 ), 'edit.php' ) ),
1088 esc_html( sanitize_term_field( 'name', $label->name, $label->term_id, self::MENU_ITEM_LABEL_TAX, 'display' ) )
1089 );
1090 }
1091
1092 echo join( _x( ', ', 'Nova label separator', 'jetpack' ), $out );
1093 } else {
1094 esc_html_e( 'No Labels', 'jetpack' );
1095 }
1096 }
1097
1098 function set_price( $post_id = 0, $price = '' ) {
1099 $post = get_post( $post_id );
1100
1101 return update_post_meta( $post->ID, 'nova_price', $price );
1102 }
1103
1104 function get_price( $post_id = 0 ) {
1105 $post = get_post( $post_id );
1106
1107 return get_post_meta( $post->ID, 'nova_price', true );
1108 }
1109
1110 function display_price( $post_id = 0 ) {
1111 echo esc_html( $this->get_price( $post_id ) );
1112 }
1113
1114 /* Menu Item Loop Markup */
1115
1116 /* Does not support nested loops */
1117
1118 function get_menu_item_loop_markup( $field = null ) {
1119 return $this->menu_item_loop_markup;
1120 }
1121
1122 /**
1123 * Sets up the loop markup.
1124 * Attached to the 'template_include' *filter*,
1125 * which fires only during a real blog view (not in admin, feeds, etc.)
1126 *
1127 * @param string Template File
1128 * @return string Template File. VERY Important.
1129 */
1130 function setup_menu_item_loop_markup__in_filter( $template ) {
1131 add_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
1132
1133 return $template;
1134 }
1135
1136 /**
1137 * If the Query is a Menu Item Query, start outputing the Menu Item Loop Marku
1138 * Attached to the 'loop_start' action.
1139 *
1140 * @param WP_Query
1141 */
1142 function start_menu_item_loop( $query ) {
1143 if ( !$this->is_menu_item_query( $query ) ) {
1144 return;
1145 }
1146
1147 $this->menu_item_loop_last_term_id = false;
1148 $this->menu_item_loop_current_term = false;
1149
1150 add_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
1151 add_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
1152 }
1153
1154 /**
1155 * Outputs the Menu Item Loop Marku
1156 * Attached to the 'the_post' action.
1157 *
1158 * @param WP_Post
1159 */
1160 function menu_item_loop_each_post( $post ) {
1161 $this->menu_item_loop_current_term = $this->get_menu_item_menu_leaf( $post->ID );
1162
1163 if ( false === $this->menu_item_loop_last_term_id ) {
1164 // We're at the very beginning of the loop
1165
1166 $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
1167 $this->menu_item_loop_header(); // Output the menu's header
1168 } elseif ( $this->menu_item_loop_last_term_id != $this->menu_item_loop_current_term->term_id ) {
1169 // We're not at the very beginning but still need to start a new menu section. End the previous menu section first.
1170
1171 $this->menu_item_loop_close_element( 'menu' ); // End the previous menu section
1172 $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
1173 $this->menu_item_loop_header(); // Output the menu's header
1174 }
1175
1176 $this->menu_item_loop_last_term_id = $this->menu_item_loop_current_term->term_id;
1177 }
1178
1179 /**
1180 * If the Query is a Menu Item Query, stop outputing the Menu Item Loop Marku
1181 * Attached to the 'loop_end' action.
1182 *
1183 * @param WP_Query
1184 */
1185 function stop_menu_item_loop( $query ) {
1186 if ( !$this->is_menu_item_query( $query ) ) {
1187 return;
1188 }
1189
1190 remove_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
1191 remove_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
1192 remove_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
1193
1194 $this->menu_item_loop_close_element( 'menu' ); // End the last menu section
1195 }
1196
1197 /**
1198 * Outputs the Menu Group Header
1199 */
1200 function menu_item_loop_header() {
1201 $this->menu_item_loop_open_element( 'menu_header' );
1202 $this->menu_item_loop_open_element( 'menu_title' );
1203 echo esc_html( $this->menu_item_loop_current_term->name ); // @todo tax filter
1204 $this->menu_item_loop_close_element( 'menu_title' );
1205 if ( $this->menu_item_loop_current_term->description ) :
1206 $this->menu_item_loop_open_element( 'menu_description' );
1207 echo esc_html( $this->menu_item_loop_current_term->description ); // @todo kses, tax filter
1208 $this->menu_item_loop_close_element( 'menu_description' );
1209 endif;
1210 $this->menu_item_loop_close_element( 'menu_header' );
1211 }
1212
1213 /**
1214 * Outputs a Menu Item Markup element opening tag
1215 *
1216 * @param string $field - Menu Item Markup settings field.
1217 */
1218 function menu_item_loop_open_element( $field ) {
1219 $markup = $this->get_menu_item_loop_markup();
1220 /**
1221 * Filter a menu item's element opening tag.
1222 *
1223 * @module custom-content-types
1224 *
1225 * @since 4.4.0
1226 *
1227 * @param string $tag Menu item's element opening tag.
1228 * @param string $field Menu Item Markup settings field.
1229 * @param array $markup Array of markup elements for the menu item.
1230 * @param false|object $term Taxonomy term for current menu item.
1231 */
1232 echo apply_filters(
1233 'jetpack_nova_menu_item_loop_open_element',
1234 '<' . tag_escape( $markup["{$field}_tag"] ) . $this->menu_item_loop_class( $markup["{$field}_class"] ) . ">\n",
1235 $field,
1236 $markup,
1237 $this->menu_item_loop_current_term
1238 );
1239 }
1240
1241 /**
1242 * Outputs a Menu Item Markup element closing tag
1243 *
1244 * @param string $field - Menu Item Markup settings field
1245 */
1246 function menu_item_loop_close_element( $field ) {
1247 $markup = $this->get_menu_item_loop_markup();
1248 /**
1249 * Filter a menu item's element closing tag.
1250 *
1251 * @module custom-content-types
1252 *
1253 * @since 4.4.0
1254 *
1255 * @param string $tag Menu item's element closing tag.
1256 * @param string $field Menu Item Markup settings field.
1257 * @param array $markup Array of markup elements for the menu item.
1258 * @param false|object $term Taxonomy term for current menu item.
1259 */
1260 echo apply_filters(
1261 'jetpack_nova_menu_item_loop_close_element',
1262 '</' . tag_escape( $markup["{$field}_tag"] ) . ">\n",
1263 $field,
1264 $markup,
1265 $this->menu_item_loop_current_term
1266 );
1267 }
1268
1269 /**
1270 * Returns a Menu Item Markup element's class attribute.
1271 *
1272 * @param string $class Class name.
1273 * @return string HTML class attribute with leading whitespace.
1274 */
1275 function menu_item_loop_class( $class ) {
1276 if ( ! $class ) {
1277 return '';
1278 }
1279
1280 /**
1281 * Filter a menu Item Markup element's class attribute.
1282 *
1283 * @module custom-content-types
1284 *
1285 * @since 4.4.0
1286 *
1287 * @param string $tag Menu Item Markup element's class attribute.
1288 * @param string $class Menu Item Class name.
1289 * @param false|object $term Taxonomy term for current menu item.
1290 */
1291 return apply_filters(
1292 'jetpack_nova_menu_item_loop_class',
1293 ' class="' . esc_attr( $class ) . '"',
1294 $class,
1295 $this->menu_item_loop_current_term
1296 );
1297 }
1298 }
1299
1300 add_action( 'init', array( 'Nova_Restaurant', 'init' ) );
1301