Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 103 additions & 11 deletions add-descendants-as-submenu-items.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,29 @@ class Add_Descendants_As_Submenu_Items {
public $form_idtracker = 'adasi-idtracker';

/**
* ID/name prefix for the checkbox inputs.
* ID/name prefix for the main checkbox input.
*
* @since 1.0.0
* @var string
*/
public $form_checkbox_prefix = 'adasi-child-checkbox-';

/**
* ID/name prefix for the skip-this-item checkbox input.
*
* @since 1.0.0
* @var string
*/
public $form_checkbox_skip_prefix = 'adasi-skip-checkbox-';

/**
* ID/name prefix for the children-only checkbox input.
*
* @since 1.0.0
* @var string
*/
public $form_checkbox_shallow_prefix = 'adasi-shallow-checkbox-';

/**
* admin-ajax.php action name for some server-side checks.
*
Expand All @@ -79,6 +95,22 @@ class Add_Descendants_As_Submenu_Items {
*/
public $meta_key = '_adasi_enabled';

/**
* Meta key name for storing skip-this-item status.
*
* @since 1.0.0
* @var string
*/
public $meta_key_skip = '_adasi_skip';

/**
* Meta key name for storing children-only status.
*
* @since 1.0.0
* @var string
*/
public $meta_key_shallow = '_adasi_shallow';

/**
* Stores submenu items that have been added by this plugin.
*
Expand Down Expand Up @@ -120,10 +152,14 @@ public function maybe_enqueue_script( $hook_suffix ) {

// Pass dynamic values to the Javascript file
$params = array(
'idtracker' => $this->form_idtracker,
'ajaxaction' => $this->ajax_action,
'checkboxprefix' => $this->form_checkbox_prefix,
'checkboxdesc' => __( 'Automatically add all descendants as submenu items', 'add-descendants-as-submenu-items' ),
'idtracker' => $this->form_idtracker,
'ajaxaction' => $this->ajax_action,
'checkboxprefix' => $this->form_checkbox_prefix,
'checkboxdesc' => __( 'Automatically add all descendants as submenu items', 'add-descendants-as-submenu-items' ),
'checkboxskipprefix' => $this->form_checkbox_skip_prefix,
'checkboxskipdesc' => __( 'Hide this item', 'add-descendants-as-submenu-items' ),
'checkboxshallowprefix' => $this->form_checkbox_shallow_prefix,
'checkboxshallowdesc' => __( 'Show only direct descendants (children)', 'add-descendants-as-submenu-items' ),
);

wp_localize_script( $script_slug, 'ADASIParams', $params );
Expand All @@ -150,6 +186,8 @@ public function ajax_get_menu_status() {

$response['add'] = 1;
$response['checked'] = ( $this->is_enabled_for_menu_item( $id ) ) ? 1 : 0;
$response['skip'] = ( $this->is_item_marked_for_skip( $id ) ) ? 1 : 0;
$response['shallow'] = ( $this->is_item_shallow( $id ) ) ? 1 : 0;

exit( json_encode( $response ) );
}
Expand Down Expand Up @@ -199,6 +237,30 @@ public function is_enabled_for_menu_item( $id ) {
return (bool) get_post_meta( $id, $this->meta_key, true );
}

/**
* Returns a boolean stating whether or not this plugin's option to skip the parent item is enabled.
*
* @since 1.3.0
*
* @param int $id The ID of a menu item.
* @return boolean Skip status
*/
public function is_item_marked_for_skip( $id ) {
return (bool) get_post_meta( $id, $this->meta_key_skip, true );
}

/**
* Returns a boolean stating whether or not this plugin's option to show only children is enabled.
*
* @since 1.3.0
*
* @param int $id The ID of a menu item.
* @return boolean Shallow status
*/
public function is_item_shallow( $id ) {
return (bool) get_post_meta( $id, $this->meta_key_shallow, true );
}

/**
* Saves the status of the checkboxes that were added to the nav menu configuration panel.
* Called when a nav menu is saved.
Expand All @@ -219,6 +281,17 @@ public function save_nav_menu_custom_fields() {
update_post_meta( $id, $this->meta_key, true );
else
delete_post_meta( $id, $this->meta_key );

if ( isset( $_POST[$this->form_checkbox_skip_prefix . $id] ) )
update_post_meta( $id, $this->meta_key_skip, true );
else
delete_post_meta( $id, $this->meta_key_skip );

if ( isset( $_POST[$this->form_checkbox_shallow_prefix . $id] ) )
update_post_meta( $id, $this->meta_key_shallow, true );
else
delete_post_meta( $id, $this->meta_key_shallow );

}

// This gets called twice for some reason
Expand All @@ -227,7 +300,7 @@ public function save_nav_menu_custom_fields() {

/**
* Loop through all nav menu items checking whether the functionality has been enabled or not for them.
* If enabled, add in submenu items for all of their descendants
* If enabled, add in submenu items for their descendants according to selected options.
*
* @since 1.0.0
*
Expand All @@ -237,10 +310,21 @@ public function save_nav_menu_custom_fields() {
public function add_children_to_menu( $items ) {
$menu_order = count( $items ) + 1000;
$filter_added = false;
$new_items = array();

foreach ( $items as $item ) {
if ( ! $this->is_menu_item_supported( $item->db_id, $item->type, $item->object ) || ! $this->is_enabled_for_menu_item( $item->db_id ) )

// Creating a new array in order to avoid operating on the array that is looped through. Problematic if is_item_marked_for_skip() == true.
$new_items[] = $item;

if ( ! $this->is_menu_item_supported( $item->db_id, $item->type, $item->object ) || ! $this->is_enabled_for_menu_item( $item->db_id ) ) {
continue;
}

// Remove item if "Hide this item" is checked
if ( $this->is_item_marked_for_skip( $item->ID ) ) {
array_pop( $new_items );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Explicit is better than implicit." Thus explicitly poping out rather than if-ing around to avoid adding to the array in the first place.

}

// Get all descendants
switch ( $item->type ) {
Expand Down Expand Up @@ -277,13 +361,21 @@ public function add_children_to_menu( $items ) {
$child = wp_setup_nav_menu_item( $child );
$child->db_id = $child->ID;

// Skip if not immediate child
if ( $this->is_item_shallow( $item->ID ) && $child->$parent_field != $item->object_id ) {
continue;
}

$this->added[$child->ID] = true; // We'll need this later

// Set the parent menu item.
// When adding items as children of existing menu items, their IDs won't match up
// which means that the parent value can't always be used.
if ( $child->$parent_field == $item->object_id ) {
$child->menu_item_parent = $item->ID; // Children
if ( $child->$parent_field == $item->object_id ) { // Children
if ( $this->is_item_marked_for_skip( $item->ID ) )
$child->menu_item_parent = $item->parent;
else
$child->menu_item_parent = $item->ID;
} else {
$child->menu_item_parent = $child->$parent_field ; // Grandchildren, etc.
}
Expand All @@ -293,11 +385,11 @@ public function add_children_to_menu( $items ) {
$menu_order++;
$child->menu_order = $menu_order;

$items[] = $child;
$new_items[] = $child;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's important not to append the children items to the end of $items array because:
If $item is marked to be hidden (is_item_marked_for_skip) it's children would be added to the last place in the menu. By creating the new $new_items array, children are added in the same place as the $item (effectively replacing it).

}
}

return $items;
return $new_items;
}

/**
Expand Down
31 changes: 28 additions & 3 deletions checkboxes.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,38 @@ jQuery(document).ready(function($) {
// Track IDs to check the POST for
IDtracker.val( IDtracker.val() + ',' + itemID );

// Add the checkbox
// Get ids for checkboxes
var checkboxid = ADASIParams.checkboxprefix + itemID;
$(item).find('.menu-item-actions .link-to-original').after('<p><label><input type="checkbox" id="' + checkboxid + '" name="' + checkboxid + '" value="1" /> ' + ADASIParams.checkboxdesc + '</label></p>');
var checkboxskipid = ADASIParams.checkboxskipprefix + itemID;
var checkboxshallowid = ADASIParams.checkboxshallowprefix + itemID;

if ( response.checked ) {
// Add the checkboxes
$(item).find('.menu-item-actions .link-to-original + *').eq(0)
.before('<p><label><input type="checkbox" id="' + checkboxid + '" name="' + checkboxid + '" value="1" /> ' + ADASIParams.checkboxdesc + '</label></p>')
.before('<p><label style="margin-left: 30px;"><input type="checkbox" id="' + checkboxskipid + '" name="' + checkboxskipid + '" value="1" /> ' + ADASIParams.checkboxskipdesc + '</label></p>')
.before('<p><label style="margin-left: 30px;"><input type="checkbox" id="' + checkboxshallowid + '" name="' + checkboxshallowid + '" value="1" /> ' + ADASIParams.checkboxshallowdesc + '</label></p>');

var $label = $('#' + checkboxid).parents('li.menu-item').eq(0).find('.item-title');
var $notification = $('<emph style="font-size: 80%; font-style: italic; margin-left: 15px;"></emph>').appendTo($label);
if ( response.checked ) {
$('#' + checkboxid).prop('checked', true);
}
if ( response.shallow ) {
$('#' + checkboxshallowid).prop('checked', true);
}
if ( response.skip ) {
$('#' + checkboxskipid).prop('checked', true);
}
if ( response.checked ) {
$notification.html('+&nbsp;descendants');
if ( response.shallow ) {
$notification.html('+&nbsp;children');
}
if ( response.skip ) {
$notification.text($notification.text() + ', item hidden');
}
}

}
},
'json'
Expand Down
9 changes: 7 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
=== Add Descendants As Submenu Items ===
Contributors: Viper007Bond
Tags: menu, nav menu, children, descendants
Tested up to: 3.5
Stable tag: 1.2.0
Tested up to: 3.5.1
Stable tag: 1.3.0

Automatically all of a nav menu item's descendants as submenu items. Designed for pages but will work with any hierarchical post type or taxonomy.

Expand All @@ -23,6 +23,11 @@ Visit Plugins &rarr; Add New in your administration area and search for the name

== ChangeLog ==

= Version 1.3.0 =
* Option to add only direct descendants (i.e. children).
* Option to skip the parent item, adding only the descendants.
* Added a small indicator "+descendants" or "+children" to visually identify menu elements that have additional items automatically added by this plugin.

= Version 1.2.0 =
* `_get_post_ancestors()` will/was deprecated in WordPress 3.5 and no longer works. Parts of this plugin have been rewritten to more properly get post ancestors.
* Bug fix: Don't highlight parents of different types. Post types and terms can have the same IDs.
Expand Down