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