PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.0.1
Defender Security – Malware Scanner, Login Security & Firewall v3.0.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / audit / menu-audit.php

menu-audit.php in Defender Security – Malware Scanner, Login Security & Firewall 3.0.1, at src/component/audit/menu-audit.php

335 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WP_Defender\Component\Audit;
4
5 use Calotes\Helper\Array_Cache;
6 use WP_Defender\Model\Audit_Log;
7
8 /**
9 * Log menu audits
10 *
11 * @author Shoaib Ali
12 * @package WP_Defender\Component\Audit
13 * @since 2.6.1
14 */
15 class Menu_Audit extends Audit_Event {
16 public const ACTION_CREATED = 'created';
17
18 protected $type = 'Navigation Menu';
19
20 public function __construct() {
21 add_action( 'admin_init', array( $this, 'cache_old_menu' ) );
22 }
23
24 /**
25 * Cache old menu before updating.
26 */
27 public function cache_old_menu() {
28 $script_name = filter_var( $_SERVER['SCRIPT_NAME'], FILTER_SANITIZE_URL );
29 $action_type = filter_input( INPUT_POST, 'action' ) ?: filter_input( INPUT_GET, 'action' );
30 $term_id = filter_input( INPUT_POST, 'menu' ) ?: filter_input( INPUT_GET, 'menu' );
31
32 if (
33 'nav-menus.php' === basename( $script_name )
34 && ! empty( $action_type )
35 && ! empty( $term_id )
36 ) {
37 Array_Cache::append(
38 'menu_updated',
39 $this->build_menu( $term_id ),
40 'audit'
41 );
42 }
43 }
44
45 /**
46 * @return array
47 */
48 public function build_menu( $term_id ) {
49 $menu = array();
50 $menu_obj = wp_get_nav_menu_object( $term_id );
51
52 if ( ! empty( $menu_obj ) ) {
53 $menu['term_id'] = $menu_obj->term_id;
54 $menu['name'] = $menu_obj->name;
55 $menu['items'] = array();
56
57 $items = wp_get_nav_menu_items( $menu_obj->term_id );
58 if ( ! empty( $items ) ) {
59 foreach ( $items as $item ) {
60 array_push(
61 $menu['items'],
62 array(
63 'item_id' => $item->ID,
64 'title' => $item->title,
65 'url' => $item->url,
66 'object' => $item->object,
67 'menu_order' => $item->menu_order,
68 'menu_item_parent' => $item->menu_item_parent,
69 )
70 );
71 }
72 }
73 }
74
75 return $menu;
76 }
77
78 /**
79 * @return array
80 */
81 public function get_hooks() {
82 return array(
83 'wp_create_nav_menu' => array(
84 'args' => array( 'term_id', 'menu_data' ),
85 'callback' => array( self::class, 'menu_created_callback' ),
86 'event_type' => Audit_Log::EVENT_TYPE_MENU,
87 'action_type' => self::ACTION_CREATED,
88 ),
89 'wp_update_nav_menu' => array(
90 'args' => array( 'menu_id', 'menu_data' ),
91 'callback' => array( self::class, 'menu_updated_callback' ),
92 'event_type' => Audit_Log::EVENT_TYPE_MENU,
93 'action_type' => self::ACTION_UPDATED,
94 ),
95 'wp_delete_nav_menu' => array(
96 'args' => array( 'term_id' ),
97 'callback' => array( self::class, 'menu_deleted_callback' ),
98 'event_type' => Audit_Log::EVENT_TYPE_MENU,
99 'action_type' => self::ACTION_DELETED,
100 ),
101 'wp_update_nav_menu_item' => array(
102 'args' => array( 'menu_id', 'menu_item_db_id', 'args' ),
103 'callback' => array( self::class, 'menu_item_updated_callback' ),
104 'event_type' => Audit_Log::EVENT_TYPE_MENU,
105 'action_type' => self::ACTION_UPDATED,
106 ),
107 'delete_post' => array(
108 'args' => array( 'post_ID' ),
109 'callback' => array( self::class, 'menu_item_deleted_callback' ),
110 'event_type' => Audit_Log::EVENT_TYPE_MENU,
111 'action_type' => self::ACTION_DELETED,
112 ),
113 );
114 }
115
116 /**
117 * @return array|bool
118 */
119 public function menu_item_updated_callback() {
120 if ( $this->doing_autosave() ) {
121 return false;
122 }
123
124 // Filter $_POST.
125 $post_array = filter_input_array( INPUT_POST );
126
127 if ( ! isset( $post_array['menu-name'] ) ) {
128 return false;
129 }
130
131 $func_args = func_get_args();
132 $menu_id = $func_args[1]['menu_id'];
133 $menu_item_db_id = $func_args[1]['menu_item_db_id'];
134 $args = $func_args[1]['args'];
135 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
136 $old_menu = $this->get_cached_menu( $menu_id );
137
138 if ( ! empty( $old_menu ) ) {
139 $old_items = array_column( $old_menu['items'], 'item_id' );
140 $new_items = array_keys( $post_array['menu-item-title'] );
141
142 if ( ! empty( $old_menu['items'] ) ) {
143 foreach ( $old_menu['items'] as $old_item ) {
144 if ( $menu_item_db_id === $old_item['item_id'] ) {
145 if (
146 $old_item['menu_order'] !== $args['menu-item-position']
147 || $old_item['menu_item_parent'] !== $args['menu-item-parent-id']
148 || ( ! empty( $args['menu-item-title'] ) && $old_item['title'] !== $args['menu-item-title'] )
149 ) {
150 return array(
151 sprintf(
152 /* translators: */
153 __( '%1$s %2$s updated item "%3$s" from menu "%4$s"', 'wpdef' ),
154 $blog_name,
155 $this->get_user_display( get_current_user_id() ),
156 $post_array['menu-item-title'][ $menu_item_db_id ],
157 $post_array['menu-name']
158 ),
159 $this->type,
160 );
161 }
162
163 break;
164 }
165 }
166 }
167
168 $added_items = array_diff( $new_items, $old_items );
169 if ( in_array( $menu_item_db_id, $added_items, true ) ) {
170 return array(
171 sprintf(
172 /* translators: */
173 __( '%1$s %2$s added item "%3$s" to menu "%4$s"', 'wpdef' ),
174 $blog_name,
175 $this->get_user_display( get_current_user_id() ),
176 $post_array['menu-item-title'][ $menu_item_db_id ],
177 $post_array['menu-name']
178 ),
179 $this->type,
180 );
181 }
182 }
183
184 return false;
185 }
186
187 /**
188 * @return array|bool
189 */
190 public function menu_item_deleted_callback() {
191 $post_array = filter_input_array( INPUT_POST );
192
193 if ( ! isset( $post_array['menu-name'] ) ) {
194 return false;
195 }
196
197 $func_args = func_get_args();
198 $menu_item_db_id = $func_args[1]['post_ID'];
199 $menu_id = (int) $post_array['menu'];
200 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
201 $old_menu = $this->get_cached_menu( $menu_id );
202
203 if ( ! empty( $old_menu ) && is_array( $old_menu ) ) {
204 $old_items = array_column( $old_menu['items'], 'item_id' );
205 if ( in_array( $menu_item_db_id, $old_items, true ) ) {
206 $key = array_search( $menu_item_db_id, $old_items, true );
207 return array(
208 sprintf(
209 /* translators: */
210 __( '%1$s %2$s removed item "%3$s" from menu "%4$s"', 'wpdef' ),
211 $blog_name,
212 $this->get_user_display( get_current_user_id() ),
213 $old_menu['items'][ $key ]['title'],
214 $post_array['menu-name']
215 ),
216 $this->type,
217 );
218 }
219 }
220
221 return false;
222 }
223
224 /**
225 * @return array|bool
226 */
227 public function menu_created_callback() {
228 $func_args = func_get_args();
229 $menu_data = $func_args[1]['menu_data'];
230 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
231
232 return array(
233 sprintf(
234 /* translators: */
235 __( '%1$s %2$s created a new menu "%3$s"', 'wpdef' ),
236 $blog_name,
237 $this->get_user_display( get_current_user_id() ),
238 $menu_data['menu-name']
239 ),
240 $this->type,
241 );
242 }
243
244 /**
245 * @return array|bool
246 */
247 public function menu_updated_callback() {
248 $func_args = func_get_args();
249 $menu_id = $func_args[1]['menu_id'];
250 $menu_data = $func_args[1]['menu_data'];
251 $post_array = filter_input_array( INPUT_POST );
252 $new_items = isset( $post_array['menu-item-title'] ) ? array_keys( $post_array['menu-item-title'] ) : array();
253 $old_menu = $this->get_cached_menu( $menu_id );
254 $old_items = array_column( $old_menu['items'], 'item_id' );
255
256 sort( $new_items );
257 sort( $old_items );
258 if ( $new_items === $old_items ) {
259 // Check if item title, position or parent is changed.
260 $is_any_item_changed = false;
261 foreach ( $old_menu['items'] as $old_items ) {
262 if (
263 $old_items['title'] !== $post_array['menu-item-title'][ $old_items['item_id'] ]
264 || $old_items['menu_order'] !== (int) $post_array['menu-item-position'][ $old_items['item_id'] ]
265 || $old_items['menu_item_parent'] !== $post_array['menu-item-parent-id'][ $old_items['item_id'] ]
266 ) {
267 $is_any_item_changed = true;
268 break;
269 }
270 }
271
272 if ( false === $is_any_item_changed ) {
273 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
274
275 return array(
276 sprintf(
277 /* translators: */
278 __( '%1$s %2$s updated menu "%3$s"', 'wpdef' ),
279 $blog_name,
280 $this->get_user_display( get_current_user_id() ),
281 $menu_data['menu-name']
282 ),
283 $this->type,
284 );
285 }
286 }
287
288 return false;
289 }
290
291 /**
292 * @return array
293 */
294 public function menu_deleted_callback() {
295 $func_args = func_get_args();
296 $menu_id = $func_args[1]['term_id'];
297 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
298 $old_menu = $this->get_cached_menu( $menu_id );
299
300 return array(
301 sprintf(
302 /* translators: */
303 __( '%1$s %2$s deleted menu "%3$s"', 'wpdef' ),
304 $blog_name,
305 $this->get_user_display( get_current_user_id() ),
306 $old_menu['name']
307 ),
308 $this->type,
309 );
310 }
311
312 /**
313 * @param int $term_id
314 *
315 * @return array
316 */
317 public function get_cached_menu( $term_id ) {
318 $cached = Array_Cache::get( 'menu_updated', 'audit', array() );
319 foreach ( $cached as $menu_arr ) {
320 if ( $term_id === $menu_arr['term_id'] ) {
321 return $menu_arr;
322 }
323 }
324
325 return false;
326 }
327
328 /**
329 * @return bool
330 */
331 public function doing_autosave() {
332 return defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE;
333 }
334 }
335