PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | app/AdminPageRouter.php +111 -44 3.0.43.2.1 View file →
@@ -29,8 +29,9 @@
29 29 {
30 30 // This does the initial redirect to Launch.
31 31 \add_action('admin_init', [$this, 'redirectOnce'], 10);
32 32 \add_action('admin_init', [$this, 'maybeForceFlush'], 5);
33 + \add_action('admin_init', [$this, 'handleLaunchRedirect'], 1);
33 34
34 35 // Add a dropdown above Dashboard in the admin toolbar.
35 36 \add_action('admin_bar_menu', function ($wpAdminBar) {
36 37 if (!PartnerData::$id || is_admin()) {
@@ -175,10 +176,49 @@
175 176 return 'admin.php?page=extendify-assist';
176 177 }
177 178
178 179 /**
180 + * Routes /wp-admin/?launch-redirect based on Launch and Agent state.
181 + *
182 + * @return void
183 + */
184 + public function handleLaunchRedirect()
185 + {
186 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
187 + if (!isset($_GET['launch-redirect']) || \wp_doing_ajax() || !PartnerData::$id) {
188 + return;
189 + }
190 +
191 + // If launch hasn't yet completed, they go to launch/auto-launch
192 + if (!Config::$launchCompleted) {
193 + $useAgentOnboarding = PartnerData::setting('useAgentOnboarding') ||
194 + Config::preview('agent-onboarding') ||
195 + constant('EXTENDIFY_DEVMODE');
196 + $page = $useAgentOnboarding ? 'extendify-auto-launch' : 'extendify-launch';
197 + $query_params = $this->presentLaunchParams(['page' => $page]);
198 + \wp_safe_redirect(\add_query_arg($query_params, \admin_url('admin.php')));
199 + exit;
200 + }
201 +
202 + // If they have the Agent onboarding enabled, redirect to home.
203 + if (PartnerData::setting('showAIAgents')) {
204 + \wp_safe_redirect(\add_query_arg(
205 + ['extendify-open-agent' => '1'],
206 + \home_url('/')
207 + ));
208 + exit;
209 + }
210 +
211 + // Otherwise, they go to Assist.
212 + \wp_safe_redirect(\admin_url() . $this->getRoute());
213 + exit;
214 + }
215 +
216 + /**
179 217 * Redirect once to Launch, only once (at least once) when
180 218 * the email matches the entry in WP Admin > Settings > General.
219 + * Requests carrying a build-id keep redirecting until onboarding
220 + * completes.
181 221 *
182 222 * @return void
183 223 */
184 224 public function redirectOnce()
@@ -190,12 +230,21 @@
190 230 if (defined('EXTENDIFY_IS_THEME_EXTENDABLE') && !EXTENDIFY_IS_THEME_EXTENDABLE) {
191 231 return;
192 232 }
193 233
194 - if (\get_option('extendify_launch_loaded', false) || !Config::$showLaunch) {
234 + // Partner preview links must work on every admin visit, not just the first.
235 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
236 + $buildIdRedirect = !empty(sanitize_text_field(wp_unslash($_GET['build-id'] ?? '')))
237 + && !Config::$launchCompleted;
238 +
239 + if (!$buildIdRedirect && \get_option('extendify_launch_loaded', false)) {
195 240 return;
196 241 }
197 242
243 + if (!Config::$showLaunch) {
244 + return;
245 + }
246 +
198 247 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
199 248 if (isset($_GET['page']) && $_GET['page'] === 'extendify-auto-launch') {
200 249 return;
201 250 }
@@ -206,19 +255,27 @@
206 255 $agentOnboarding = PartnerData::setting('useAgentOnboarding') ||
207 256 Config::preview('agent-onboarding') ||
208 257 constant('EXTENDIFY_DEVMODE');
209 258 if ($agentOnboarding) {
210 - // If they landed on launch but have the Agent onboarding enabled, redirect to auto-launch.
211 - $redirect_url = \add_query_arg(
212 - ['page' => 'extendify-auto-launch'],
213 - \admin_url('admin.php')
214 - );
215 - \wp_safe_redirect($redirect_url);
259 + // If they landed on launch but have the Agent onboarding enabled, redirect to
260 + // auto-launch — carrying their deep-link params, which a bare page-only redirect drops.
261 + $query_params = $this->presentLaunchParams(['page' => 'extendify-auto-launch']);
262 + \wp_safe_redirect(\add_query_arg($query_params, \admin_url('admin.php')));
216 263 exit;
217 264 }
218 265 return;
219 266 }
220 267
268 + if ($buildIdRedirect) {
269 + \update_option('permalink_structure', '/%postname%/');
270 + \update_option('extendify_needs_rewrite_flush', true);
271 +
272 + // Only AutoLaunch consumes build-id.
273 + $query_params = $this->presentLaunchParams(['page' => 'extendify-auto-launch']);
274 + \wp_safe_redirect(\add_query_arg($query_params, \admin_url('admin.php')));
275 + exit;
276 + }
277 +
221 278 $user = \wp_get_current_user();
222 279 if (
223 280 $user
224 281 // Check the main admin email, and they have an admin role.
@@ -237,52 +294,62 @@
237 294 // Update permalink structure to postname when auto-redirecting to Launch
238 295 \update_option('permalink_structure', '/%postname%/');
239 296 \update_option('extendify_needs_rewrite_flush', true);
240 297
241 - $allowed_launch_params = [
242 - 'objective',
243 - 'title',
244 - 'description',
245 - 'structure',
246 - 'tone',
247 - 'skip',
248 - // new for autolaunch (some duplicated)
249 - 'type',
250 - 'title',
251 - 'description',
252 - 'objective',
253 - 'category',
254 - 'structure',
255 - 'tone',
256 - 'products',
257 - 'appointments',
258 - 'events',
259 - 'donations',
260 - 'multilingual',
261 - 'contact',
262 - 'address',
263 - 'blog',
264 - 'landing-page',
265 - 'cta-link',
266 - 'build-id',
267 - 'go',
268 - ];
269 298 // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
270 299 $autoLaunch = isset($_GET['auto-launch']) && filter_var($_GET['auto-launch'], FILTER_VALIDATE_BOOLEAN);
271 - $query_params = ['page' => $autoLaunch ? 'extendify-auto-launch' : 'extendify-launch'];
300 + $query_params = $this->presentLaunchParams([
301 + 'page' => $autoLaunch ? 'extendify-auto-launch' : 'extendify-launch',
302 + ]);
272 303
273 - foreach ($allowed_launch_params as $param) {
274 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
275 - $value = sanitize_text_field(wp_unslash($_GET[$param] ?? ''));
276 - if (!empty($value)) {
277 - $query_params[$param] = $value;
278 - }
279 - }
280 -
281 304 $redirect_url = \add_query_arg($query_params, \admin_url('admin.php'));
282 305 \wp_safe_redirect($redirect_url);
283 306 exit;
284 307 }
308 + }
309 +
310 + /**
311 + * Merges the allowlisted launch deep-link params present in the request onto
312 + * $base, so a redirect into Launch/AutoLaunch carries the partner's params
313 + * through instead of dropping them.
314 + *
315 + * @param array $base Seed query args (typically the destination `page`).
316 + * @return array
317 + */
318 + private function presentLaunchParams(array $base)
319 + {
320 + $allowed = [
321 + 'objective',
322 + 'title',
323 + 'description',
324 + 'structure',
325 + 'tone',
326 + 'skip',
327 + 'type',
328 + 'category',
329 + 'products',
330 + 'appointments',
331 + 'events',
332 + 'donations',
333 + 'multilingual',
334 + 'contact',
335 + 'address',
336 + 'blog',
337 + 'landing-page',
338 + 'cta-link',
339 + 'build-id',
340 + 'go',
341 + ];
342 +
343 + foreach ($allowed as $param) {
344 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
345 + $value = sanitize_text_field(wp_unslash($_GET[$param] ?? ''));
346 + if (!empty($value)) {
347 + $base[$param] = $value;
348 + }
349 + }
350 +
351 + return $base;
285 352 }
286 353
287 354 /**
288 355 * Flushes WordPress rewrite rules if previously scheduled by `redirectOnce()`.