Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nav menu field to scf #44

Open
wants to merge 9 commits into
base: trunk
Choose a base branch
from
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
17 changes: 17 additions & 0 deletions docs/features/field/nav_menu/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Nav Menu Field

The Nav Menu Field field provides a way to select nav menus and output them.

## Key Features

- Different Return Value (Object, HTML, ID)
- Different Menu Container (nav, div)
- Ability to select no value

## Settings

- Return Value
- Menu Container
- Allow Null?


71 changes: 71 additions & 0 deletions docs/features/field/nav_menu/tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# **Using the Nav Menu Field**

## **Basic Setup**

To get started with the **Nav Menu Field** in SCF, follow these steps to configure and display a WordPress navigation menu:

### **Step 1: Create a New Field Group**

First, create a new field group in **Secure Custom Fields (SCF)**. This field group will hold your custom fields, including the **Nav Menu** field.

1. Go to **Custom Fields > Add New** in your WordPress admin panel.
2. Title your field group and choose the location rules for where this field group should be displayed (e.g., on a specific page or post type).

### **Step 2: Add a Nav Menu Field**

Once you've created a new field group, add a new field of type **Nav Menu**. This field will allow users to select a navigation menu from the available menus on your site.

1. Click **Add Field** within the field group.
2. Set the **Field Type** to **Nav Menu**.
3. Configure the necessary field options based on your needs.

### **Step 3: Configure Options**

Configure the field options for the **Nav Menu** field to tailor it to your needs.

- **Return Value:** Choose how you want the selected menu to be returned:
- **Menu ID:** The ID of the selected menu.
- **Nav Menu HTML:** The raw HTML of the selected menu.
- **Nav Menu Object:** The complete menu object, including properties like the menu name and term ID.

- **Menu Container:** This option determines the wrapper tag for the menu when the **Nav Menu HTML** return format is selected. Common options include `div`, `nav`, or `none`. You can also add additional container tags using the `wp_nav_menu_container_allowed_tags` filter.

- **Allow Null:** Set this option to **true** or **false** to allow or disallow a **null** value (i.e., no menu selected). When **true**, an empty option will be available for the user to select.

### **Code Example: Basic Setup**

Here's how you can implement the **Nav Menu Field** in a template file:

```php
// Check if the Nav Menu Field has a value
$menu_id = get_field('your_nav_menu_field_name');

if ($menu_id) {
// Get the menu object or HTML based on your configuration
$menu_html = wp_nav_menu(array(
'menu' => $menu_id, // Use the menu ID
'container' => 'nav', // Use a 'nav' container
'echo' => false, // Don't output directly; return the HTML
));

echo $menu_html; // Output the menu HTML
}
```

## **Common Use Cases**

1. **Use to Output WordPress Navigation Menu Anywhere:**
The **Nav Menu Field** allows you to output a WordPress navigation menu in custom locations across your site, such as in custom templates, widgets, or shortcodes.

## **Tips**

- **To Add More Menu Containers:**
Use the `wp_nav_menu_container_allowed_tags` hook to add additional allowed container tags for the Nav Menu field. This will enable more flexibility in the menu's wrapper tag.

Example:
```php
function my_custom_menu_container_tags($tags) {
$tags[] = 'section'; // Adds 'section' as an allowed container tag
return $tags;
}
add_filter('wp_nav_menu_container_allowed_tags', 'my_custom_menu_container_tags');
243 changes: 243 additions & 0 deletions includes/fields/class-acf-field-nav-menu.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<?php
/**
* This is a PHP file containing the code for the acf_field_nav_menu class.
*
* @package wordpress/secure-custom-fields
* @since 6.5.0
*/

if ( ! class_exists( 'Acf_Field_Nav_Menu' ) ) :
/**
* Acf Nav menu field class
*/
class Acf_Field_Nav_Menu extends acf_field {

/**
* This function will setup the field type data
*
* @type function
* @date 5/03/2014
* @since 6.5.0
*/
public function initialize() {

// vars
$this->name = 'nav_menu';
$this->label = _x( 'Nav Menu', 'noun', 'secure-custom-fields' );
$this->category = 'choice';
$this->description = __( 'A dropdown list with a selection of menu choices that you can chose.', 'secure-custom-fields' );
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-select.png';
$this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/nav_menu/';
$this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/select/nav_menu-tutorial/';
$this->defaults = array(
'save_format' => 'id',
'allow_null' => 0,
'container' => 'div',
);

add_filter( 'acf/field_wrapper_attributes', array( $this, 'nav_menu_field_wrapper_attributes' ), 10, 2 );
}

/**
* Renders the Nav Menu Field options seen when editing a Nav Menu Field.
*
* @param array $field The array representation of the current Nav Menu Field.
*/
public function render_field_settings( $field ) {
$allow_null = $field['allow_null'];
$nav_menus = wp_get_nav_menus( $allow_null );
if ( current_theme_supports( 'menus' ) ) {
if ( empty( $nav_menus ) ) {
?>
<div class="acf-field">
<div class="acf-notice">
<p>
<?php
printf(
/* translators: %s is a link to the WordPress menu creation page in the admin dashboard. */
esc_html_x( 'Warning: No menus have been created yet. Please visit %s to set up your site navigation.', 'Admin menu creation notice', 'secure-custom-fields' ),
'<a href="' . esc_url( admin_url( 'nav-menus.php' ) ) . '">' . esc_html__( 'the menu settings page', 'secure-custom-fields' ) . '</a>'
);
?>
</p>
</div>
</div>
<?php
}
} else {
?>
<div class="acf-field">
<div class="acf-notice">
<p>
<?php esc_html_e( 'Warning: The theme does not support navigation menus, the field will not display.', 'secure-custom-fields' ); ?>
</p>
</div>
</div>
<?php

}

// Register the Return Value format setting
acf_render_field_setting(
$field,
array(
'label' => __( 'Return Value', 'secure-custom-fields' ),
'instructions' => __( 'Specify the returned value on front end', 'secure-custom-fields' ),
'type' => 'radio',
'name' => 'save_format',
'layout' => 'horizontal',
'choices' => array(
'object' => __( 'Nav Menu Object', 'secure-custom-fields' ),
'menu' => __( 'Nav Menu HTML', 'secure-custom-fields' ),
'id' => __( 'Nav Menu ID', 'secure-custom-fields' ),
),
)
);

// Register the Menu Container setting
acf_render_field_setting(
$field,
array(
'label' => __( 'Menu Container', 'secure-custom-fields' ),
'instructions' => __( "What to wrap the Menu's ul with (when returning HTML only)", 'secure-custom-fields' ),
'type' => 'select',
'name' => 'container',
'choices' => $this->get_allowed_nav_container_tags(),
)
);

// Register the Allow Null setting
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'secure-custom-fields' ),
'type' => 'radio',
'name' => 'allow_null',
'layout' => 'horizontal',
'choices' => array(
1 => __( 'Yes', 'secure-custom-fields' ),
0 => __( 'No', 'secure-custom-fields' ),
),
)
);
}
/**
* Get the allowed wrapper tags for use with wp_nav_menu().
*
* @return array An array of allowed wrapper tags.
*/
private function get_allowed_nav_container_tags() {
$tags = apply_filters( 'wp_nav_menu_container_allowed_tags', array( 'div', 'nav' ) );
$formatted_tags = array(
'0' => 'None',
);

foreach ( $tags as $tag ) {
$formatted_tags[ $tag ] = $tag;
}

return $formatted_tags;
}
/**
* Renders the Nav Menu Field.
*
* @param array $field The array representation of the current Nav Menu Field.
*/
public function render_field( $field ) {
$allow_null = $field['allow_null'];
$nav_menus = wp_get_nav_menus( $allow_null );
if ( ! current_theme_supports( 'menus' ) || empty( $nav_menus ) ) {
return; // Don't render the field
}

?>
<select id="<?php esc_attr( $field['id'] ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" name="<?php echo esc_attr( $field['name'] ); ?>">
<?php
if ( $allow_null ) {
?>
<option value="">
<?php esc_html_e( '- Select -', 'secure-custom-fields' ); ?>
</option>
<?php
}
foreach ( $nav_menus as $nav_menu_name ) {
?>
<option value="<?php echo esc_attr( $nav_menu_name->term_id ); ?>" <?php selected( $field['value'], $nav_menu_name->term_id ); ?>>
<?php echo esc_html( $nav_menu_name->name ); ?>
</option>
<?php } ?>
</select>
<?php
}

/**
* Renders the Nav Menu Field.
*
* @param int $value The Nav Menu ID selected for this Nav Menu Field.
* @param int $post_id The Post ID this $value is associated with.
* @param array $field The array representation of the current Nav Menu Field.
*
* @return mixed The Nav Menu ID, or the Nav Menu HTML, or the Nav Menu Object, or false.
*/
public function format_value( $value, $post_id, $field ) {
// bail early if no value
if ( empty( $value ) ) {
return false;
}

// check format
if ( 'object' === $field['save_format'] ) {
$wp_menu_object = wp_get_nav_menu_object( $value );

if ( empty( $wp_menu_object ) ) {
return false;
}

$menu_object = new stdClass();

$menu_object->ID = $wp_menu_object->term_id;
$menu_object->name = $wp_menu_object->name;
$menu_object->slug = $wp_menu_object->slug;
$menu_object->count = $wp_menu_object->count;

return $menu_object;
} elseif ( 'menu' === $field['save_format'] ) {
ob_start();

wp_nav_menu(
array(
'menu' => $value,
'container' => $field['container'],
)
);

return ob_get_clean();
}

// Just return the Nav Menu ID
return $value;
}
/**
* Hide Field if no support
*
* @param array $wrapper Wrapper array that contains all field main wrapper attributes.
* @param array $field main field array will all field data.
*/
public function nav_menu_field_wrapper_attributes( $wrapper, $field ) {
// Check if it's the nav menu field (or any other specific field type)
if ( isset( $field['type'] ) && 'nav_menu' === $field['type'] ) {
// Check if menus are available and the theme supports them
if ( ! current_theme_supports( 'menus' ) ) {
// Add inline CSS to hide the field if no menus are available
$wrapper['style'] = 'display: none;'; // You can also add additional styles
}
}

return $wrapper;
}
}


// initialize
acf_register_field_type( 'Acf_Field_Nav_Menu' );
endif; // class_exists check
1 change: 1 addition & 0 deletions secure-custom-fields.php
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ public function init() {
acf_include( 'includes/fields/class-acf-field-flexible-content.php' );
acf_include( 'includes/fields/class-acf-field-gallery.php' );
acf_include( 'includes/fields/class-acf-field-clone.php' );
acf_include( 'includes/fields/class-acf-field-nav-menu.php' );

/**
* Fires after field types have been included.
Expand Down