PageRenderTime 73ms CodeModel.GetById 9ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-content/plugins/custom-post-type-auto-menu/bfp-cpt-auto-menu.php

https://gitlab.com/vovanduc/dainghia
PHP | 836 lines | 326 code | 152 blank | 358 comment | 61 complexity | c4c62d5d173201062e9adfe34adcecb5 MD5 | raw file
  1<?php
  2/*
  3  Plugin Name: Custom Post Type Auto Menu
  4  Plugin URI: https://github.com/badfun/custom-post-type-auto-menu
  5  Description: Automatically adds new custom post type posts to the chosen menu and parent item as a sub-menu item.
  6  Version: 1.1.9
  7  Author: Ken Dirschl, Bad Fun Productions
  8  Author URI: http://badfunproductions.com
  9  Author Email: ken@badfunproductions.com
 10  Text Domain: bfp-cpt-auto-menu
 11  Domain Path: /lang/
 12
 13  License:
 14
 15  Copyright 2015 Bad Fun Productions
 16
 17  This program is free software; you can redistribute it and/or modify
 18  it under the terms of the GNU General Public License, version 2, as
 19  published by the Free Software Foundation.
 20
 21  This program is distributed in the hope that it will be useful,
 22  but WITHOUT ANY WARRANTY; without even the implied warranty of
 23  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 24  GNU General Public License for more details.
 25
 26  You should have received a copy of the GNU General Public License
 27  along with this program; if not, write to the Free Software
 28  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 29
 30 */
 31defined( 'ABSPATH' ) or die( 'You do not have the required permissions' );
 32
 33include( plugin_dir_path( __FILE__ ) . 'classes/cpt_nav_menu_handler.class.php' );
 34
 35if ( ! class_exists( 'Custom_Post_Type_Auto_Menu' ) ) {
 36
 37
 38	class Custom_Post_Type_Auto_Menu {
 39
 40		/**
 41		 * Create private instance variable
 42		 * @link  http://jumping-duck.com/tutorial/wordpress-plugin-structure/
 43		 *
 44		 * @since 1.0.0
 45		 *
 46		 * @var bool
 47		 */
 48		private static $instance = false;
 49
 50		/**
 51		 * Instantiate singleton object
 52		 * @link  http://jumping-duck.com/tutorial/wordpress-plugin-structure/
 53		 *
 54		 * @since 1.0.0
 55		 *
 56		 * @return bool|Custom_Post_Type_Auto_Menu
 57		 */
 58		public static function get_instance() {
 59			if ( ! self::$instance ) {
 60				self::$instance = new self();
 61			}
 62
 63			return self::$instance;
 64		}
 65
 66		/**
 67		 * Plugin version, used for cache-busting of style and script file references.
 68		 *
 69		 * @since   1.0.0
 70		 *
 71		 * @var     string
 72		 */
 73		protected $version = '1.1.9';
 74
 75		/**
 76		 * Unique identifier for your plugin.
 77		 *
 78		 * Use this value (not the variable name) as the text domain when internationalizing strings of text. It should
 79		 * match the Text Domain file header in the main plugin file.
 80		 *
 81		 * @since    1.0.0
 82		 *
 83		 * @var      string
 84		 */
 85		protected $plugin_slug = 'bfp-cpt-auto-menu';
 86
 87		/**
 88		 * Constructor. Load action hooks here.
 89		 * @version 1.1.0
 90		 *
 91		 * @since   1.0.0
 92		 */
 93		private function __construct() {
 94			// load text domain for internationalization
 95			add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
 96
 97			// test for nav menus
 98			add_action( 'admin_notices', array( $this, 'test_for_nav_menu_support' ) );
 99			add_action( 'admin_notices', array( $this, 'test_for_nav_menu' ) );
100
101			$this->nav_menu_handler = new Cpt_Nav_Menu_Handler( $this );
102
103			// load admin settings actions
104			add_action( 'admin_init', array( &$this, 'admin_init' ) );
105
106			// create an admin page and prepare enqueue our scripts
107			add_action( 'admin_menu', array( &$this, 'add_admin_menu_page' ) );
108
109			// redirect must happen before headers are sent
110			add_action( 'admin_menu', array( $this, 'cpt_settings_redirect' ) );
111
112			// load ajax handler
113			add_action( 'wp_ajax_admin_script_ajax', array( $this, 'admin_script_ajax_handler' ) );
114
115			// register activation
116			register_activation_hook( __FILE__, array( $this, 'activate' ) );
117		}
118
119		/**
120		 * Properties
121		 * @version 1.1.0
122		 *
123		 * @since   1.0.0
124		 *
125		 * @var string
126		 */
127		private $parent_menu;
128		private $parent_menu_item;
129		private $parent_menu_item_ID;
130		private $current_cpt;
131		private $cpt_list;
132		private $settings;
133		private $main_page;
134
135		/**
136		 * Activation
137		 * @version 1.1.0
138		 *
139		 * @since   1.0.0
140		 */
141		static function activate() {
142			//@TODO-bfp: this redirect not working
143			// Redirect to settings page if not activating multiple plugins at once
144			if ( ! isset( $_GET['activate-multi'] ) ) {
145				wp_redirect( admin_url( 'admin.php?page=cpt_auto_menu&tab=select_cpt' ) );
146			}
147		}
148
149		/**
150		 * Load the plugin text domain for translation.
151		 *
152		 * @since    1.0.0
153		 */
154		public function load_plugin_textdomain() {
155
156			$domain = $this->plugin_slug;
157			$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
158
159			load_textdomain( $domain, WP_LANG_DIR . '/' . $domain . '/' . $domain . '-' . $locale . '.mo' );
160			load_plugin_textdomain( $domain, false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );
161		}
162
163		/**
164		 * Add admin menu page and load admin js action to load script only on our page
165		 * @link  http://wordpress.stackexchange.com/questions/41207/how-do-i-enqueue-styles-scripts-on-certain-wp-admin-pages#76420
166		 * dashicons requires version 3.8: @link http://melchoyce.github.io/dashicons/
167		 *
168		 * @since 1.1.0
169		 *
170		 */
171		public function add_admin_menu_page() {
172			$this->main_page = add_menu_page(
173				__( 'CPT Auto Menu Settings', 'bfp-cpt-auto-menu' ), __( 'CPT Auto Menu', 'bfp-cpt-auto-menu' ), 'manage_options', 'cpt_auto_menu', array( &$this, 'plugin_settings_page' ), 'dashicons-screenoptions'
174			);
175
176			add_action( 'load-' . $this->main_page, array( $this, 'load_admin_js' ) );
177
178			// also use this hook for page redirection
179			add_action( 'load-' . $this->main_page, array( $this, 'admin_page_redirect' ) );
180
181			// and for adding our stylesheet
182			add_action( 'admin_print_styles-' . $this->main_page, array( $this, 'load_admin_css' ) );
183		}
184
185		/**
186		 * Prepare our js to be loaded into the queue after add admin menu page has been called
187		 * @link  http://wordpress.stackexchange.com/questions/41207/how-do-i-enqueue-styles-scripts-on-certain-wp-admin-pages#76420
188		 *
189		 * @since 1.1.0
190		 */
191		public function load_admin_js() {
192			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_js' ) );
193		}
194
195		/**
196		 * Register and enqueue admin-specific JavaScript.
197		 *
198		 * @since     1.0.0
199		 *
200		 */
201		public function enqueue_admin_js() {
202
203			wp_enqueue_script( $this->plugin_slug . '-admin-script', plugins_url( 'js/admin.js', __FILE__ ), array( 'jquery' ), $this->version );
204
205			// wp_localize_script added to same action hook
206			$this->localize_admin_script();
207		}
208
209		/**
210		 * Localize admin script so we can pass Selected Menu object in ajax. Also add nonce for security.
211		 *
212		 * @since 1.0.0
213		 *
214		 */
215		private function localize_admin_script() {
216
217			wp_localize_script(
218				$this->plugin_slug . '-admin-script', 'AjaxSelected', array(
219					'ajaxurl'   => admin_url( 'admin-ajax.php' ),
220					'ajaxnonce' => wp_create_nonce( 'ajax-form-nonce' )
221				)
222			);
223		}
224
225		/**
226		 * Register our css stylesheet
227		 *
228		 * @since 1.1.0
229		 *
230		 */
231		private function admin_register_css() {
232			wp_register_style( 'cpt-auto-menu-style', plugins_url( 'css/cpt-auto-menu.css', __FILE__ ) );
233		}
234
235		/**
236		 * Load our css stylesheet.
237		 *
238		 * @since 1.1.0
239		 *
240		 */
241		public function load_admin_css() {
242			wp_enqueue_style( 'cpt-auto-menu-style' );
243		}
244
245		/**
246		 * Test for Nav Menu Support. If theme does not support menus output admin error notice
247		 *
248		 * @since 1.0.0
249		 *
250		 * @return bool
251		 *
252		 */
253		public function test_for_nav_menu_support() {
254
255			if ( ! current_theme_supports( 'menus' ) ) {
256				$html = '<div class="error"><p>';
257				$html .= __( 'Your theme does not support custom navigation menus. The plugin requires themes built for at least WordPress 3.0', 'bfp-cpt-auto-menu' );
258				$html .= '</p></div>';
259
260				echo $html;
261			}
262
263			// otherwise return true
264			return true;
265		}
266
267		/**
268		 * Test that a Nav Menu has been setup, otherwise output admin error notice
269		 *
270		 * @since 1.0.0
271		 *
272		 * @return bool
273		 */
274		public function test_for_nav_menu() {
275
276			// if theme does not support menus don't need to show this message as well
277			if ( current_theme_supports( 'menus' ) ) {
278
279				$menus = wp_get_nav_menus();
280
281				if ( empty( $menus ) ) {
282					$html = '<div class="error"><p>';
283					$html .= __( 'You do not have any menus setup with your theme. You need to create a menu to use this plugin.', 'bfp-cpt-auto-menu' );
284					$html .= '</p></div>';
285
286					echo $html;
287				}
288
289				// otherwise return true
290				return true;
291			}
292		}
293
294		/**
295		 * Receive the Ajax data from POST and use it on the page
296		 * Some good info here: @link http://www.garyc40.com/2010/03/5-tips-for-using-ajax-in-wordpress/
297		 * @version 1.1.0
298		 *
299		 * @since   1.0.0
300		 *
301		 *
302		 */
303		public function admin_script_ajax_handler() {
304
305			// Menu name determines Parent Menu Item
306			if ( isset( $_POST['selected_menu'] ) ) {
307
308				// verify our nonce
309				if ( ! wp_verify_nonce( $_POST['ajaxnonce'], 'ajax-form-nonce' ) ) {
310					die( __( 'There is an access error', 'bfp-cpt-auto-menu' ) );
311				}
312
313				// verify user has permission
314				if ( ! current_user_can( 'edit_posts' ) ) {
315					die( __( 'You do not have sufficient permission', 'bfp-cpt-auto-menu' ) );
316				}
317
318				$main_menu = wp_get_nav_menu_object( $_POST['selected_menu'] );
319
320				// make sure there is a value then extract the ID
321				if ( true == $main_menu ) {
322					$parent_menu_ID = (int) $main_menu->term_id;
323
324
325					// get option if one exists
326					$parent_menu_item = $this->settings['parent_menu'];
327
328					$menu_items = wp_get_nav_menu_items( $parent_menu_ID, array( 'post_status' => 'publish' ) );
329
330					foreach ( $menu_items as $menu_item ) {
331						// only display items in the root menu
332						if ( $menu_item->menu_item_parent != 0 ) {
333							continue;
334						}
335						echo '<option value="' . $menu_item->title . '"' . selected( $this->settings['parent_menu'], $menu_item->title, false ) . '>' . ucfirst( $menu_item->title ) . '</option>';
336					}
337				}
338			}
339		}
340
341		/**
342		 * Get all custom post types as names and put in an array for later access
343		 *
344		 * @since 1.1.0
345		 *
346		 * @return array
347		 */
348		private function get_custom_post_type_names() {
349			$args = array(
350				'public'   => true,
351				'_builtin' => false
352			);
353
354			// note: $output and $operator are defaults but here for readability
355			$output   = 'names';
356			$operator = 'and';
357
358			$custom_post_types = get_post_types( $args, $output, $operator );
359
360			return $custom_post_types;
361		}
362
363		/**
364		 * Get the settings for the CPT's saved in options. This way it is a single call to database
365		 * @link http://stackoverflow.com/questions/8102221/php-multidimensional-array-searching-find-key-by-specific-value
366		 *
367		 * @since 1.1.0
368		 *
369		 * @param $cpt
370		 *
371		 * @return mixed
372		 */
373		private function get_cpt_settings( $cpt ) {
374			// make sure settings exist and option is not empty
375			if ( get_option( 'cpt_auto_menu_settings' ) && ( true == get_option( 'cpt_auto_menu_settings' ) ) ) {
376
377				$settings = get_option( 'cpt_auto_menu_settings' );
378
379				// loop through the main array for each sub array
380				foreach ( $settings as $setting ) {
381					// loop through sub array
382					foreach ( $setting as $key => $value ) {
383
384						if ( $value === $cpt ) {
385							return $setting;
386							break;
387						}
388					}
389				}
390			}
391		}
392
393		/**
394		 * Get selected custom post types saved in options or create empty array
395		 *
396		 * @since 1.1.0
397		 *
398		 * @return array|mixed|void
399		 */
400		private function get_selected_cpts() {
401			if ( get_option( 'cpt_auto_menu_cpt_list' ) ) {
402				$this->cpt_list = get_option( 'cpt_auto_menu_cpt_list' );
403			} else {
404				$this->cpt_list = array();
405			}
406
407			return $this->cpt_list;
408		}
409
410		/**
411		 * Hook into WP's admin_init action hook and add our sections and fields
412		 * @version 1.1.0
413		 *
414		 * @since   1.0.0
415		 *
416		 */
417		public function admin_init() {
418			// add our option rows to options table
419			if ( false == get_option( 'cpt_auto_menu_cpt_list' ) ) {
420				add_option( 'cpt_auto_menu_cpt_list' );
421			}
422
423			if ( false == get_option( 'cpt_auto_menu_settings' ) ) {
424				add_option( 'cpt_auto_menu_settings' );
425			}
426
427
428			// register the settings
429			register_setting( 'select_cpt_settings', 'cpt_auto_menu_cpt_list', array( &$this, 'cpt_settings_validation' ) );
430			register_setting( 'select_menu_settings', 'cpt_auto_menu_settings', array( &$this, 'menu_settings_validation' ) );
431
432			/*
433			 * Sections
434			 */
435
436			// Select custom post type(s) section
437			add_settings_section(
438				'select_cpt_section', __( 'Custom Post Type Settings', 'bfp-cpt-auto-menu' ), array( &$this, 'select_cpt_section' ), 'select_cpt_settings'
439			);
440
441			// Select menu and menu parent item section
442			add_settings_section(
443				'select_menu_section', __( 'Menu and Parent Menu Item Settings', 'bfp-cpt-auto-menu' ), array( &$this, 'select_menu_section' ), 'select_menu_settings'
444			);
445
446			/*
447			 * Fields
448			 */
449
450			// select custom post types checkbox menu
451			add_settings_field(
452				'cpt_auto_menu-select_cpts', __( 'Available Custom Post Types', 'bfp-cpt-auto-menu' ), array( &$this, 'settings_field_select_cpts' ), 'select_cpt_settings', 'select_cpt_section', array()
453			);
454
455
456			// select menu and parent menu item
457			add_settings_field(
458				'cpt_auto_menu-select_menus', __( 'Select Menu and Parent Menu Item', 'bfp-cpt-auto-menu' ), array( &$this, 'settings_field_select_menus' ), 'select_menu_settings', 'select_menu_section', array()
459			);
460
461			// add our registered stylesheet
462			$this->admin_register_css();
463		}
464
465		/**
466		 * Select CPT section callback
467		 * @version 1.1.0
468		 *
469		 * @since   1.0.0
470		 *
471		 * @link    http://wordpress.stackexchange.com/questions/89251/run-function-on-settings-save
472		 *
473		 */
474		public function select_cpt_section() {
475
476			echo __( 'Select the custom post types for which you would like an automated menu.', 'bfp-cpt-auto-menu' );
477
478			// if selected cpts are not an empty array then redirect to menu page, otherwise give error message
479			if ( $this->get_selected_cpts() ) {
480				// redirect after save
481				$this->cpt_settings_redirect();
482			}
483		}
484
485		/**
486		 * Select menu section callback
487		 *
488		 * @since 1.1.0
489		 *
490		 */
491		public function select_menu_section() {
492
493			echo __( 'Select the menu and parent menu item for each custom post type', 'bfp-cpt-auto-menu' );
494		}
495
496		/**
497		 * Select which custom post types require auto menu option
498		 *
499		 * @since 1.1.0
500		 */
501		public function settings_field_select_cpts() {
502
503			$selected_cpts = $this->get_selected_cpts();
504
505			// need to define html variable before foreach loop with concantanation
506			$html = '';
507
508			// get existing custom post types and display as checklist
509			foreach ( $this->get_custom_post_type_names() as $post_type ) {
510				// check if cpt exists in get options array
511				if ( in_array( $post_type, $selected_cpts ) ) {
512
513					// if yes add checked option
514					$html .= '<input type="checkbox" class="cpts_list" name="cpt_auto_menu_cpt_list[]" value="' . $post_type . '" checked="checked">' . ucfirst( $post_type ) . '<br />';
515				} else {
516					// otherwise display without
517					$html .= '<input type="checkbox" class="cpts_list" name="cpt_auto_menu_cpt_list[]" value="' . $post_type . '">' . ucfirst( $post_type ) . '<br />';
518				}
519			}
520
521			echo $html;
522		}
523
524		/**
525		 * Get menu names and add to Select Menu
526		 *
527		 * @since 1.0.0
528		 *
529		 */
530		private function settings_field_select_menu() {
531
532			$text = __( 'Select Menu', 'bfp-cpt-auto-menu' );
533
534			// get list of menus
535			//@TODO-bfp: may need to lowercase results
536			$menus = get_terms( 'nav_menu' );
537
538			$html = '<select class="menu_name" name="cpt_auto_menu_settings[menu_name][]">';
539			$html .= '<option value="default" class="highlight">' . $text . '</option>';
540
541
542			foreach ( $menus as $menu ) {
543
544				$html .= '<option value="' . $menu->name . '"' . selected( $this->settings['menu_name'], $menu->name, false ) . '>' . ucfirst( $menu->name ) . '</option>';
545			}
546
547
548			$html .= '</select>';
549			echo $html;
550		}
551
552		/**
553		 * Get menu item names and add to Select Parent Menu Item
554		 *
555		 * @since   1.0.0
556		 *
557		 * @TODO-bfp: wp_get_nav_menu_items() generating php notice
558		 *
559		 */
560		private function settings_field_select_parent_menu_item() {
561
562			$text = __( 'Select Menu Item', 'bfp-cpt-auto-menu' );
563
564			$html = '<select class="parent_name" name="cpt_auto_menu_settings[parent_name][]">';
565			$html .= '<option value="default" class="highlight">' . $text . '</option>';
566
567			// if options exist in db then show selected option
568			if ( $this->settings['parent_menu'] != false ) {
569
570				$main_menu = wp_get_nav_menu_object( $this->settings['menu_name'] );
571
572				// then extract the ID
573				$parent_menu_ID = (int) $main_menu->term_id;
574
575				// get option if one exists
576				$parent_menu_item = $this->settings['parent_menu'];
577
578				$menu_items = wp_get_nav_menu_items( $parent_menu_ID, array( 'post_status' => 'publish' ) );
579
580				foreach ( $menu_items as $menu_item ) {
581					// only display items in the root menu
582					if ( $menu_item->menu_item_parent != 0 ) {
583						continue;
584					}
585					$html .= '<option value="' . $menu_item->title . '"' . selected( $this->settings['parent_menu'], $menu_item->title, false ) . '>' . ucfirst( $menu_item->title ) . '</option>';
586				}
587			}
588
589			$html .= '</select>';
590			echo $html;
591		}
592
593		/**
594		 * Main function for returning multiple fields based on users CPT selection
595		 *
596		 * @since 1.1.0
597		 *
598		 */
599		public function settings_field_select_menus() {
600			// get saved cpt options
601			$selected_cpts = $this->get_selected_cpts();
602			// set up an id for our array keys
603			$i = 0;
604
605			// for each cpt selected display our fields
606			foreach ( $selected_cpts as $selected_cpt ) {
607
608				// get settings array for each cpt and pass into a reusable variable
609				$this->settings = $this->get_cpt_settings( $selected_cpt );
610
611				$form = '<input type="hidden" name="cpt_auto_menu_settings[id][]" value="' . $i ++ . '">';
612				$form .= '<input type="hidden" name="cpt_auto_menu_settings[cpt][]" value="' . $selected_cpt . '">';
613
614				echo '<h4 class="cpt-heading">' . ucfirst( $selected_cpt ) . '</h4>';
615				echo $form;
616
617				echo $this->settings_field_select_menu();
618				echo $this->settings_field_select_parent_menu_item();
619
620				echo '<br />';
621			}
622		}
623
624		/**
625		 * Callback to redirect to Menu Settings tab after saving CPT settings. Hooked in Settings Section callback
626		 *
627		 * @since   1.1.0
628		 *
629		 * @version 1.1.4
630		 *
631		 * @return mixed
632		 */
633		public function cpt_settings_redirect() {
634			// make sure we are saving settings only on our page
635			if ( isset( $_GET['page'] ) && $_GET['page'] == 'cpt_auto_menu' ) {
636
637				// check if save settings have been submitted and at least one cpt has been selected
638				if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] == true ) {
639
640					// if no cpt selected echo error
641					if ( ! $this->get_selected_cpts() ) {
642
643						add_settings_error(
644							'cpt_error', esc_attr( 'settings_updated' ), __( 'You need to select at least one Custom Post Type', 'bfp-cpt-auto-menu' ), 'error'
645						);
646					} else {
647						// otherwise safe to redirect to menu page
648						wp_redirect( admin_url( 'admin.php?page=cpt_auto_menu&tab=select_menu' ) );
649						exit;
650					}
651				}
652			}
653
654			return;
655		}
656
657		/**
658		 * Make sure we always land on a tab and not the base page.
659		 * @TODO-bfp: this is a work-around due to how we are loading pages and tabs. Could be better
660		 *
661		 * @since   1.1.0
662		 *
663		 * @version 1.1.2
664		 *
665		 */
666		public function admin_page_redirect() {
667			// if our request is for the base page
668			if ( isset( $_GET['page'] ) && $_GET['page'] == 'cpt_auto_menu' ) {
669
670				// if neither tab has been requested
671				if ( isset( $_GET['tab'] ) != 'select_cpt' && isset( $_GET['tab'] ) != 'select_menu' ) {
672					// means we are on base page and can be redirected to first tab
673					wp_redirect( admin_url( 'admin.php?page=cpt_auto_menu&tab=select_cpt' ) );
674					exit;
675				}
676			}
677
678			return;
679		}
680
681		/**
682		 * Callback from cpt settings.
683		 * @link    https://github.com/tommcfarlin/WordPress-Settings-Sandbox/blob/master/functions.php
684		 *
685		 * @since   1.1.0
686		 *
687		 * @version 1.1.3
688		 *
689		 * @param $input
690		 *
691		 * @return mixed
692		 */
693		public function cpt_settings_validation( $input ) {
694
695			$output = array();
696
697			foreach ( (array)$input as $key => $value ) {
698				// check to see if current option has value. If so, process it.
699				if ( isset( $input[$key] ) ) {
700					// strip all HTML and PHP tags and properly handle quoted strings
701					$output[$key] = strip_tags( stripslashes( $input[$key] ) );
702				}
703			}
704
705			return apply_filters( 'cpt_settings_validation', $output, $input );
706		}
707
708		/**
709		 * Callback to merge the fields arrays and sanitize the inputs
710		 * @link  http://stackoverflow.com/questions/6553752/array-combine-three-or-more-arrays-with-php
711		 *
712		 * @since 1.1.0
713		 *
714		 * @param $input
715		 *
716		 * @return array
717		 */
718		public function menu_settings_validation( $input ) {
719			$keys              = $input['id'];
720			$cpt_array         = $input['cpt'];
721			$menu_name_array   = $input['menu_name'];
722			$parent_name_array = $input['parent_name'];
723
724			$output = array();
725
726			foreach ( $keys as $id => $key ) {
727				$output[$key] = array(
728					'cpt'         => $cpt_array[$id],
729					'menu_name'   => strip_tags( stripslashes( $menu_name_array[$id] ) ),
730					'parent_menu' => $parent_name_array[$id]
731				);
732			}
733
734			return apply_filters( 'menu_settings_validation', $output, $input );
735		}
736
737		/**
738		 * Menu Callback and View
739		 *
740		 * @since 1.0.0
741		 *
742		 */
743		public function plugin_settings_page() {
744
745			// if user does not have capabilities give error message
746			if ( ! current_user_can( 'manage_options' ) ) {
747
748				wp_die( __( 'You do not have sufficient permissions to access this page', 'bfp-cpt-auto-menu' ) );
749			}
750
751			// render the settings template
752			include( plugin_dir_path( __FILE__ ) . '/views/settings.php' );
753		}
754
755		/**
756		 * Create Nav Menu Items from new Custom Post Type
757		 *
758		 * @since   1.0.0
759		 *
760		 * @version 1.1.4
761		 *
762		 * @param $post_id
763		 *
764		 */
765		public function cpt_auto_menu_save( $post_id ) {
766			// get the current post
767			$post = get_post( $post_id );
768
769			//  verify post is not a revision or auto-save: http: //tommcfarlin.com/wordpress-save_post-called-twice/
770			if ( wp_is_post_revision( $post->ID ) && wp_is_post_autosave( $post->ID ) ) {
771				return;
772			}
773
774			$itemData = array(
775				'menu-item-object-id' => $post->ID,
776				'menu-item-parent-id' => $this->get_parent_menu_item_ID(),
777				'menu-item-position'  => 0,
778				'menu-item-object'    => $this->get_current_cpt(),
779				'menu-item-type'      => 'post_type',
780				'menu-item-status'    => 'publish'
781			);
782
783			// Check if menu items exist
784			$current_menu_items = wp_get_nav_menu_items( $this->get_parent_menu_ID(), array( 'post_status' => 'publish' ) );
785
786			// if no menu items exist then exit
787			if ( ! is_array( $current_menu_items ) ) {
788				return;
789			}
790
791			// create array for titles
792			$current_menu_titles = array();
793
794			// extract list of titles from menu objects and populate array
795			foreach ( $current_menu_items as $current_menu_item ) {
796				//trim the title, fix: multiple menu item added when post title has a trailing space during edit.
797				$current_menu_titles[] = trim( $current_menu_item->title );
798
799				// get the menu post object id from matching the current id to the object id in menu post object
800				// check if item is being trashed
801				if ( $current_menu_item->object_id == $post->ID && get_post_status( $post->ID ) == 'trash' ) {
802					// the id of the menu post object NOT the post!
803					$menuID = $current_menu_item->db_id;
804
805					// delete the nav menu item post object
806					wp_delete_post( $menuID );
807				}
808			}
809
810
811			// otherwise get title of current project (decode entities to prevent problems with html characters)
812			$new_project_title = wp_kses_decode_entities( get_the_title( $post->ID ) );
813
814
815			// make sure title does not exist already and that it is not an auto-draft
816			if ( ! in_array( $new_project_title, $current_menu_titles ) && ( get_post_status( $post->ID ) != 'auto-draft' ) ) {
817
818				// make sure the selected custom post type matches
819				if ( $this->get_current_cpt() != get_post_type( $post->ID ) ) {
820					return;
821				}
822
823				// finally check that we are not adding a draft to the menu
824				if ( get_post_status( $post->ID ) != 'draft' ) {
825
826					// if new title then go ahead and add new menu item
827					wp_update_nav_menu_item( $this->get_parent_menu_ID(), 0, $itemData );
828				}
829			}
830		}
831
832	}
833
834}
835
836$cpt_auto_menu_save = Custom_Post_Type_Auto_Menu::get_instance();