PluginProbe
Extendify / trunk
Extendify vtrunk
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.4 → trunk 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()`.