1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Carbon_Fields\Container; |
4
|
|
|
|
5
|
|
|
use Carbon_Fields\Datastore\Datastore; |
6
|
|
|
use Carbon_Fields\Exception\Incorrect_Syntax_Exception; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Nav menu item fields container class. |
10
|
|
|
*/ |
11
|
|
|
class Nav_Menu_Item_Container extends Container { |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Array of container clones for every menu item |
15
|
|
|
* |
16
|
|
|
* @see init() |
17
|
|
|
* @var int |
18
|
|
|
*/ |
19
|
|
|
protected $menu_item_instances = array(); |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* The menu item id this container is for |
23
|
|
|
* |
24
|
|
|
* @var int |
25
|
|
|
*/ |
26
|
|
|
protected $menu_item_id = 0; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* {@inheritDoc} |
30
|
|
|
*/ |
31
|
|
|
public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) { |
32
|
|
|
parent::__construct( $id, $title, $type, $condition_collection, $condition_translator ); |
33
|
|
|
|
34
|
|
|
if ( ! $this->get_datastore() ) { |
35
|
|
|
$this->set_datastore( Datastore::make( 'nav_menu_item' ), $this->has_default_datastore() ); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
// Register the custom edit walker only once |
39
|
|
|
$callable = array( get_class(), 'edit_walker' ); |
40
|
|
|
if ( ! has_filter( 'wp_edit_nav_menu_walker', $callable ) ) { |
41
|
|
|
add_filter( 'wp_edit_nav_menu_walker', $callable, 10, 2 ); |
42
|
|
|
} |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Perform instance initialization |
47
|
|
|
* |
48
|
|
|
* @param int $menu_item_id Used to pass the correct menu_item_id to the Container object |
49
|
|
|
*/ |
50
|
|
|
public function init( $menu_item_id = 0 ) { |
51
|
|
|
$this->menu_item_id = $menu_item_id; |
52
|
|
|
$this->get_datastore()->set_object_id( $this->menu_item_id ); |
53
|
|
|
$this->_attach(); |
54
|
|
|
|
55
|
|
|
// Only the base container should register for updating/rendering |
56
|
|
|
if ( $this->menu_item_id === 0 ) { |
57
|
|
|
add_action( 'wp_update_nav_menu_item', array( $this, 'update' ), 10, 3 ); |
58
|
|
|
add_action( 'carbon_fields_print_nav_menu_item_container_fields', array( $this, 'form' ), 10, 5 ); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
return $this; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Checks whether the current save request is valid |
66
|
|
|
* |
67
|
|
|
* @return bool |
68
|
|
|
*/ |
69
|
|
View Code Duplication |
public function is_valid_save() { |
|
|
|
|
70
|
|
|
if ( ! $this->verified_nonce_in_request() ) { |
71
|
|
|
return false; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
$params = func_get_args(); |
75
|
|
|
return $this->is_valid_attach_for_object( $params[0] ); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Perform save operation after successful is_valid_save() check. |
80
|
|
|
* The call is propagated to all fields in the container. |
81
|
|
|
*/ |
82
|
|
View Code Duplication |
public function save( $data = null ) { |
|
|
|
|
83
|
|
|
foreach ( $this->fields as $field ) { |
84
|
|
|
$field->set_value_from_input( stripslashes_deep( $_POST ) ); |
85
|
|
|
$field->save(); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
do_action( 'carbon_fields_nav_menu_item_container_saved', $this ); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* {@inheritDoc} |
93
|
|
|
*/ |
94
|
|
|
public function is_active() { |
95
|
|
|
return ( $this->active && $this->menu_item_id !== 0 ); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Get environment array for page request (in admin) |
100
|
|
|
* |
101
|
|
|
* @return array |
102
|
|
|
*/ |
103
|
|
|
protected function get_environment_for_request() { |
104
|
|
|
return array(); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Perform checks whether the container should be attached during the current request |
109
|
|
|
* |
110
|
|
|
* @return bool True if the container is allowed to be attached |
111
|
|
|
*/ |
112
|
|
|
public function is_valid_attach_for_request() { |
113
|
|
|
global $pagenow; |
114
|
|
|
|
115
|
|
|
$input = stripslashes_deep( $_REQUEST ); |
116
|
|
|
$ajax = defined( 'DOING_AJAX' ) ? DOING_AJAX : false; |
117
|
|
|
$ajax_action = isset( $input['action'] ) ? $input['action'] : ''; |
118
|
|
|
|
119
|
|
|
$is_on_menu_page = ( $pagenow === 'nav-menus.php' ); |
120
|
|
|
$is_menu_ajax_request = ( $ajax && $ajax_action === 'add-menu-item' ); |
121
|
|
|
if ( ! $is_on_menu_page && ! $is_menu_ajax_request ) { |
122
|
|
|
return false; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
return $this->static_conditions_pass(); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Get environment array for object id |
130
|
|
|
* |
131
|
|
|
* @return array |
132
|
|
|
*/ |
133
|
|
|
protected function get_environment_for_object( $object_id ) { |
134
|
|
|
return array(); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Check container attachment rules against object id |
139
|
|
|
* |
140
|
|
|
* @param int $object_id |
141
|
|
|
* @return bool |
142
|
|
|
*/ |
143
|
|
View Code Duplication |
public function is_valid_attach_for_object( $object_id = null ) { |
|
|
|
|
144
|
|
|
$post = get_post( $object_id ); |
145
|
|
|
|
146
|
|
|
if ( ! $post ) { |
147
|
|
|
return false; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
if ( $post->post_type !== 'nav_menu_item' ) { |
151
|
|
|
return false; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
return $this->all_conditions_pass( intval( $post->ID ) ); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Output the container markup |
159
|
|
|
*/ |
160
|
|
|
public function render() { |
161
|
|
|
include \Carbon_Fields\DIR . '/templates/Container/nav_menu_item.php'; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Trigger Save for all instances |
166
|
|
|
*/ |
167
|
|
|
public function update( $menu_id, $current_menu_item_id ) { |
168
|
|
|
if ( ! $this->is_valid_attach_for_request() ) { |
169
|
|
|
return; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$clone = $this->get_clone_for_menu_item( $current_menu_item_id, false ); |
173
|
|
|
$clone->_save( $current_menu_item_id ); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Render custom fields inside each Nav Menu entry |
178
|
|
|
*/ |
179
|
|
|
public function form( $item ) { |
180
|
|
|
if ( ! $this->is_valid_attach_for_request() ) { |
181
|
|
|
return; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
$clone = $this->get_clone_for_menu_item( $item->ID ); |
185
|
|
|
$clone->render(); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Create a clone of this container with it's own datastore for every menu item |
190
|
|
|
*/ |
191
|
|
|
protected function get_clone_for_menu_item( $menu_item_id, $load = true ) { |
192
|
|
|
if ( ! isset( $this->menu_item_instances[ $menu_item_id ] ) ) { |
193
|
|
|
$menu_item_datastore = Datastore::make( 'nav_menu_item' ); |
194
|
|
|
$menu_item_datastore->set_object_id( $menu_item_id ); |
195
|
|
|
$menu_item_field_prefix = $menu_item_datastore->get_garbage_prefix(); |
196
|
|
|
|
197
|
|
|
$custom_fields = array(); |
198
|
|
|
$fields = $this->get_fields(); |
199
|
|
|
foreach ( $fields as $field ) { |
200
|
|
|
$tmp_field = clone $field; |
201
|
|
|
|
202
|
|
|
$tmp_field->set_id( $menu_item_field_prefix . $tmp_field->get_id() ); |
203
|
|
|
$tmp_field->set_name( $menu_item_field_prefix . $tmp_field->get_name() ); |
204
|
|
|
$tmp_field->set_datastore( $menu_item_datastore, true ); |
205
|
|
|
|
206
|
|
|
$custom_fields[] = $tmp_field; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
$container = Container::factory( $this->type, $menu_item_field_prefix . $this->get_id() ) |
210
|
|
|
->set_datastore( $menu_item_datastore, true ) |
211
|
|
|
->add_fields( $custom_fields ) |
212
|
|
|
->init( $menu_item_id ); |
|
|
|
|
213
|
|
|
if ( $load ) { |
214
|
|
|
$container->load(); |
215
|
|
|
} |
216
|
|
|
$this->menu_item_instances[ $menu_item_id ] = $container; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
return $this->menu_item_instances[ $menu_item_id ]; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Setup custom walker for the Nav Menu entries |
224
|
|
|
*/ |
225
|
|
|
public static function edit_walker() { |
226
|
|
|
return 'Carbon_Fields\\Walker\\Nav_Menu_Item_Edit_Walker'; |
227
|
|
|
} |
228
|
|
|
} |
229
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.