Skip to content

Commit 1b65a58

Browse files
committed
Do not cache requests with query string + whitelist
1 parent 6cd4c2d commit 1b65a58

File tree

1 file changed

+73
-17
lines changed

1 file changed

+73
-17
lines changed

tiny-nav-menu-cache.php

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,33 @@
22
/**
33
* Plugin Name: Tiny navigation menu cache (MU)
44
* Description: Cache nav menu's HTML content in persistent object cache.
5-
* Version: 0.1.3
5+
* Version: 0.2.0
66
* Constants: TINY_CACHE_NAV_MENU_EXCLUDES
77
*/
88

99
class Tiny_Nav_Menu_Cache {
1010

11-
const GROUP = 'navmenu';
11+
/**
12+
* @var string Name of the cache group.
13+
*/
14+
private const GROUP = 'navmenu';
15+
16+
/**
17+
* @var array List of whitelisted query string fields (these do not prevent cache write).
18+
*/
19+
private const WHITELISTED_QUERY_STRING_FIELDS = [
20+
// https://support.google.com/searchads/answer/7342044
21+
'gclid',
22+
'gclsrc',
23+
// https://www.facebook.com/business/help/330994334179410 "URL in ad can't contain Facebook Click ID" section
24+
'fbclid',
25+
// https://en.wikipedia.org/wiki/UTM_parameters
26+
'utm_campaign',
27+
'utm_content',
28+
'utm_medium',
29+
'utm_source',
30+
'utm_term',
31+
];
1232

1333
public function __construct() {
1434

@@ -40,32 +60,41 @@ public function init() {
4060
add_filter( 'wp_nav_menu', array( $this, 'save_nav_menu' ), PHP_INT_MAX, 2 );
4161
}
4262

43-
public function get_nav_menu( $nav_menu, $args ) {
63+
/**
64+
* @param string $nav_menu_html
65+
* @param object $args
66+
* @return string
67+
*/
68+
public function get_nav_menu( $nav_menu_html, $args ) {
4469

45-
$key = $this->get_cache_key( $args );
46-
// Check excluded nav menus
47-
if ( false !== $key ) {
70+
$enabled = $this->is_enabled( $args );
71+
if ( $enabled ) {
4872
$found = null;
49-
$cache = wp_cache_get( $key, self::GROUP, false, $found );
73+
$cache = wp_cache_get( $this->get_cache_key( $args ), self::GROUP, false, $found );
5074
if ( $found ) {
5175

5276
return $cache;
5377
}
5478
}
5579

56-
return $nav_menu;
80+
return $nav_menu_html;
5781
}
5882

59-
public function save_nav_menu( $nav_menu, $args ) {
60-
61-
$key = $this->get_cache_key( $args );
62-
// Check excluded nav menus
63-
if ( false !== $key ) {
64-
wp_cache_set( $key, $nav_menu, self::GROUP, DAY_IN_SECONDS );
83+
/**
84+
* @param string $nav_menu_html
85+
* @param object $args
86+
* @return string
87+
*/
88+
public function save_nav_menu( $nav_menu_html, $args ) {
89+
90+
$enabled = $this->is_enabled( $args );
91+
if ( $enabled ) {
92+
$key = $this->get_cache_key( $args );
93+
wp_cache_set( $key, $nav_menu_html, self::GROUP, DAY_IN_SECONDS );
6594
$this->remember_key( $key );
6695
}
6796

68-
return $nav_menu;
97+
return $nav_menu_html;
6998
}
7099

71100
public function flush_all() {
@@ -76,6 +105,9 @@ public function flush_all() {
76105
wp_cache_delete( 'key_list', self::GROUP );
77106
}
78107

108+
/**
109+
* @param string $key
110+
*/
79111
private function remember_key( $key ) {
80112

81113
// @TODO Not atomic
@@ -89,6 +121,9 @@ private function remember_key( $key ) {
89121
wp_cache_set( 'key_list', $key_list, self::GROUP, DAY_IN_SECONDS );
90122
}
91123

124+
/**
125+
* @return array
126+
*/
92127
private function get_all_keys() {
93128

94129
$found = null;
@@ -100,9 +135,15 @@ private function get_all_keys() {
100135
return explode( '|', $key_list );
101136
}
102137

103-
private function get_cache_key( $args ) {
138+
/**
139+
* Check excluded nav menus and the query string.
140+
*
141+
* @param object $args
142+
* @return bool
143+
*/
144+
private function is_enabled( $args ) {
104145

105-
// Excluded theme locations
146+
// Excluded theme locations.
106147
if ( defined( 'TINY_CACHE_NAV_MENU_EXCLUDES' ) && TINY_CACHE_NAV_MENU_EXCLUDES ) {
107148
$excludes = explode( '|', TINY_CACHE_NAV_MENU_EXCLUDES );
108149

@@ -114,6 +155,21 @@ private function get_cache_key( $args ) {
114155
}
115156
}
116157

158+
// Do not cache requests with query string except whitelisted ones.
159+
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
160+
if ( [] !== array_diff( array_keys( $_GET ), self::WHITELISTED_QUERY_STRING_FIELDS ) ) {
161+
return false;
162+
}
163+
164+
return true;
165+
}
166+
167+
/**
168+
* @param object $args
169+
* @return string
170+
*/
171+
private function get_cache_key( $args ) {
172+
117173
$request_uri = isset( $_SERVER['REQUEST_URI'] )
118174
? $_SERVER['REQUEST_URI']
119175
: ''; // WPCS: sanitization, input var OK.

0 commit comments

Comments
 (0)