Nova_Restaurant

The Jetpack by WordPress.com Nova Restaurant class.

Defined (1)

The class is defined in the following location(s).

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