Skip to content

Commit 469b150

Browse files
Add nav menu field to scf (#44)
* Add nav menu field to scf
1 parent d8806e2 commit 469b150

File tree

4 files changed

+332
-0
lines changed

4 files changed

+332
-0
lines changed

docs/features/field/nav_menu/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Nav Menu Field
2+
3+
The Nav Menu Field field provides a way to select nav menus and output them.
4+
5+
## Key Features
6+
7+
- Different Return Value (Object, HTML, ID)
8+
- Different Menu Container (nav, div)
9+
- Ability to select no value
10+
11+
## Settings
12+
13+
- Return Value
14+
- Menu Container
15+
- Allow Null?
16+
17+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# **Using the Nav Menu Field**
2+
3+
## **Basic Setup**
4+
5+
To get started with the **Nav Menu Field** in SCF, follow these steps to configure and display a WordPress navigation menu:
6+
7+
### **Step 1: Create a New Field Group**
8+
9+
First, create a new field group in **Secure Custom Fields (SCF)**. This field group will hold your custom fields, including the **Nav Menu** field.
10+
11+
1. Go to **Custom Fields > Add New** in your WordPress admin panel.
12+
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).
13+
14+
### **Step 2: Add a Nav Menu Field**
15+
16+
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.
17+
18+
1. Click **Add Field** within the field group.
19+
2. Set the **Field Type** to **Nav Menu**.
20+
3. Configure the necessary field options based on your needs.
21+
22+
### **Step 3: Configure Options**
23+
24+
Configure the field options for the **Nav Menu** field to tailor it to your needs.
25+
26+
- **Return Value:** Choose how you want the selected menu to be returned:
27+
- **Menu ID:** The ID of the selected menu.
28+
- **Nav Menu HTML:** The raw HTML of the selected menu.
29+
- **Nav Menu Object:** The complete menu object, including properties like the menu name and term ID.
30+
31+
- **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.
32+
33+
- **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.
34+
35+
### **Code Example: Basic Setup**
36+
37+
Here's how you can implement the **Nav Menu Field** in a template file:
38+
39+
```php
40+
// Check if the Nav Menu Field has a value
41+
$menu_id = get_field('your_nav_menu_field_name');
42+
43+
if ($menu_id) {
44+
// Get the menu object or HTML based on your configuration
45+
$menu_html = wp_nav_menu(array(
46+
'menu' => $menu_id, // Use the menu ID
47+
'container' => 'nav', // Use a 'nav' container
48+
'echo' => false, // Don't output directly; return the HTML
49+
));
50+
51+
echo $menu_html; // Output the menu HTML
52+
}
53+
```
54+
55+
## **Common Use Cases**
56+
57+
1. **Use to Output WordPress Navigation Menu Anywhere:**
58+
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.
59+
60+
## **Tips**
61+
62+
- **To Add More Menu Containers:**
63+
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.
64+
65+
Example:
66+
```php
67+
function my_custom_menu_container_tags($tags) {
68+
$tags[] = 'section'; // Adds 'section' as an allowed container tag
69+
return $tags;
70+
}
71+
add_filter('wp_nav_menu_container_allowed_tags', 'my_custom_menu_container_tags');
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
<?php
2+
/**
3+
* This is a PHP file containing the code for the acf_field_nav_menu class.
4+
*
5+
* @package wordpress/secure-custom-fields
6+
* @since 6.5.0
7+
*/
8+
9+
if ( ! class_exists( 'Acf_Field_Nav_Menu' ) ) :
10+
/**
11+
* Acf Nav menu field class
12+
*/
13+
class Acf_Field_Nav_Menu extends acf_field {
14+
15+
/**
16+
* This function will setup the field type data
17+
*
18+
* @type function
19+
* @date 5/03/2014
20+
* @since 6.5.0
21+
*/
22+
public function initialize() {
23+
24+
// vars
25+
$this->name = 'nav_menu';
26+
$this->label = _x( 'Nav Menu', 'noun', 'secure-custom-fields' );
27+
$this->category = 'choice';
28+
$this->description = __( 'A dropdown list with a selection of menu choices that you can chose.', 'secure-custom-fields' );
29+
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-select.png';
30+
$this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/nav_menu/';
31+
$this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/select/nav_menu-tutorial/';
32+
$this->defaults = array(
33+
'save_format' => 'id',
34+
'allow_null' => 0,
35+
'container' => 'div',
36+
);
37+
38+
add_filter( 'acf/field_wrapper_attributes', array( $this, 'nav_menu_field_wrapper_attributes' ), 10, 2 );
39+
}
40+
41+
/**
42+
* Renders the Nav Menu Field options seen when editing a Nav Menu Field.
43+
*
44+
* @param array $field The array representation of the current Nav Menu Field.
45+
*/
46+
public function render_field_settings( $field ) {
47+
$allow_null = $field['allow_null'];
48+
$nav_menus = wp_get_nav_menus( $allow_null );
49+
if ( current_theme_supports( 'menus' ) ) {
50+
if ( empty( $nav_menus ) ) {
51+
?>
52+
<div class="acf-field">
53+
<div class="acf-notice">
54+
<p>
55+
<?php
56+
printf(
57+
/* translators: %s is a link to the WordPress menu creation page in the admin dashboard. */
58+
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' ),
59+
'<a href="' . esc_url( admin_url( 'nav-menus.php' ) ) . '">' . esc_html__( 'the menu settings page', 'secure-custom-fields' ) . '</a>'
60+
);
61+
?>
62+
</p>
63+
</div>
64+
</div>
65+
<?php
66+
}
67+
} else {
68+
?>
69+
<div class="acf-field">
70+
<div class="acf-notice">
71+
<p>
72+
<?php esc_html_e( 'Warning: The theme does not support navigation menus, the field will not display.', 'secure-custom-fields' ); ?>
73+
</p>
74+
</div>
75+
</div>
76+
<?php
77+
78+
}
79+
80+
// Register the Return Value format setting
81+
acf_render_field_setting(
82+
$field,
83+
array(
84+
'label' => __( 'Return Value', 'secure-custom-fields' ),
85+
'instructions' => __( 'Specify the returned value on front end', 'secure-custom-fields' ),
86+
'type' => 'radio',
87+
'name' => 'save_format',
88+
'layout' => 'horizontal',
89+
'choices' => array(
90+
'object' => __( 'Nav Menu Object', 'secure-custom-fields' ),
91+
'menu' => __( 'Nav Menu HTML', 'secure-custom-fields' ),
92+
'id' => __( 'Nav Menu ID', 'secure-custom-fields' ),
93+
),
94+
)
95+
);
96+
97+
// Register the Menu Container setting
98+
acf_render_field_setting(
99+
$field,
100+
array(
101+
'label' => __( 'Menu Container', 'secure-custom-fields' ),
102+
'instructions' => __( "What to wrap the Menu's ul with (when returning HTML only)", 'secure-custom-fields' ),
103+
'type' => 'select',
104+
'name' => 'container',
105+
'choices' => $this->get_allowed_nav_container_tags(),
106+
)
107+
);
108+
109+
// Register the Allow Null setting
110+
acf_render_field_setting(
111+
$field,
112+
array(
113+
'label' => __( 'Allow Null?', 'secure-custom-fields' ),
114+
'type' => 'radio',
115+
'name' => 'allow_null',
116+
'layout' => 'horizontal',
117+
'choices' => array(
118+
1 => __( 'Yes', 'secure-custom-fields' ),
119+
0 => __( 'No', 'secure-custom-fields' ),
120+
),
121+
)
122+
);
123+
}
124+
/**
125+
* Get the allowed wrapper tags for use with wp_nav_menu().
126+
*
127+
* @return array An array of allowed wrapper tags.
128+
*/
129+
private function get_allowed_nav_container_tags() {
130+
$tags = apply_filters( 'wp_nav_menu_container_allowed_tags', array( 'div', 'nav' ) );
131+
$formatted_tags = array(
132+
'0' => 'None',
133+
);
134+
135+
foreach ( $tags as $tag ) {
136+
$formatted_tags[ $tag ] = $tag;
137+
}
138+
139+
return $formatted_tags;
140+
}
141+
/**
142+
* Renders the Nav Menu Field.
143+
*
144+
* @param array $field The array representation of the current Nav Menu Field.
145+
*/
146+
public function render_field( $field ) {
147+
$allow_null = $field['allow_null'];
148+
$nav_menus = wp_get_nav_menus( $allow_null );
149+
if ( ! current_theme_supports( 'menus' ) || empty( $nav_menus ) ) {
150+
return; // Don't render the field
151+
}
152+
153+
?>
154+
<select id="<?php esc_attr( $field['id'] ); ?>" class="<?php echo esc_attr( $field['class'] ); ?>" name="<?php echo esc_attr( $field['name'] ); ?>">
155+
<?php
156+
if ( $allow_null ) {
157+
?>
158+
<option value="">
159+
<?php esc_html_e( '- Select -', 'secure-custom-fields' ); ?>
160+
</option>
161+
<?php
162+
}
163+
foreach ( $nav_menus as $nav_menu_name ) {
164+
?>
165+
<option value="<?php echo esc_attr( $nav_menu_name->term_id ); ?>" <?php selected( $field['value'], $nav_menu_name->term_id ); ?>>
166+
<?php echo esc_html( $nav_menu_name->name ); ?>
167+
</option>
168+
<?php } ?>
169+
</select>
170+
<?php
171+
}
172+
173+
/**
174+
* Renders the Nav Menu Field.
175+
*
176+
* @param int $value The Nav Menu ID selected for this Nav Menu Field.
177+
* @param int $post_id The Post ID this $value is associated with.
178+
* @param array $field The array representation of the current Nav Menu Field.
179+
*
180+
* @return mixed The Nav Menu ID, or the Nav Menu HTML, or the Nav Menu Object, or false.
181+
*/
182+
public function format_value( $value, $post_id, $field ) {
183+
// bail early if no value
184+
if ( empty( $value ) ) {
185+
return false;
186+
}
187+
188+
// check format
189+
if ( 'object' === $field['save_format'] ) {
190+
$wp_menu_object = wp_get_nav_menu_object( $value );
191+
192+
if ( empty( $wp_menu_object ) ) {
193+
return false;
194+
}
195+
196+
$menu_object = new stdClass();
197+
198+
$menu_object->ID = $wp_menu_object->term_id;
199+
$menu_object->name = $wp_menu_object->name;
200+
$menu_object->slug = $wp_menu_object->slug;
201+
$menu_object->count = $wp_menu_object->count;
202+
203+
return $menu_object;
204+
} elseif ( 'menu' === $field['save_format'] ) {
205+
ob_start();
206+
207+
wp_nav_menu(
208+
array(
209+
'menu' => $value,
210+
'container' => $field['container'],
211+
)
212+
);
213+
214+
return ob_get_clean();
215+
}
216+
217+
// Just return the Nav Menu ID
218+
return $value;
219+
}
220+
/**
221+
* Hide Field if no support
222+
*
223+
* @param array $wrapper Wrapper array that contains all field main wrapper attributes.
224+
* @param array $field main field array will all field data.
225+
*/
226+
public function nav_menu_field_wrapper_attributes( $wrapper, $field ) {
227+
// Check if it's the nav menu field (or any other specific field type)
228+
if ( isset( $field['type'] ) && 'nav_menu' === $field['type'] ) {
229+
// Check if menus are available and the theme supports them
230+
if ( ! current_theme_supports( 'menus' ) ) {
231+
// Add inline CSS to hide the field if no menus are available
232+
$wrapper['style'] = 'display: none;'; // You can also add additional styles
233+
}
234+
}
235+
236+
return $wrapper;
237+
}
238+
}
239+
240+
241+
// initialize
242+
acf_register_field_type( 'Acf_Field_Nav_Menu' );
243+
endif; // class_exists check

secure-custom-fields.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ public function init() {
328328
acf_include( 'includes/fields/class-acf-field-flexible-content.php' );
329329
acf_include( 'includes/fields/class-acf-field-gallery.php' );
330330
acf_include( 'includes/fields/class-acf-field-clone.php' );
331+
acf_include( 'includes/fields/class-acf-field-nav-menu.php' );
331332

332333
/**
333334
* Fires after field types have been included.

0 commit comments

Comments
 (0)