Skip to content

Commit 280bc23

Browse files
authored
Merge pull request #773 from alleyinteractive/add-menu-item-context
Add Menu Item Context
2 parents 1a40280 + 01bcf85 commit 280bc23

File tree

5 files changed

+394
-4
lines changed

5 files changed

+394
-4
lines changed

fieldmanager.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
* Fieldmanager Base Plugin File.
44
*
55
* @package Fieldmanager
6-
* @version 1.2.6
6+
* @version 1.3.0
77
*/
88

99
/*
1010
Plugin Name: Fieldmanager
1111
Plugin URI: https://github.com/alleyinteractive/wordpress-fieldmanager
1212
Description: Add fields to WordPress programatically.
1313
Author: Alley
14-
Version: 1.2.6
14+
Version: 1.3.0
1515
Author URI: https://www.alley.co/
1616
*/
1717

1818
/**
1919
* Current version of Fieldmanager.
2020
*/
21-
define( 'FM_VERSION', '1.2.6' );
21+
define( 'FM_VERSION', '1.3.0' );
2222

2323
/**
2424
* Filesystem path to Fieldmanager.
@@ -358,6 +358,10 @@ function fm_calculate_context() {
358358
$calculated_context = array( 'term', sanitize_text_field( wp_unslash( $_GET['taxonomy'] ) ) ); // WPCS: input var okay.
359359
}
360360
break;
361+
// Context = "nav-menu".
362+
case 'nav-menus.php':
363+
$calculated_context = array( 'nav_menu', null );
364+
break;
361365
}
362366
}
363367
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Fieldmanager",
33
"description": "Fieldmanager is a comprehensive toolkit for building forms, metaboxes, and custom admin screens for WordPress.",
4-
"version": "1.2.6",
4+
"version": "1.3.0",
55
"repository": {
66
"type": "git",
77
"url": "https://github.com/alleyinteractive/wordpress-fieldmanager"

php/class-fieldmanager-field.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,14 @@ public function add_quickedit_box( $title, $post_types, $column_display_callback
12931293
return new Fieldmanager_Context_QuickEdit( $title, $post_types, $column_display_callback, $column_title, $this );
12941294
}
12951295

1296+
/**
1297+
* Add this group to an nav menu.
1298+
*/
1299+
public function add_nav_menu_fields() {
1300+
$this->require_base();
1301+
return new Fieldmanager_Context_MenuItem( $this );
1302+
}
1303+
12961304
/**
12971305
* Add this group to an options page.
12981306
*
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
/**
3+
* Class file for Fieldmanager_Context_Menu_Item
4+
*
5+
* @package Fieldmanager
6+
*/
7+
8+
/**
9+
* Use fieldmanager to ad custom fields to a menu item.
10+
*/
11+
class Fieldmanager_Context_MenuItem extends Fieldmanager_Context_Storable {
12+
/**
13+
* What post types to render this Quickedit form.
14+
*
15+
* @var string
16+
*/
17+
public $post_types = array();
18+
19+
/**
20+
* Base field
21+
*
22+
* @var Fieldmanager_Field
23+
*/
24+
public $fm = '';
25+
26+
/**
27+
* The original form name.
28+
*
29+
* @var string
30+
*/
31+
private $original_form_name = '';
32+
33+
/**
34+
* Add a context to a fieldmanager.
35+
*
36+
* @throws FM_Developer_Exception Must have a valid display callback.
37+
*
38+
* @param Fieldmanager_Field $fm The base field.
39+
*/
40+
public function __construct( $fm = null ) {
41+
global $wp_version;
42+
43+
// Needs WP version 5.4.0 or greater.
44+
if ( version_compare( $wp_version, '5.4.0', '<' ) ) {
45+
return;
46+
}
47+
48+
$this->fm = $fm;
49+
50+
$this->fm->data_type = 'post';
51+
52+
// Save the original form name.
53+
$this->original_form_name = $this->fm->name;
54+
55+
add_filter( 'wp_nav_menu_item_custom_fields', array( $this, 'add_fields' ), 10, 5 );
56+
add_action( 'wp_update_nav_menu_item', array( $this, 'save_fields' ), 10, 3 );
57+
}
58+
59+
/**
60+
* Get the menu item form name given the menu ID. This allows FM to save meta
61+
* data to each menu item within the same POST request.
62+
*
63+
* @param int $menu_id The menu ID.
64+
* @return string The form name.
65+
*/
66+
public function get_menu_item_form_name( $menu_id ) {
67+
return $this->original_form_name . '_fm-menu-item-id-' . absint( $menu_id );
68+
}
69+
70+
/**
71+
* Parse the form name, assuming it already contains the menu ID, into its
72+
* original form name.
73+
*
74+
* @param string $form_name The form name.
75+
* @return mixed False if form name does not exist or an array of menu ID and name.
76+
*/
77+
public function parse_form_name( $form_name ) {
78+
// Not a menu item form name.
79+
if ( false === strpos( $form_name, '_fm-menu-item-id-', true ) ) {
80+
return false;
81+
}
82+
83+
// Break out the original name from the menu item ID.
84+
$parts = explode( '_fm-menu-item-id-', $form_name );
85+
86+
if ( ! empty( $parts[0] ) && ! empty( $parts[1] ) ) {
87+
return array(
88+
'name' => $parts[0],
89+
'id' => absint( $parts[1] ),
90+
);
91+
}
92+
93+
return false;
94+
}
95+
96+
97+
/**
98+
* Add fields to the editor of a nav menu item.
99+
*
100+
* @param int $item_id Menu item ID.
101+
*/
102+
public function add_fields( $item_id ) {
103+
// Set the ID.
104+
$this->fm->data_id = $item_id;
105+
106+
// Ensure the ID is part of the name.
107+
$this->fm->name = $this->get_menu_item_form_name( $item_id );
108+
109+
// Render the field.
110+
$this->render_field();
111+
}
112+
113+
/**
114+
* Save post meta for nav menu items.
115+
*
116+
* @param int $menu_id The ID of the menu.
117+
* @param int $menu_item_db_id The ID of the menu item.
118+
* @param array $menu_item_args Menu item args.
119+
*/
120+
public function save_fields( $menu_id, $menu_item_db_id, $menu_item_args ) {
121+
// Ensure the ID is part of the name.
122+
$this->fm->name = $this->get_menu_item_form_name( $menu_item_db_id );
123+
124+
// Ensure that the nonce is set and valid.
125+
if ( ! $this->is_valid_nonce() ) {
126+
return;
127+
}
128+
129+
// Make sure the current user can save this post.
130+
if ( ! current_user_can( 'edit_theme_options' ) ) {
131+
$this->fm->_unauthorized_access( __( 'User cannot edit this menu item', 'fieldmanager' ) );
132+
return;
133+
}
134+
135+
$this->save_to_post_meta( $menu_item_db_id );
136+
}
137+
138+
/**
139+
* Helper to save an array of data to post meta.
140+
*
141+
* @param int $post_id The post ID.
142+
* @param array $data The post data.
143+
*/
144+
public function save_to_post_meta( $post_id, $data = null ) {
145+
$this->fm->data_id = $post_id;
146+
$this->fm->data_type = 'post';
147+
148+
$this->save( $data );
149+
}
150+
151+
/**
152+
* Get post meta.
153+
*
154+
* @see get_post_meta().
155+
*
156+
* @param int $post_id Post ID.
157+
* @param string $meta_key Optional. The meta key to retrieve. By default, returns
158+
* data for all keys. Default empty.
159+
* @param bool $single Optional. Whether to return a single value. Default false.
160+
*/
161+
protected function get_data( $post_id, $meta_key, $single = false ) {
162+
$parts = $this->parse_form_name( $meta_key );
163+
164+
if ( ! empty( $parts['name'] ) && ! empty( $parts['id'] ) ) {
165+
$post_id = $parts['id'];
166+
$meta_key = $parts['name'];
167+
}
168+
169+
return get_post_meta( $post_id, $meta_key, $single );
170+
}
171+
172+
/**
173+
* Add post meta.
174+
*
175+
* @see add_post_meta().
176+
*
177+
* @param int $post_id Post ID.
178+
* @param string $meta_key Metadata name.
179+
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
180+
* @param bool $unique Optional. Whether the same key should not be added.
181+
* Default false.
182+
*/
183+
protected function add_data( $post_id, $meta_key, $meta_value, $unique = false ) {
184+
$parts = $this->parse_form_name( $meta_key );
185+
186+
if ( ! empty( $parts['name'] ) && ! empty( $parts['id'] ) ) {
187+
$post_id = $parts['id'];
188+
$meta_key = $parts['name'];
189+
}
190+
191+
return add_post_meta( $post_id, $meta_key, $meta_value, $unique );
192+
}
193+
194+
/**
195+
* Update post meta.
196+
*
197+
* @see update_post_meta().
198+
*
199+
* @param int $post_id Post ID.
200+
* @param string $meta_key Metadata key.
201+
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
202+
* @param mixed $data_prev_value Optional. Previous value to check before removing.
203+
* Default empty.
204+
*/
205+
protected function update_data( $post_id, $meta_key, $meta_value, $data_prev_value = '' ) {
206+
$parts = $this->parse_form_name( $meta_key );
207+
208+
if ( ! empty( $parts['name'] ) && ! empty( $parts['id'] ) ) {
209+
$post_id = $parts['id'];
210+
$meta_key = $parts['name'];
211+
}
212+
213+
$meta_value = $this->sanitize_scalar_value( $meta_value );
214+
return update_post_meta( $post_id, $meta_key, $meta_value, $data_prev_value );
215+
}
216+
217+
/**
218+
* Delete post meta.
219+
*
220+
* @see delete_post_meta().
221+
*
222+
* @param int $post_id Post ID.
223+
* @param string $meta_key Metadata name.
224+
* @param mixed $meta_value Optional. Metadata value. Must be serializable if
225+
* non-scalar. Default empty.
226+
*/
227+
protected function delete_data( $post_id, $meta_key, $meta_value = '' ) {
228+
$parts = $this->parse_form_name( $meta_key );
229+
230+
if ( ! empty( $parts['name'] ) && ! empty( $parts['id'] ) ) {
231+
$post_id = $parts['id'];
232+
$meta_key = $parts['name'];
233+
}
234+
235+
return delete_post_meta( $post_id, $meta_key, $meta_value );
236+
}
237+
}

0 commit comments

Comments
 (0)