PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.0.5.4
Adminify – White Label, Admin Menu Editor, Login Customizer v4.0.5.4
4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.1.17 All 164 releases
← All changes | Inc/Admin/Frames/Init.php +14 -149 4.2.264.0.5.4 View file →
@@ -1,10 +1,8 @@
1 1 <?php
2 2
3 -namespace PXLBSAdminify\Inc\Admin\Frames;
3 +namespace WPAdminify\Inc\Admin\Frames;
4 4
5 -use PXLBSAdminify\Inc\Utils;
6 -
7 5 // no direct access allowed
8 6 if (!defined('ABSPATH')) {
9 7 exit;
10 8 }
@@ -32,38 +30,17 @@
32 30
33 31 public function __construct()
34 32 {
35 33
36 - if ( ! Utils::is_admin_page_request() ) {
37 - return;
38 - }
39 -
40 34 if ( ! $this->is_allowed() ) {
41 - if ( Utils::is_iframe() || ! Utils::has_fetch_metadata() ) {
42 - $http_host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
43 - $request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
44 - $scheme = empty($_SERVER['HTTPS']) ? 'http' : 'https';
45 - $actual_link = $scheme . '://' . $http_host . $request_uri;
46 -
47 - if ( Utils::is_iframe() ) {
48 - Frames::custom_plugin_change_reload($actual_link);
49 - } else {
50 - // No Fetch Metadata to go by - let the browser decide
51 - // whether this really is the Adminify iframe.
52 - Frames::maybe_break_out_of_frame($actual_link);
53 - }
35 + if ( is_iframe() ) {
36 + $actual_link = (empty($_SERVER['HTTPS']) ? 'http' : 'https') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
37 + Frames::custom_plugin_change_reload($actual_link);
54 38 }
55 39 return;
56 40 }
57 41
58 - // Without Fetch Metadata a POST is treated as coming from the frame:
59 - // the shell template prints during `admin_init`, so rendering it for a
60 - // form submission sends output before WordPress can redirect and the
61 - // request dead-ends on a blank page. Submissions in a running Adminify
62 - // UI always originate inside the iframe anyway.
63 - $is_frame = Utils::is_iframe() || ( ! Utils::has_fetch_metadata() && ! Utils::is_get_request() );
64 -
65 - if ( $is_frame ) {
42 + if ( is_iframe() ) {
66 43 $this->frame = new Frames();
67 44 } else {
68 45 $this->admin = new Admin();
69 46 }
@@ -69,97 +46,8 @@
69 46 }
70 47
71 48 }
72 49
73 - /**
74 - * Get the relative admin path without subdirectory prefix
75 - * Handles root, subdirectory, subdomain, and multisite installations
76 - *
77 - * @return string Normalized path (e.g., /wp-admin/edit.php)
78 - */
79 - private function get_normalized_admin_path() {
80 - $php_self = isset($_SERVER['PHP_SELF']) ? sanitize_text_field(wp_unslash($_SERVER['PHP_SELF'])) : '';
81 -
82 - // Method 1: Use WordPress native function to get subdirectory path
83 - // site_url() returns full URL including subdirectory
84 - // e.g., https://example.com/blog or https://example.com
85 - $site_url_path = wp_parse_url( site_url(), PHP_URL_PATH );
86 -
87 - // Remove subdirectory prefix if exists
88 - if ( ! empty( $site_url_path ) && $site_url_path !== '/' ) {
89 - // Ensure path starts with subdirectory
90 - if ( strpos( $php_self, $site_url_path ) === 0 ) {
91 - $php_self = substr( $php_self, strlen( $site_url_path ) );
92 - }
93 - }
94 -
95 - // Ensure path starts with /
96 - if ( empty( $php_self ) || $php_self[0] !== '/' ) {
97 - $php_self = '/' . $php_self;
98 - }
99 -
100 - return $php_self;
101 - }
102 -
103 - /**
104 - * Check if current path matches the blocked URL pattern
105 - * Supports exact match and ends-with matching for subdirectory compatibility
106 - *
107 - * @param string $blocked_url The URL pattern to check against
108 - * @return bool True if current path matches the blocked URL
109 - */
110 - private function matches_blocked_url( $blocked_url ) {
111 - $current_path = $this->get_normalized_admin_path();
112 -
113 - // Exact match (normalized)
114 - if ( $current_path === $blocked_url ) {
115 - return true;
116 - }
117 -
118 - // Fallback: ends-with check for edge cases
119 - // e.g., /wp-admin/customize.php should match even if normalization fails
120 - $php_self = isset($_SERVER['PHP_SELF']) ? sanitize_text_field(wp_unslash($_SERVER['PHP_SELF'])) : '';
121 - if ( $this->url_ends_with( $php_self, $blocked_url ) ) {
122 - return true;
123 - }
124 -
125 - return false;
126 - }
127 -
128 - /**
129 - * Check if a URL ends with a specific path
130 - * Useful for subdirectory WordPress installs
131 - *
132 - * @param string $url Full URL or path to check
133 - * @param string $ending The ending pattern to match
134 - * @return bool
135 - */
136 - private function url_ends_with( $url, $ending ) {
137 - $ending_length = strlen( $ending );
138 - if ( $ending_length === 0 ) {
139 - return true;
140 - }
141 - return substr( $url, -$ending_length ) === $ending;
142 - }
143 -
144 - /**
145 - * Get WordPress installation context for debugging
146 - *
147 - * @return array Installation details
148 - */
149 - public function get_install_context() {
150 - return [
151 - 'is_multisite' => is_multisite(),
152 - 'is_subdomain' => defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL,
153 - 'site_url' => site_url(),
154 - 'home_url' => home_url(),
155 - 'admin_url' => admin_url(),
156 - 'subdirectory' => wp_parse_url( site_url(), PHP_URL_PATH ) ?: '/',
157 - 'php_self' => isset($_SERVER['PHP_SELF']) ? sanitize_text_field(wp_unslash($_SERVER['PHP_SELF'])) : '',
158 - 'normalized_path' => $this->get_normalized_admin_path(),
159 - ];
160 - }
161 -
162 50 public function is_allowed() {
163 51
164 52 $not_allowed_urls = Admin::get_not_allowed_urls();
165 53
@@ -166,39 +54,26 @@
166 54 foreach ( $not_allowed_urls as $url_object ) {
167 55 if ( is_string( $url_object ) ) {
168 56
169 57 $is_allowed = true; // Scoped Default allowed
170 - // Use normalized path matching for subdirectory compatibility
171 - if ( $this->matches_blocked_url( $url_object ) ) {
172 - $is_allowed = false; // not allowed
173 - }
58 + if ( $url_object === $_SERVER['PHP_SELF'] ) $is_allowed = false; // not allowed
174 59
175 60 } else {
176 61
177 62 $is_allowed = false; // Scoped Default not allowed
178 63
179 - // Use normalized path matching for subdirectory compatibility
180 - if ( $url_object['url'] !== '*' && ! $this->matches_blocked_url( $url_object['url'] ) ) {
181 - $is_allowed = true; // allowed
182 - }
183 -
64 + if ( $url_object['url'] !== '*' && $url_object['url'] !== $_SERVER['PHP_SELF'] ) $is_allowed = true; // allowed
184 65 if ( ! $is_allowed && array_key_exists( 'query_params', $url_object ) ) {
185 - if ( ! $this->check_query_params( $url_object['query_params'] ) ) {
186 - $is_allowed = true; // allowed
187 - }
66 + if ( ! $this->check_query_params( $url_object['query_params'] ) ) $is_allowed = true; // allowed
188 67 }
189 68
190 69 if ( ! $is_allowed && array_key_exists( 'post_type', $url_object ) ) {
191 - if ( ! $this->check_post_type( $url_object['post_type'] ) ) {
192 - $is_allowed = true; // allowed
193 - }
70 + if ( ! $this->check_post_type( $url_object['post_type'] ) ) $is_allowed = true; // allowed
194 71 }
195 72
196 73 }
197 74
198 - if ( ! $is_allowed ) {
199 - return $is_allowed;
200 - }
75 + if ( ! $is_allowed ) return $is_allowed;
201 76
202 77 }
203 78
204 79 return true;
@@ -208,10 +83,9 @@
208 83 function check_query_params($query_params) {
209 84 // Pattern 1: Both keys and their values should check in $_GET
210 85 if (array_keys($query_params) === $query_params) {
211 86 foreach ($query_params as $key => $value) {
212 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
213 - if (!isset($_GET[$key]) || sanitize_text_field(wp_unslash($_GET[$key])) != $value) {
87 + if (!isset($_GET[$key]) || $_GET[$key] != $value) {
214 88 return false; // Key doesn't exist or the value doesn't match
215 89 }
216 90 }
217 91 return true; // All keys and values match
@@ -221,12 +95,10 @@
221 95 if (array_values($query_params) === $query_params) {
222 96 foreach ($query_params as $param) {
223 97 if ( substr($param, -1) === '!' ) {
224 98 $param = substr($param, 0, -1);
225 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
226 99 if ( isset($_GET[$param]) ) return false; // The key exists in $_GET
227 100 } else {
228 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
229 101 if ( ! isset($_GET[$param]) ) return false; // The key doesn't exist in $_GET
230 102 }
231 103
232 104 }
@@ -238,18 +110,15 @@
238 110 if (is_numeric($key)) {
239 111 // For numeric keys, we're checking only existence (Pattern 1 behavior)
240 112 if ( substr($value, -1) === '!' ) {
241 113 $value = substr($value, 0, -1);
242 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
243 114 if ( isset($_GET[$value]) ) return false; // The key exists in $_GET
244 115 } else {
245 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
246 116 if ( ! isset($_GET[$value]) ) return false; // The key doesn't exist in $_GET
247 117 }
248 118 } else {
249 119 // For associative keys, we check for both key and value (Pattern 2 behavior)
250 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
251 - if (!isset($_GET[$key]) || sanitize_text_field(wp_unslash($_GET[$key])) != $value) {
120 + if (!isset($_GET[$key]) || $_GET[$key] != $value) {
252 121 return false; // Key doesn't exist or value doesn't match
253 122 }
254 123 }
255 124 }
@@ -257,16 +126,12 @@
257 126 return true; // All conditions are met
258 127 }
259 128
260 129 function check_post_type($post_types) {
261 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
262 130 if ( isset( $_GET['post_type'] ) ) {
263 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
264 - return in_array( sanitize_text_field( wp_unslash( $_GET['post_type'] ) ), $post_types );
265 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
131 + return in_array( $_GET['post_type'], $post_types );
266 132 } else if ( isset( $_GET['post'] ) ) {
267 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
268 - return in_array( get_post_type( absint( wp_unslash( $_GET['post'] ) ) ), $post_types );
133 + return in_array( get_post_type( $_GET['post'] ), $post_types );
269 134 }
270 135 return in_array( 'post', $post_types );
271 136 }
272 137