Completed
Push — renovate/react-monorepo ( 545e89...65a81e )
by
unknown
268:48 queued 253:47
created

Nova_Restaurant::get_price()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
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 ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $menu_item_loop_markup of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
60
			$instance->menu_item_loop_markup = wp_parse_args( $menu_item_loop_markup, $instance->default_menu_item_loop_markup );
0 ignored issues
show
Documentation introduced by
$instance->default_menu_item_loop_markup is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation Bug introduced by
It seems like wp_parse_args($menu_item..._menu_item_loop_markup) can be null. However, the property $menu_item_loop_markup is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
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 );
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with self::MENU_ITEM_POST_TYPE.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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 View Code Duplication
	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(
329
				'<a href="%1$s">%2$s</a>',
330
				esc_url(
331
					get_admin_url(
332
						get_current_blog_id(),
333
						'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE
334
					)
335
				),
336
				sprintf(
337
					/* translators: Placehoder is a number of items. */
338
					_n(
339
						'%1$d Food Menu Item',
340
						'%1$d Food Menu Items',
341
						(int) $number_menu_items->publish,
342
						'jetpack'
343
					),
344
					number_format_i18n( $number_menu_items->publish )
345
				)
346
			);
347
		} else {
348
			$number_menu_items_published = sprintf(
349
				'<span>%1$s</span>',
350
				sprintf(
351
					/* translators: Placehoder is a number of items. */
352
					_n(
353
						'%1$d Food Menu Item',
354
						'%1$d Food Menu Items',
355
						(int) $number_menu_items->publish,
356
						'jetpack'
357
					),
358
					number_format_i18n( $number_menu_items->publish )
359
				)
360
			);
361
		}
362
363
		echo '<li class="nova-menu-count">' . $number_menu_items_published . '</li>';
364
	}
365
366
367
	/**
368
	 * Query
369
	 */
370
	function is_menu_item_query( $query ) {
371
		if (
372
			( isset( $query->query_vars['taxonomy'] ) && self::MENU_TAX == $query->query_vars['taxonomy'] )
373
		||
374
			( isset( $query->query_vars['post_type'] ) && self::MENU_ITEM_POST_TYPE == $query->query_vars['post_type'] )
375
		) {
376
			return true;
377
		}
378
379
		return false;
380
	}
381
382
	function sort_menu_item_queries_by_menu_order( $query ) {
383
		if ( ! $this->is_menu_item_query( $query ) ) {
384
			return;
385
		}
386
387
		$query->query_vars['orderby'] = 'menu_order';
388
		$query->query_vars['order'] = 'ASC';
389
390
		// For now, just turn off paging so we can sort by taxonmy later
391
		// 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)
392
		$query->query_vars['posts_per_page'] = -1;
393
	}
394
395
	function sort_menu_item_queries_by_menu_taxonomy( $posts, $query ) {
396
		if ( !$posts ) {
397
			return $posts;
398
		}
399
400
		if ( !$this->is_menu_item_query( $query ) ) {
401
			return $posts;
402
		}
403
404
		$grouped_by_term = array();
405
406
		foreach ( $posts as $post ) {
407
			$term = $this->get_menu_item_menu_leaf( $post->ID );
408
			if ( !$term || is_wp_error( $term ) ) {
409
				$term_id = 0;
410
			} else {
411
				$term_id = $term->term_id;
412
			}
413
414
			if ( !isset( $grouped_by_term["$term_id"] ) ) {
415
				$grouped_by_term["$term_id"] = array();
416
			}
417
418
			$grouped_by_term["$term_id"][] = $post;
419
		}
420
421
		$term_order = get_option( 'nova_menu_order', array() );
422
423
		$return = array();
424 View Code Duplication
		foreach ( $term_order as $term_id ) {
425
			if ( isset( $grouped_by_term["$term_id"] ) ) {
426
				$return = array_merge( $return, $grouped_by_term["$term_id"] );
427
				unset( $grouped_by_term["$term_id"] );
428
			}
429
		}
430
431
		foreach ( $grouped_by_term as $term_id => $posts ) {
432
			$return = array_merge( $return, $posts );
433
		}
434
435
		return $return;
436
	}
437
438
439
	/**
440
	 * Add Many Items
441
	 */
442
	function add_admin_menus() {
443
		$hook = add_submenu_page(
444
			'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE,
445
			__( 'Add Many Items', 'jetpack' ),
446
			__( 'Add Many Items', 'jetpack' ),
447
			'edit_pages',
448
			'add_many_nova_items',
449
			array( $this, 'add_many_new_items_page' )
450
		);
451
452
		add_action( "load-$hook",     array( $this, 'add_many_new_items_page_load' ) );
453
454
		add_action( 'current_screen', array( $this, 'current_screen_load' ) );
455
456
		//Adjust 'Add Many Items' submenu position
457
		if ( isset( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] ) ) {
458
			$submenu_item = array_pop( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
459
			$GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE][11] = $submenu_item;
460
			ksort( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
461
		}
462
463
464
		$this->setup_menu_item_columns();
465
466
		wp_register_script(
467
			'nova-menu-checkboxes',
468
			Assets::get_file_url_for_environment(
469
				'_inc/build/custom-post-types/js/menu-checkboxes.min.js',
470
				'modules/custom-post-types/js/menu-checkboxes.js'
471
			),
472
			array( 'jquery' ),
473
			$this->version,
474
			true
475
		);
476
	}
477
478
479
	/**
480
	 * Custom Nova Icon CSS
481
	 */
482
	function set_custom_font_icon() {
483
	?>
484
	<style type="text/css">
485
	#menu-posts-nova_menu_item .wp-menu-image:before {
486
		font-family: 'nova-font' !important;
487
		content: '\e603' !important;
488
	}
489
	</style>
490
	<?php
491
	}
492
493
	function current_screen_load() {
494
		$screen = get_current_screen();
495
		if ( 'edit-nova_menu_item' !== $screen->id ) {
496
			return;
497
		}
498
499
		$this->edit_menu_items_page_load();
500
		add_filter( 'admin_notices', array( $this, 'admin_notices' ) );
501
	}
502
503
/* Edit Items List */
504
505
	function admin_notices() {
506
		if ( isset( $_GET['nova_reordered'] ) )
507
			/* translators: this is about a food menu */
508
			printf( '<div class="updated"><p>%s</p></div>', __( 'Menu Items re-ordered.', 'jetpack' ) );
509
	}
510
511
	function no_title_sorting( $columns ) {
512
		if ( isset( $columns['title'] ) )
513
			unset( $columns['title'] );
514
		return $columns;
515
	}
516
517
	function setup_menu_item_columns() {
518
		add_filter( sprintf( 'manage_edit-%s_sortable_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'no_title_sorting' ) );
519
		add_filter( sprintf( 'manage_%s_posts_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_columns' ) );
520
521
		add_action( sprintf( 'manage_%s_posts_custom_column', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_column_callback' ), 10, 2 );
522
	}
523
524
	function menu_item_columns( $columns ) {
525
		unset( $columns['date'], $columns['likes'] );
526
527
		$columns['thumbnail'] = __( 'Thumbnail', 'jetpack' );
528
		$columns['labels']    = __( 'Labels',    'jetpack' );
529
		$columns['price']     = __( 'Price',     'jetpack' );
530
		$columns['order']     = __( 'Order',     'jetpack' );
531
532
		return $columns;
533
	}
534
535
	function menu_item_column_callback( $column, $post_id ) {
536
		$screen = get_current_screen();
537
538
		switch ( $column ) {
539
			case 'thumbnail':
540
				echo get_the_post_thumbnail( $post_id, array( 50, 50 ) );
541
				break;
542
			case 'labels' :
543
				$this->list_admin_labels( $post_id );
544
				break;
545
			case 'price' :
546
				$this->display_price( $post_id );
547
				break;
548
			case 'order' :
549
				$url = admin_url( $screen->parent_file );
550
551
				$up_url = add_query_arg( array(
552
					'action' => 'move-item-up',
553
					'post_id' => (int) $post_id,
554
				), wp_nonce_url( $url, 'nova_move_item_up_' . $post_id ) );
555
556
				$down_url = add_query_arg( array(
557
					'action' => 'move-item-down',
558
					'post_id' => (int) $post_id,
559
				), wp_nonce_url( $url, 'nova_move_item_down_' . $post_id ) );
560
				$menu_item = get_post($post_id);
561
				$this->get_menu_by_post_id( $post_id );
562
				if ( $term_id = $this->get_menu_by_post_id( $post_id ) ) {
563
					$term_id = $term_id->term_id;
564
				}
565
	?>
566
				<input type="hidden" class="menu-order-value" name="nova_order[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $menu_item->menu_order ) ?>" />
567
				<input type="hidden" class='nova-menu-term' name="nova_menu_term[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $term_id ); ?>">
568
569
				<span class="hide-if-js">
570
				&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>
571
				<br />
572
				&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>
573
				</span>
574
	<?php
575
				break;
576
		}
577
	}
578
579
	function get_menu_by_post_id( $post_id = null ) {
580
		if ( ! $post_id )
581
			return false;
582
583
		$terms = get_the_terms( $post_id, self::MENU_TAX );
584
585
		if ( ! is_array( $terms ) )
586
			return false;
587
588
		return array_pop( $terms );
589
	}
590
591
	/**
592
	 * Fires on a menu edit page. We might have drag-n-drop reordered
593
	 */
594
	function maybe_reorder_menu_items() {
595
		// make sure we clicked our button
596
		if ( ! ( isset( $_REQUEST['menu_reorder_submit'] ) && $_REQUEST['menu_reorder_submit'] === __( 'Save New Order', 'jetpack' ) ) )
597
			return;
598
		;
599
600
		// make sure we have the nonce
601
		if ( ! ( isset( $_REQUEST['drag-drop-reorder'] ) && wp_verify_nonce( $_REQUEST['drag-drop-reorder'], 'drag-drop-reorder' ) ) )
602
			return;
603
604
		$term_pairs = array_map( 'absint', $_REQUEST['nova_menu_term'] );
605
		$order_pairs = array_map( 'absint', $_REQUEST['nova_order'] );
606
607
		foreach( $order_pairs as $ID => $menu_order ) {
608
			$ID = absint( $ID );
609
			unset( $order_pairs[$ID] );
610
			if ( $ID < 0 )
611
				continue;
612
613
			$post = get_post( $ID );
614
			if ( ! $post )
615
				continue;
616
617
			// save a write if the order hasn't changed
618
			if ( $menu_order != $post->menu_order )
619
				wp_update_post( compact( 'ID', 'menu_order' ) );
620
621
			// save a write if the term hasn't changed
622
			if ( $term_pairs[$ID] != $this->get_menu_by_post_id( $ID )->term_id )
623
				wp_set_object_terms( $ID, $term_pairs[$ID], self::MENU_TAX );
624
625
		}
626
627
		$redirect = add_query_arg( array(
628
			'post_type' => self::MENU_ITEM_POST_TYPE,
629
			'nova_reordered' => '1'
630
		), admin_url( 'edit.php' ) );
631
		wp_safe_redirect( $redirect );
632
		exit;
633
634
	}
635
636
	function edit_menu_items_page_load() {
637
		if ( isset( $_GET['action'] ) ) {
638
			$this->handle_menu_item_actions();
639
		}
640
641
		$this->maybe_reorder_menu_items();
642
643
		wp_enqueue_script(
644
			'nova-drag-drop',
645
			Assets::get_file_url_for_environment(
646
				'_inc/build/custom-post-types/js/nova-drag-drop.min.js',
647
				'modules/custom-post-types/js/nova-drag-drop.js'
648
			),
649
			array( 'jquery-ui-sortable' ),
650
			$this->version,
651
			true
652
		);
653
654
		wp_localize_script( 'nova-drag-drop', '_novaDragDrop', array(
655
			'nonce'       => wp_create_nonce( 'drag-drop-reorder' ),
656
			'nonceName'   => 'drag-drop-reorder',
657
			'reorder'     => __( 'Save New Order', 'jetpack' ),
658
			'reorderName' => 'menu_reorder_submit'
659
		) );
660
		add_action( 'the_post', array( $this, 'show_menu_titles_in_menu_item_list' ) );
661
	}
662
663
	function handle_menu_item_actions() {
664
		$action = (string) $_GET['action'];
665
666
		switch ( $action ) {
667
		case 'move-item-up' :
668
		case 'move-item-down' :
669
			$reorder = false;
670
671
			$post_id = (int) $_GET['post_id'];
672
673
			$term = $this->get_menu_item_menu_leaf( $post_id );
674
675
			// Get all posts in that term
676
			$query = new WP_Query( array(
677
				'taxonomy' => self::MENU_TAX,
678
				'term'     => $term->slug,
679
			) );
680
681
			$order = array();
682
			foreach ( $query->posts as $post ) {
683
				$order[] = $post->ID;
684
			}
685
686
			if ( 'move-item-up' == $action ) {
687
				check_admin_referer( 'nova_move_item_up_' . $post_id );
688
689
				$first_post_id = $order[0];
690
				if ( $post_id == $first_post_id ) {
691
					break;
692
				}
693
694
				foreach ( $order as $menu_order => $order_post_id ) {
695
					if ( $post_id != $order_post_id ) {
696
						continue;
697
					}
698
699
					$swap_post_id = $order[$menu_order - 1];
700
					$order[$menu_order - 1] = $post_id;
701
					$order[$menu_order] = $swap_post_id;
702
703
					$reorder = true;
704
					break;
705
				}
706 View Code Duplication
			} else {
707
				check_admin_referer( 'nova_move_item_down_' . $post_id );
708
709
				$last_post_id = end( $order );
710
				if ( $post_id == $last_post_id ) {
711
					break;
712
				}
713
714
				foreach ( $order as $menu_order => $order_post_id ) {
715
					if ( $post_id != $order_post_id ) {
716
						continue;
717
					}
718
719
					$swap_post_id = $order[$menu_order + 1];
720
					$order[$menu_order + 1] = $post_id;
721
					$order[$menu_order] = $swap_post_id;
722
723
					$reorder = true;
724
				}
725
			}
726
727
			if ( $reorder ) {
728
				foreach ( $order as $menu_order => $ID ) {
729
					wp_update_post( compact( 'ID', 'menu_order' ) );
730
				}
731
			}
732
733
			break;
734
		case 'move-menu-up' :
735
		case 'move-menu-down' :
736
			$reorder = false;
737
738
			$term_id = (int) $_GET['term_id'];
739
740
			$terms = $this->get_menus();
741
742
			$order = array();
743
			foreach ( $terms as $term ) {
744
				$order[] = $term->term_id;
745
			}
746
747
			if ( 'move-menu-up' == $action ) {
748
				check_admin_referer( 'nova_move_menu_up_' . $term_id );
749
750
				$first_term_id = $order[0];
751
				if ( $term_id == $first_term_id ) {
752
					break;
753
				}
754
755
				foreach ( $order as $menu_order => $order_term_id ) {
756
					if ( $term_id != $order_term_id ) {
757
						continue;
758
					}
759
760
					$swap_term_id = $order[$menu_order - 1];
761
					$order[$menu_order - 1] = $term_id;
762
					$order[$menu_order] = $swap_term_id;
763
764
					$reorder = true;
765
					break;
766
				}
767 View Code Duplication
			} else {
768
				check_admin_referer( 'nova_move_menu_down_' . $term_id );
769
770
				$last_term_id = end( $order );
771
				if ( $term_id == $last_term_id ) {
772
					break;
773
				}
774
775
				foreach ( $order as $menu_order => $order_term_id ) {
776
					if ( $term_id != $order_term_id ) {
777
						continue;
778
					}
779
780
					$swap_term_id = $order[$menu_order + 1];
781
					$order[$menu_order + 1] = $term_id;
782
					$order[$menu_order] = $swap_term_id;
783
784
					$reorder = true;
785
				}
786
			}
787
788
			if ( $reorder ) {
789
				update_option( 'nova_menu_order', $order );
790
			}
791
792
			break;
793
		default :
794
			return;
795
		}
796
797
		$redirect = add_query_arg( array(
798
			'post_type' => self::MENU_ITEM_POST_TYPE,
799
			'nova_reordered' => '1'
800
		), admin_url( 'edit.php' ) );
801
		wp_safe_redirect( $redirect );
802
		exit;
803
	}
804
805
	/*
806
	 * Add menu title rows to the list table
807
	 */
808
	function show_menu_titles_in_menu_item_list( $post ) {
809
		global $wp_list_table;
810
811
		static $last_term_id = false;
812
813
		$term = $this->get_menu_item_menu_leaf( $post->ID );
814
815
		$term_id = $term instanceof WP_Term ? $term->term_id : null;
0 ignored issues
show
Bug introduced by
The class WP_Term does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
816
817
		if ( false !== $last_term_id && $last_term_id === $term_id ) {
818
			return;
819
		}
820
821
		if ( is_null( $term_id ) ) {
822
			$last_term_id = null;
823
			$term_name = '';
824
			$parent_count = 0;
825
		} else {
826
			$last_term_id = $term->term_id;
827
			$term_name = $term->name;
828
			$parent_count = 0;
829
			$current_term = $term;
830
			while ( $current_term->parent ) {
831
				$parent_count++;
832
				$current_term = get_term( $current_term->parent, self::MENU_TAX );
833
			}
834
		}
835
836
		$non_order_column_count = $wp_list_table->get_column_count() - 1;
837
838
		$screen = get_current_screen();
839
840
		$url = admin_url( $screen->parent_file );
841
842
		$up_url = add_query_arg( array(
843
			'action'  => 'move-menu-up',
844
			'term_id' => (int) $term_id,
845
		), wp_nonce_url( $url, 'nova_move_menu_up_' . $term_id ) );
846
847
		$down_url = add_query_arg( array(
848
			'action'  => 'move-menu-down',
849
			'term_id' => (int) $term_id,
850
		), wp_nonce_url( $url, 'nova_move_menu_down_' . $term_id ) );
851
852
?>
853
		<tr class="no-items menu-label-row" data-term_id="<?php echo esc_attr( $term_id ) ?>">
854
			<td class="colspanchange" colspan="<?php echo (int) $non_order_column_count; ?>">
855
				<h3><?php
856
					echo str_repeat( ' &mdash; ', (int) $parent_count );
857
858
					if ( $term instanceof WP_Term ) {
0 ignored issues
show
Bug introduced by
The class WP_Term does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
859
						echo esc_html( sanitize_term_field( 'name', $term_name, $term_id, self::MENU_TAX, 'display' ) );
860
						edit_term_link( __( 'edit', 'jetpack' ), '<span class="edit-nova-section"><span class="dashicon dashicon-edit"></span>', '</span>', $term );
861
862
					} else {
863
						_e( 'Uncategorized' , 'jetpack' );
864
					}
865
				?></h3>
866
			</td>
867
			<td>
868
				<?php if ( $term instanceof WP_Term ) { ?>
0 ignored issues
show
Bug introduced by
The class WP_Term does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
869
				<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>
870
				<br />
871
				<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>
872
				<?php } ?>
873
			</td>
874
		</tr>
875
<?php
876
	}
877
878
/* Edit Many Items */
879
880
	function add_many_new_items_page_load() {
881
		if ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
882
			$this->process_form_request();
883
			exit;
884
		}
885
886
		$this->enqueue_many_items_scripts();
887
	}
888
889
	function enqueue_many_items_scripts() {
890
		wp_enqueue_script(
891
			'nova-many-items',
892
			Assets::get_file_url_for_environment(
893
				'_inc/build/custom-post-types/js/many-items.min.js',
894
				'modules/custom-post-types/js/many-items.js'
895
			),
896
			array( 'jquery' ),
897
			$this->version,
898
			true
899
		);
900
	}
901
902
	function process_form_request() {
903
		if ( !isset( $_POST['nova_title'] ) || !is_array( $_POST['nova_title'] ) ) {
904
			return;
905
		}
906
907
		$is_ajax = !empty( $_POST['ajax'] );
908
909
		if ( $is_ajax ) {
910
			check_ajax_referer( 'nova_many_items' );
911
		} else {
912
			check_admin_referer( 'nova_many_items' );
913
		}
914
915
		foreach ( array_keys( $_POST['nova_title'] ) as $key ) :
916
			// $_POST is already slashed
917
			$post_details = array(
918
				'post_status'  => 'publish',
919
				'post_type'    => self::MENU_ITEM_POST_TYPE,
920
				'post_content' => $_POST['nova_content'][$key],
921
				'post_title'   => $_POST['nova_title'][$key],
922
				'tax_input'    => array(
923
					self::MENU_ITEM_LABEL_TAX => $_POST['nova_labels'][$key],
924
					self::MENU_TAX            => isset( $_POST['nova_menu_tax'] ) ? $_POST['nova_menu_tax'] : null,
925
				),
926
			);
927
928
			$post_id = wp_insert_post( $post_details );
929
			if ( !$post_id || is_wp_error( $post_id ) ) {
930
				continue;
931
			}
932
933
			$this->set_price( $post_id, isset( $_POST['nova_price'][$key] ) ? stripslashes( $_POST['nova_price'][$key] ) : '' );
934
935
			if ( $is_ajax ) :
936
				$post = get_post( $post_id );
937
				$GLOBALS['post'] = $post;
938
				setup_postdata( $post );
939
940
?>
941
			<td><?php the_title(); ?></td>
942
			<td class="nova-price"><?php $this->display_price(); ?></td>
943
			<td><?php $this->list_labels( $post_id ); ?></td>
944
			<td><?php the_content(); ?></td>
945
<?php
946
			endif;
947
948
		endforeach;
949
950
		if ( $is_ajax ) {
951
			exit;
952
		}
953
954
		wp_safe_redirect( admin_url( 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) );
955
		exit;
956
	}
957
958
	function add_many_new_items_page() {
959
?>
960
	<div class="wrap">
961
		<h2><?php esc_html_e( 'Add Many Items', 'jetpack' ); ?></h2>
962
963
		<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>
964
965
		<form method="post" action="" enctype="multipart/form-data">
966
			<p><h3><?php esc_html_e( 'Add to section:', 'jetpack' ); ?> <?php wp_dropdown_categories( array(
967
				'id'           => 'nova-menu-tax',
968
				'name'         => 'nova_menu_tax',
969
				'taxonomy'     => self::MENU_TAX,
970
				'hide_empty'   => false,
971
				'hierarchical' => true,
972
			) ); ?></h3></p>
973
974
			<table class="many-items-table wp-list-table widefat">
975
				<thead>
976
					<tr>
977
						<th scope="col"><?php esc_html_e( 'Name', 'jetpack' ); ?></th>
978
						<th scope="col" class="nova-price"><?php esc_html_e( 'Price', 'jetpack' ); ?></th>
979
						<th scope="col"><?php _e( 'Labels: <small>spicy, favorite, etc. <em>Separate Labels with commas</em></small>', 'jetpack' ); ?></th>
980
						<th scope="col"><?php esc_html_e( 'Description', 'jetpack' ); ?></th>
981
					</tr>
982
				</thead>
983
				<tbody>
984
					<tr>
985
						<td><input type="text" name="nova_title[]" aria-required="true" /></td>
986
						<td class="nova-price"><input type="text" name="nova_price[]" /></td>
987
						<td><input type="text" name="nova_labels[]" /></td>
988
						<td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
989
					</tr>
990
				</tbody>
991
				<tbody>
992
					<tr>
993
						<td><input type="text" name="nova_title[]" aria-required="true" /></td>
994
						<td class="nova-price"><input type="text" name="nova_price[]" /></td>
995
						<td><input type="text" name="nova_labels[]" /></td>
996
						<td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
997
					</tr>
998
				</tbody>
999
				<tfoot>
1000
					<tr>
1001
						<th><a class="button button-secondary nova-new-row"><span class="dashicon dashicon-plus"></span> <?php esc_html_e( 'New Row' , 'jetpack' ); ?></a></th>
1002
						<th class="nova-price"></th>
1003
						<th></th>
1004
						<th></th>
1005
					</tr>
1006
				</tfoot>
1007
			</table>
1008
1009
			<p class="submit">
1010
				<input type="submit" class="button-primary" value="<?php esc_attr_e( 'Add These New Menu Items', 'jetpack' ); ?>" />
1011
				<?php wp_nonce_field( 'nova_many_items' ); ?>
1012
			</p>
1013
		</form>
1014
	</div>
1015
<?php
1016
	}
1017
1018
/* Edit One Item */
1019
1020
	function register_menu_item_meta_boxes() {
1021
		wp_enqueue_script( 'nova-menu-checkboxes' );
1022
1023
		add_meta_box( 'menu_item_price', __( 'Price', 'jetpack' ), array( $this, 'menu_item_price_meta_box' ), null, 'side', 'high' );
1024
	}
1025
1026
	function menu_item_price_meta_box( $post, $meta_box ) {
1027
		$price = $this->get_price( $post->ID );
1028
?>
1029
	<label for="nova-price-<?php echo (int) $post->ID; ?>" class="screen-reader-text"><?php esc_html_e( 'Price', 'jetpack' ); ?></label>
1030
	<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 ); ?>" />
1031
<?php
1032
	}
1033
1034
	function add_post_meta( $post_id ) {
1035
		if ( !isset( $_POST['nova_price'][$post_id] ) ) {
1036
			return;
1037
		}
1038
1039
		$this->set_price( $post_id, stripslashes( $_POST['nova_price'][$post_id] ) );
1040
	}
1041
1042
/* Data */
1043
1044
	function get_menus( $args = array() ) {
1045
		$args = wp_parse_args( $args, array(
0 ignored issues
show
Documentation introduced by
array('hide_empty' => false) is of type array<string,false,{"hide_empty":"false"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1046
			'hide_empty' => false,
1047
		) );
1048
1049
		$terms = get_terms( self::MENU_TAX, $args );
1050
		if ( !$terms || is_wp_error( $terms ) ) {
1051
			return array();
1052
		}
1053
1054
		$terms_by_id = array();
1055
		foreach ( $terms as $term ) {
1056
			$terms_by_id["{$term->term_id}"] = $term;
1057
		}
1058
1059
		$term_order = get_option( 'nova_menu_order', array() );
1060
1061
		$return = array();
1062 View Code Duplication
		foreach ( $term_order as $term_id ) {
1063
			if ( isset( $terms_by_id["$term_id"] ) ) {
1064
				$return[] = $terms_by_id["$term_id"];
1065
				unset( $terms_by_id["$term_id"] );
1066
			}
1067
		}
1068
1069
		foreach ( $terms_by_id as $term_id => $term ) {
1070
			$return[] = $term;
1071
		}
1072
1073
		return $return;
1074
	}
1075
1076
	function get_menu_item_menu_leaf( $post_id ) {
1077
		// Get first menu taxonomy "leaf"
1078
		$term_ids = wp_get_object_terms( $post_id, self::MENU_TAX, array( 'fields' => 'ids' ) );
1079
1080
		foreach ( $term_ids as $term_id ) {
1081
			$children = get_term_children( $term_id, self::MENU_TAX );
1082
			if ( ! $children ) {
1083
				break;
1084
			}
1085
		}
1086
1087
		if ( ! isset( $term_id ) ) {
1088
			return false;
1089
		}
1090
1091
		return get_term( $term_id, self::MENU_TAX );
1092
1093
	}
1094
1095
	function list_labels( $post_id = 0 ) {
1096
		$post = get_post( $post_id );
1097
		echo get_the_term_list( $post->ID, self::MENU_ITEM_LABEL_TAX, '', _x( ', ', 'Nova label separator', 'jetpack' ), '' );
1098
	}
1099
1100
	function list_admin_labels( $post_id = 0 ) {
1101
		$post = get_post( $post_id );
1102
		$labels = get_the_terms( $post->ID, self::MENU_ITEM_LABEL_TAX );
1103
		if ( !empty( $labels ) ) {
1104
			$out = array();
1105
			foreach ( $labels as $label ) {
1106
				$out[] = sprintf( '<a href="%s">%s</a>',
1107
					esc_url( add_query_arg( array(
1108
						'post_type' => self::MENU_ITEM_POST_TYPE,
1109
						'taxonomy'  => self::MENU_ITEM_LABEL_TAX,
1110
						'term'      => $label->slug
1111
					), 'edit.php' ) ),
1112
					esc_html( sanitize_term_field( 'name', $label->name, $label->term_id, self::MENU_ITEM_LABEL_TAX, 'display' ) )
1113
				);
1114
			}
1115
1116
			echo join( _x( ', ', 'Nova label separator', 'jetpack' ), $out );
1117
		} else {
1118
			esc_html_e( 'No Labels', 'jetpack' );
1119
		}
1120
	}
1121
1122
	function set_price( $post_id = 0, $price = '' ) {
1123
		$post = get_post( $post_id );
1124
1125
		return update_post_meta( $post->ID, 'nova_price', $price );
1126
	}
1127
1128
	function get_price( $post_id = 0 ) {
1129
		$post = get_post( $post_id );
1130
1131
		return get_post_meta( $post->ID, 'nova_price', true );
1132
	}
1133
1134
	function display_price( $post_id = 0 ) {
1135
		echo esc_html( $this->get_price( $post_id ) );
1136
	}
1137
1138
/* Menu Item Loop Markup */
1139
1140
	/* Does not support nested loops */
1141
1142
	function get_menu_item_loop_markup( $field = null ) {
1143
		return $this->menu_item_loop_markup;
1144
	}
1145
1146
	/**
1147
	 * Sets up the loop markup.
1148
	 * Attached to the 'template_include' *filter*,
1149
	 * which fires only during a real blog view (not in admin, feeds, etc.)
1150
	 *
1151
	 * @param string Template File
1152
	 * @return string Template File.  VERY Important.
1153
	 */
1154
	function setup_menu_item_loop_markup__in_filter( $template ) {
1155
		add_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
1156
1157
		return $template;
1158
	}
1159
1160
	/**
1161
	 * If the Query is a Menu Item Query, start outputing the Menu Item Loop Marku
1162
	 * Attached to the 'loop_start' action.
1163
	 *
1164
	 * @param WP_Query
1165
	 */
1166
	function start_menu_item_loop( $query ) {
1167
		if ( !$this->is_menu_item_query( $query ) ) {
1168
			return;
1169
		}
1170
1171
		$this->menu_item_loop_last_term_id = false;
1172
		$this->menu_item_loop_current_term = false;
1173
1174
		add_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
1175
		add_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
1176
	}
1177
1178
	/**
1179
	 * Outputs the Menu Item Loop Marku
1180
	 * Attached to the 'the_post' action.
1181
	 *
1182
	 * @param WP_Post
1183
	 */
1184
	function menu_item_loop_each_post( $post ) {
1185
		$this->menu_item_loop_current_term = $this->get_menu_item_menu_leaf( $post->ID );
1186
1187
		if ( false === $this->menu_item_loop_last_term_id ) {
1188
			// We're at the very beginning of the loop
1189
1190
			$this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
1191
			$this->menu_item_loop_header(); // Output the menu's header
1192
		} elseif ( $this->menu_item_loop_last_term_id != $this->menu_item_loop_current_term->term_id ) {
1193
			// We're not at the very beginning but still need to start a new menu section.  End the previous menu section first.
1194
1195
			$this->menu_item_loop_close_element( 'menu' ); // End the previous menu section
1196
			$this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
1197
			$this->menu_item_loop_header(); // Output the menu's header
1198
		}
1199
1200
		$this->menu_item_loop_last_term_id = $this->menu_item_loop_current_term->term_id;
1201
	}
1202
1203
	/**
1204
	 * If the Query is a Menu Item Query, stop outputing the Menu Item Loop Marku
1205
	 * Attached to the 'loop_end' action.
1206
	 *
1207
	 * @param WP_Query
1208
	 */
1209
	function stop_menu_item_loop( $query ) {
1210
		if ( !$this->is_menu_item_query( $query ) ) {
1211
			return;
1212
		}
1213
1214
		remove_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
1215
		remove_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
1216
		remove_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
1217
1218
		$this->menu_item_loop_close_element( 'menu' ); // End the last menu section
1219
	}
1220
1221
	/**
1222
	 * Outputs the Menu Group Header
1223
	 */
1224
	function menu_item_loop_header() {
1225
		$this->menu_item_loop_open_element( 'menu_header' );
1226
			$this->menu_item_loop_open_element( 'menu_title' );
1227
				echo esc_html( $this->menu_item_loop_current_term->name ); // @todo tax filter
1228
			$this->menu_item_loop_close_element( 'menu_title' );
1229
		if ( $this->menu_item_loop_current_term->description ) :
1230
			$this->menu_item_loop_open_element( 'menu_description' );
1231
				echo esc_html( $this->menu_item_loop_current_term->description ); // @todo kses, tax filter
1232
			$this->menu_item_loop_close_element( 'menu_description' );
1233
		endif;
1234
		$this->menu_item_loop_close_element( 'menu_header' );
1235
	}
1236
1237
	/**
1238
	 * Outputs a Menu Item Markup element opening tag
1239
	 *
1240
	 * @param string $field - Menu Item Markup settings field.
1241
	 */
1242 View Code Duplication
	function menu_item_loop_open_element( $field ) {
1243
		$markup = $this->get_menu_item_loop_markup();
1244
		/**
1245
		 * Filter a menu item's element opening tag.
1246
		 *
1247
		 * @module custom-content-types
1248
		 *
1249
		 * @since 4.4.0
1250
		 *
1251
		 * @param string       $tag    Menu item's element opening tag.
1252
		 * @param string       $field  Menu Item Markup settings field.
1253
		 * @param array        $markup Array of markup elements for the menu item.
1254
		 * @param false|object $term   Taxonomy term for current menu item.
1255
		 */
1256
		echo apply_filters(
1257
			'jetpack_nova_menu_item_loop_open_element',
1258
			'<' . tag_escape( $markup["{$field}_tag"] ) . $this->menu_item_loop_class( $markup["{$field}_class"] ) . ">\n",
1259
			$field,
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $field.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1260
			$markup,
1261
			$this->menu_item_loop_current_term
1262
		);
1263
	}
1264
1265
	/**
1266
	 * Outputs a Menu Item Markup element closing tag
1267
	 *
1268
	 * @param string $field - Menu Item Markup settings field
1269
	 */
1270 View Code Duplication
	function menu_item_loop_close_element( $field ) {
1271
		$markup = $this->get_menu_item_loop_markup();
1272
		/**
1273
		 * Filter a menu item's element closing tag.
1274
		 *
1275
		 * @module custom-content-types
1276
		 *
1277
		 * @since 4.4.0
1278
		 *
1279
		 * @param string       $tag    Menu item's element closing tag.
1280
		 * @param string       $field  Menu Item Markup settings field.
1281
		 * @param array        $markup Array of markup elements for the menu item.
1282
		 * @param false|object $term   Taxonomy term for current menu item.
1283
		 */
1284
		echo apply_filters(
1285
			'jetpack_nova_menu_item_loop_close_element',
1286
			'</' . tag_escape( $markup["{$field}_tag"] ) . ">\n",
1287
			$field,
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $field.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1288
			$markup,
1289
			$this->menu_item_loop_current_term
1290
		);
1291
	}
1292
1293
	/**
1294
	 * Returns a Menu Item Markup element's class attribute.
1295
	 *
1296
	 * @param  string $class Class name.
1297
	 * @return string HTML   class attribute with leading whitespace.
1298
	 */
1299
	function menu_item_loop_class( $class ) {
1300
		if ( ! $class ) {
1301
			return '';
1302
		}
1303
1304
		/**
1305
		 * Filter a menu Item Markup element's class attribute.
1306
		 *
1307
		 * @module custom-content-types
1308
		 *
1309
		 * @since 4.4.0
1310
		 *
1311
		 * @param string       $tag    Menu Item Markup element's class attribute.
1312
		 * @param string       $class  Menu Item Class name.
1313
		 * @param false|object $term   Taxonomy term for current menu item.
1314
		 */
1315
		return apply_filters(
1316
			'jetpack_nova_menu_item_loop_class',
1317
			' class="' . esc_attr( $class ) . '"',
1318
			$class,
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $class.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1319
			$this->menu_item_loop_current_term
1320
		);
1321
	}
1322
}
1323
1324
add_action( 'init', array( 'Nova_Restaurant', 'init' ) );
1325