← All changes
|
jetpack_vendor/automattic/jetpack-forms/src/dashboard/class-dashboard.php
+131
-222
16.2
→
16.3-beta
View file →
| @@ -7,9 +7,8 @@ | ||
| 7 | 7 | |
| 8 | 8 | namespace Automattic\Jetpack\Forms\Dashboard; |
| 9 | 9 | |
| 10 | 10 | use Automattic\Jetpack\Admin_UI\Admin_Menu; |
| 11 | -use Automattic\Jetpack\Assets; | |
| 12 | 11 | use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State; |
| 13 | 12 | use Automattic\Jetpack\Forms\ContactForm\Contact_Form; |
| 14 | 13 | use Automattic\Jetpack\Forms\ContactForm\Contact_Form_Plugin; |
| 15 | 14 | use Automattic\Jetpack\Tracking; |
| @@ -57,14 +56,10 @@ | ||
| 57 | 56 | // When no route path is specified, redirect to the default view |
| 58 | 57 | // so the client-side router doesn't need a catch-all root route. |
| 59 | 58 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 60 | 59 | if ( ! isset( $_GET['p'] ) ) { |
| 61 | - $default_tab = Contact_Form_Plugin::has_editor_feature_flag( 'central-form-management' ) | |
| 62 | - ? 'forms' | |
| 63 | - : 'inbox'; | |
| 60 | + wp_safe_redirect( self::get_forms_admin_url( self::get_default_tab() ) ); | |
| 64 | 61 | |
| 65 | - wp_safe_redirect( self::get_forms_admin_url( $default_tab ) ); | |
| 66 | - | |
| 67 | 62 | exit; |
| 68 | 63 | } |
| 69 | 64 | |
| 70 | 65 | // Register polyfills for WP < 7.0 (must run before enqueue). |
| @@ -99,8 +94,9 @@ | ||
| 99 | 94 | /** |
| 100 | 95 | * Script handle for the JS file we enqueue in the Feedback admin page. |
| 101 | 96 | * |
| 102 | 97 | * @var string |
| 98 | + * @deprecated 8.2.0 The legacy dashboard bundle was removed. | |
| 103 | 99 | */ |
| 104 | 100 | const SCRIPT_HANDLE = 'jp-forms-dashboard'; |
| 105 | 101 | |
| 106 | 102 | const ADMIN_SLUG = 'jetpack-forms-admin'; |
| @@ -114,8 +110,24 @@ | ||
| 114 | 110 | */ |
| 115 | 111 | const FORMS_WPBUILD_ADMIN_SLUG = 'jetpack-forms-responses-wp-admin'; |
| 116 | 112 | |
| 117 | 113 | /** |
| 114 | + * Cookie holding the top tab the user last chose. | |
| 115 | + * | |
| 116 | + * Written by src/dashboard/last-tab-cookie.ts; the two names have to stay in step. | |
| 117 | + */ | |
| 118 | + const LAST_TAB_COOKIE = 'jetpack_forms_last_tab'; | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Top tabs the dashboard can reopen on. | |
| 122 | + * | |
| 123 | + * Mirrored by TOP_TABS in src/dashboard/constants.ts. | |
| 124 | + * | |
| 125 | + * @var string[] | |
| 126 | + */ | |
| 127 | + private const TOP_TABS = array( 'forms', 'responses' ); | |
| 128 | + | |
| 129 | + /** | |
| 118 | 130 | * Priority for the dashboard menu. |
| 119 | 131 | * Needs to be high enough for us to be able to unregister the default edit.php menu item. |
| 120 | 132 | * |
| 121 | 133 | * @var int |
| @@ -127,108 +139,65 @@ | ||
| 127 | 139 | */ |
| 128 | 140 | public function init() { |
| 129 | 141 | add_action( 'admin_menu', array( $this, 'add_admin_submenu' ), self::MENU_PRIORITY ); |
| 130 | 142 | add_action( 'admin_menu', array( __CLASS__, 'redirect_dashboard_url_cross_variant' ), 1 ); |
| 143 | + add_action( 'admin_notices', array( __CLASS__, 'announce_retired_filter' ) ); | |
| 131 | 144 | |
| 132 | - /** | |
| 133 | - * Filter to enable or disable the wp-build-based Forms dashboard. | |
| 134 | - * | |
| 135 | - * Enabled by default since Central Forms Management is now available for all sites. | |
| 136 | - * Can be disabled by returning false from this filter. | |
| 137 | - * | |
| 138 | - * @since 7.18.0 | |
| 139 | - * | |
| 140 | - * @param bool $enabled Whether the wp-build dashboard is enabled. Default true. | |
| 141 | - */ | |
| 142 | - $is_wp_build_enabled = apply_filters( 'jetpack_forms_alpha', true ); | |
| 145 | + self::load_wp_build(); | |
| 143 | 146 | |
| 144 | - if ( $is_wp_build_enabled ) { | |
| 145 | - self::load_wp_build(); | |
| 146 | - } | |
| 147 | - | |
| 148 | 147 | add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_scripts' ) ); |
| 148 | + } | |
| 149 | 149 | |
| 150 | - // Removed all admin notices on the Jetpack Forms admin page. | |
| 151 | - if ( self::get_admin_query_page() === self::ADMIN_SLUG ) { | |
| 152 | - remove_all_actions( 'admin_notices' ); | |
| 150 | + /** | |
| 151 | + * Tell anyone still filtering `jetpack_forms_alpha` that it no longer does anything. | |
| 152 | + * | |
| 153 | + * The filter gated the wp-build dashboard while it was in development. That dashboard | |
| 154 | + * is now the only one, so a `false` return has nothing left to select and is ignored. | |
| 155 | + * | |
| 156 | + * Announced rather than applied: _deprecated_hook() reports the hook without honoring | |
| 157 | + * it, where apply_filters_deprecated() would return a `false` this code can no longer | |
| 158 | + * act on. Guarded by has_filter() so sites that never used it stay silent. | |
| 159 | + * | |
| 160 | + * Hooked to `admin_notices` rather than called from init(). This class loads at | |
| 161 | + * `after_setup_theme` priority -2, so with WP_DEBUG display on the notice would print | |
| 162 | + * — and send headers — before load_wp_build() and redirect_dashboard_url_cross_variant() | |
| 163 | + * get to redirect, leaving both on "headers already sent" and a blank page. | |
| 164 | + * | |
| 165 | + * That hook also fires only while an admin screen renders, so the notice stays out of | |
| 166 | + * admin-ajax and admin-post responses, which `is_admin()` would have let through. And | |
| 167 | + * it runs late enough that has_filter() sees callbacks registered on `init`, not just | |
| 168 | + * those added at file scope. | |
| 169 | + * | |
| 170 | + * @since 8.1.0 | |
| 171 | + */ | |
| 172 | + public static function announce_retired_filter() { | |
| 173 | + if ( ! has_filter( 'jetpack_forms_alpha' ) ) { | |
| 174 | + return; | |
| 153 | 175 | } |
| 176 | + | |
| 177 | + // Kept on one line: replace-next-version-tag.sh only recognizes the token in a | |
| 178 | + // single-line deprecation call, and errors the build out otherwise. | |
| 179 | + _deprecated_hook( 'jetpack_forms_alpha', 'jetpack-forms-8.1.0', '', 'The legacy Forms dashboard has been removed, so this filter no longer selects anything.' ); | |
| 154 | 180 | } |
| 155 | 181 | |
| 156 | 182 | /** |
| 157 | - * Redirect dashboard URLs when the wp-build flag has changed since the link was generated. | |
| 183 | + * Send legacy dashboard URLs to the wp-build dashboard. | |
| 158 | 184 | * |
| 159 | - * Email links may point to the legacy or wp-build dashboard. If the flag has toggled, | |
| 160 | - * the requested page may not exist. This redirects to the correct variant. | |
| 185 | + * Load-bearing, not a courtesy for stale links: Creative Mail's JITMs and post-install | |
| 186 | + * redirect, and My Jetpack's fallback URL, still emit the legacy slug today. Keep it. | |
| 161 | 187 | */ |
| 162 | 188 | public static function redirect_dashboard_url_cross_variant() { |
| 163 | 189 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 164 | 190 | $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; |
| 165 | 191 | |
| 166 | - if ( $page !== self::ADMIN_SLUG && $page !== self::FORMS_WPBUILD_ADMIN_SLUG ) { | |
| 192 | + if ( $page !== self::ADMIN_SLUG ) { | |
| 167 | 193 | return; |
| 168 | 194 | } |
| 169 | 195 | |
| 170 | - /** This filter is documented in class-dashboard.php::init */ | |
| 171 | - $is_wp_build_enabled = apply_filters( 'jetpack_forms_alpha', true ); | |
| 172 | - | |
| 173 | - // Legacy URL requested but wp-build is now active → redirect to wp-build. | |
| 174 | - if ( $page === self::ADMIN_SLUG && $is_wp_build_enabled ) { | |
| 175 | - // The hash is never sent to the server. "inbox" used as default tab so we end up specifically in the responses | |
| 176 | - // route, where the client-side router will handle the redirect to the correct status in its beforeLoad hook. | |
| 177 | - $redirect = self::get_forms_admin_url( 'inbox' ); | |
| 178 | - wp_safe_redirect( $redirect ); | |
| 179 | - exit; | |
| 180 | - } | |
| 181 | - | |
| 182 | - // WP-Build URL requested but legacy is now active → redirect to legacy. | |
| 183 | - if ( $page === self::FORMS_WPBUILD_ADMIN_SLUG && ! $is_wp_build_enabled ) { | |
| 184 | - // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 185 | - $p = isset( $_GET['p'] ) ? rawurldecode( sanitize_text_field( wp_unslash( $_GET['p'] ) ) ) : ''; | |
| 186 | - $tab = 'inbox'; | |
| 187 | - $post_id = null; | |
| 188 | - $has_mark_as_spam = false; | |
| 189 | - | |
| 190 | - // Check if mark_as_spam is a separate query parameter (old email format). | |
| 191 | - // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 192 | - if ( isset( $_GET['mark_as_spam'] ) ) { | |
| 193 | - $has_mark_as_spam = true; | |
| 194 | - } | |
| 195 | - | |
| 196 | - if ( $p !== '' ) { | |
| 197 | - // Parse path like /responses/inbox?responseIds=["2879"] or /responses/inbox?responseIds=["2879"]&mark_as_spam or /forms. | |
| 198 | - if ( preg_match( '#^/responses/(inbox|spam|trash)(?:\?responseIds=\["(\d+)"\])?(.*)$#', $p, $m ) ) { | |
| 199 | - $tab = $m[1]; | |
| 200 | - $post_id = ! empty( $m[2] ) ? absint( $m[2] ) : null; | |
| 201 | - | |
| 202 | - // Check if mark_as_spam parameter is present inside the path. | |
| 203 | - if ( ! empty( $m[3] ) && strpos( $m[3], 'mark_as_spam' ) !== false ) { | |
| 204 | - $has_mark_as_spam = true; | |
| 205 | - } | |
| 206 | - } elseif ( preg_match( '#^/response/(\d+)(?:\?(.*))?$#', $p, $m ) ) { | |
| 207 | - // Standalone single response page (wp-build only) — the legacy | |
| 208 | - // dashboard shows the response in the inbox list instead. The path | |
| 209 | - // is matched whole so trailing junk isn't read as a response ID, | |
| 210 | - // but it may legitimately carry the email's mark_as_spam trigger. | |
| 211 | - $post_id = absint( $m[1] ); | |
| 212 | - | |
| 213 | - if ( ! empty( $m[2] ) && strpos( $m[2], 'mark_as_spam' ) !== false ) { | |
| 214 | - $has_mark_as_spam = true; | |
| 215 | - } | |
| 216 | - } elseif ( preg_match( '#^/forms#', $p ) ) { | |
| 217 | - $tab = 'forms'; | |
| 218 | - } | |
| 219 | - } | |
| 220 | - | |
| 221 | - $redirect = self::get_forms_admin_url( $tab, $post_id ); | |
| 222 | - | |
| 223 | - // Add mark_as_spam parameter if it was present in the original URL (either format). | |
| 224 | - if ( $has_mark_as_spam ) { | |
| 225 | - $redirect .= '&mark_as_spam'; | |
| 226 | - } | |
| 227 | - | |
| 228 | - wp_safe_redirect( $redirect ); | |
| 229 | - exit; | |
| 230 | - } | |
| 196 | + // The hash is never sent to the server. "inbox" used as default tab so we end up specifically in the responses | |
| 197 | + // route, where the client-side router will handle the redirect to the correct status in its beforeLoad hook. | |
| 198 | + wp_safe_redirect( self::get_forms_admin_url( 'inbox' ) ); | |
| 199 | + exit; | |
| 231 | 200 | } |
| 232 | 201 | |
| 233 | 202 | /** |
| 234 | 203 | * Get the current query 'page' parameter. |
| @@ -247,38 +216,19 @@ | ||
| 247 | 216 | if ( ! self::is_jetpack_forms_admin_page() ) { |
| 248 | 217 | return; |
| 249 | 218 | } |
| 250 | 219 | |
| 251 | - // The wp-build (script-module) dashboard renders its own UI from build/pages/…, | |
| 252 | - // so the legacy SPA bundle is dead weight there. Only enqueue it on the legacy | |
| 253 | - // dashboard. The shared inline data below (connection initial state + REST | |
| 254 | - // preload) is instead attached to the always-present wp-api-fetch handle so the | |
| 255 | - // wp-build app still receives it. | |
| 256 | - if ( self::is_wp_build_dashboard_page() ) { | |
| 257 | - $inline_handle = 'wp-api-fetch'; | |
| 258 | - $preload_position = 'after'; | |
| 220 | + // Attach the shared inline data (connection initial state + REST preload) to | |
| 221 | + // wp-api-fetch, which is always on the page. | |
| 222 | + $inline_handle = 'wp-api-fetch'; | |
| 223 | + $preload_position = 'after'; | |
| 259 | 224 | |
| 260 | - // The i18n loader is registered on every admin page by jetpack-assets but | |
| 261 | - // only enqueued when depended on; the esbuild bundles don't pull it in. | |
| 262 | - // Enqueue it so the wp-build dashboard's init module can download its JS | |
| 263 | - // translation catalogs. | |
| 264 | - if ( wp_script_is( 'wp-jp-i18n-loader', 'registered' ) ) { | |
| 265 | - wp_enqueue_script( 'wp-jp-i18n-loader' ); | |
| 266 | - } | |
| 267 | - } else { | |
| 268 | - $inline_handle = self::SCRIPT_HANDLE; | |
| 269 | - $preload_position = 'before'; | |
| 270 | - | |
| 271 | - Assets::register_script( | |
| 272 | - self::SCRIPT_HANDLE, | |
| 273 | - '../../dist/dashboard/jetpack-forms-dashboard.js', | |
| 274 | - __FILE__, | |
| 275 | - array( | |
| 276 | - 'in_footer' => true, | |
| 277 | - 'textdomain' => 'jetpack-forms', | |
| 278 | - 'enqueue' => true, | |
| 279 | - ) | |
| 280 | - ); | |
| 225 | + // The i18n loader is registered on every admin page by jetpack-assets but | |
| 226 | + // only enqueued when depended on; the esbuild bundles don't pull it in. | |
| 227 | + // Enqueue it so the wp-build dashboard's init module can download its JS | |
| 228 | + // translation catalogs. | |
| 229 | + if ( wp_script_is( 'wp-jp-i18n-loader', 'registered' ) ) { | |
| 230 | + wp_enqueue_script( 'wp-jp-i18n-loader' ); | |
| 281 | 231 | } |
| 282 | 232 | |
| 283 | 233 | if ( Contact_Form_Plugin::can_use_analytics() ) { |
| 284 | 234 | Tracking::register_tracks_functions_scripts( true ); |
| @@ -362,20 +312,14 @@ | ||
| 362 | 312 | ); |
| 363 | 313 | } |
| 364 | 314 | |
| 365 | 315 | /** |
| 366 | - * Whether the current request targets the wp-build (script-module) Forms dashboard, | |
| 367 | - * as opposed to the legacy SPA dashboard. | |
| 316 | + * Whether the current request targets the Forms dashboard page. | |
| 368 | 317 | * |
| 369 | - * When true, the legacy dashboard bundle should not be enqueued: the wp-build page | |
| 370 | - * (build/pages/jetpack-forms-responses/…) provides its own UI and asset loading. | |
| 371 | - * | |
| 372 | 318 | * @return bool |
| 373 | 319 | */ |
| 374 | 320 | public static function is_wp_build_dashboard_page() { |
| 375 | - /** This filter is documented in class-dashboard.php::init */ | |
| 376 | - return apply_filters( 'jetpack_forms_alpha', true ) | |
| 377 | - && self::get_admin_query_page() === self::FORMS_WPBUILD_ADMIN_SLUG; | |
| 321 | + return self::get_admin_query_page() === self::FORMS_WPBUILD_ADMIN_SLUG; | |
| 378 | 322 | } |
| 379 | 323 | |
| 380 | 324 | /** |
| 381 | 325 | * Register the dashboard admin submenu Forms under Jetpack menu. |
| @@ -380,59 +324,56 @@ | ||
| 380 | 324 | /** |
| 381 | 325 | * Register the dashboard admin submenu Forms under Jetpack menu. |
| 382 | 326 | */ |
| 383 | 327 | public function add_admin_submenu() { |
| 384 | - | |
| 385 | - /** This filter is documented in class-dashboard.php::init */ | |
| 386 | - if ( apply_filters( 'jetpack_forms_alpha', true ) ) { | |
| 387 | - | |
| 388 | - // Report a missing build here rather than only on the page itself, so a partial | |
| 389 | - // deploy shows up on the first admin request instead of waiting for someone to | |
| 390 | - // open Forms. Keyed on the file and not on the generated callback: load_wp_build() | |
| 391 | - // only requires build.php on the Forms page, so the callback is legitimately | |
| 392 | - // absent on every other admin screen, which runs this method too. | |
| 393 | - if ( ! file_exists( self::wp_build_index_path() ) ) { | |
| 394 | - _doing_it_wrong( | |
| 395 | - __METHOD__, | |
| 396 | - 'The Jetpack Forms build output is missing: build/build.php is absent, so the dashboard has nothing to render. The package build did not run for this deploy.', | |
| 397 | - '' | |
| 398 | - ); | |
| 399 | - } | |
| 400 | - | |
| 401 | - // `jetpack_forms_jetpack_forms_responses_wp_admin_render_page` is the callback generated | |
| 402 | - // by the WP build script, named after the page slug. It only exists once `build/build.php` | |
| 403 | - // is loaded. Without it the page has nothing to render, so show an explanation rather | |
| 404 | - // than the legacy mount point, whose bundle load_admin_scripts() does not enqueue here. | |
| 405 | - $callback = function_exists( 'jetpack_forms_jetpack_forms_responses_wp_admin_render_page' ) | |
| 406 | - ? 'jetpack_forms_jetpack_forms_responses_wp_admin_render_page' | |
| 407 | - : array( $this, 'render_wp_build_unavailable' ); | |
| 408 | - | |
| 409 | - Admin_Menu::add_menu( | |
| 410 | - /** "Jetpack Forms" and "Forms" are product names, do not translate. */ | |
| 411 | - 'Jetpack Forms', | |
| 412 | - 'Forms', | |
| 413 | - 'edit_pages', | |
| 414 | - self::FORMS_WPBUILD_ADMIN_SLUG, | |
| 415 | - $callback | |
| 328 | + // Report a missing build here rather than only on the page itself, so a partial | |
| 329 | + // deploy shows up on the first admin request instead of waiting for someone to | |
| 330 | + // open Forms. Keyed on the file and not on the generated callback: load_wp_build() | |
| 331 | + // only requires build.php on the Forms page, so the callback is legitimately | |
| 332 | + // absent on every other admin screen, which runs this method too. | |
| 333 | + if ( ! file_exists( self::wp_build_index_path() ) ) { | |
| 334 | + _doing_it_wrong( | |
| 335 | + __METHOD__, | |
| 336 | + 'The Jetpack Forms build output is missing: build/build.php is absent, so the dashboard has nothing to render. The package build did not run for this deploy.', | |
| 337 | + '' | |
| 416 | 338 | ); |
| 339 | + } | |
| 417 | 340 | |
| 418 | - return; | |
| 419 | - } | |
| 341 | + // `jetpack_forms_jetpack_forms_responses_wp_admin_render_page` is the callback generated | |
| 342 | + // by the WP build script, named after the page slug. It only exists once `build/build.php` | |
| 343 | + // is loaded. Without it the page has nothing to render, so show an explanation. | |
| 344 | + $callback = function_exists( 'jetpack_forms_jetpack_forms_responses_wp_admin_render_page' ) | |
| 345 | + ? 'jetpack_forms_jetpack_forms_responses_wp_admin_render_page' | |
| 346 | + : array( $this, 'render_wp_build_unavailable' ); | |
| 420 | 347 | |
| 421 | 348 | Admin_Menu::add_menu( |
| 422 | - /** "Jetpack Forms" and "Forms" are Product names, do not translate. */ | |
| 349 | + /** "Jetpack Forms" and "Forms" are product names, do not translate. */ | |
| 423 | 350 | 'Jetpack Forms', |
| 424 | 351 | 'Forms', |
| 425 | 352 | 'edit_pages', |
| 426 | - self::ADMIN_SLUG, | |
| 427 | - array( $this, 'render_dashboard' ) | |
| 353 | + self::FORMS_WPBUILD_ADMIN_SLUG, | |
| 354 | + $callback, | |
| 355 | + null, | |
| 356 | + // The key is not the slug: the page's URL still reads | |
| 357 | + // jetpack-forms-responses-wp-admin, which FORMS-795 tracks separately. | |
| 358 | + array( | |
| 359 | + 'product' => 'jetpack-forms', | |
| 360 | + 'key' => 'jetpack-forms', | |
| 361 | + ) | |
| 428 | 362 | ); |
| 429 | 363 | } |
| 430 | 364 | |
| 431 | 365 | /** |
| 432 | - * Render the dashboard. | |
| 366 | + * Render the legacy dashboard mount point. | |
| 367 | + * | |
| 368 | + * Nothing registers this any more — the legacy dashboard was retired and its bundle | |
| 369 | + * is no longer enqueued, so the container it prints stays empty. Kept, and left | |
| 370 | + * printing the same markup, so any caller outside this package behaves as before. | |
| 371 | + * | |
| 372 | + * @deprecated 8.1.0 The legacy dashboard was retired. | |
| 433 | 373 | */ |
| 434 | 374 | public function render_dashboard() { |
| 375 | + _deprecated_function( __METHOD__, 'jetpack-forms-8.1.0' ); | |
| 435 | 376 | ?> |
| 436 | 377 | <div id="jp-forms-dashboard"></div> |
| 437 | 378 | <?php |
| 438 | 379 | } |
| @@ -442,9 +383,8 @@ | ||
| 442 | 383 | * |
| 443 | 384 | * The wp-build dashboard renders through a callback generated into `build/build.php`. |
| 444 | 385 | * That file is missing when the package ships without a complete build, and it is |
| 445 | 386 | * never loaded when a host application filters `jetpack_forms_load_wp_build` to false. |
| 446 | - * The legacy bundle is no fallback here: load_admin_scripts() skips it on this screen. | |
| 447 | 387 | * So report the problem instead of rendering a blank page. |
| 448 | 388 | * |
| 449 | 389 | * @since 7.25.0 |
| 450 | 390 | */ |
| @@ -605,27 +545,12 @@ | ||
| 605 | 545 | * |
| 606 | 546 | * @return string |
| 607 | 547 | */ |
| 608 | 548 | public static function get_forms_admin_url( $tab = null, $post_id = null ) { |
| 609 | - /** This filter is documented in class-dashboard.php::init */ | |
| 610 | - $is_wp_build_enabled = apply_filters( 'jetpack_forms_alpha', true ); | |
| 611 | - $url = admin_url( 'admin.php' ); | |
| 549 | + $url = admin_url( 'admin.php' ); | |
| 550 | + $url .= '?page=' . self::FORMS_WPBUILD_ADMIN_SLUG; | |
| 551 | + $url .= '&p=' . rawurlencode( self::get_forms_admin_path_wp_build( $tab, $post_id ) ); | |
| 612 | 552 | |
| 613 | - $url .= $is_wp_build_enabled | |
| 614 | - ? '?page=' . self::FORMS_WPBUILD_ADMIN_SLUG | |
| 615 | - : '?page=' . self::ADMIN_SLUG; | |
| 616 | - | |
| 617 | - if ( $is_wp_build_enabled ) { | |
| 618 | - $path = self::get_forms_admin_path_wp_build( $tab, $post_id ); | |
| 619 | - $url .= '&p=' . rawurlencode( $path ); | |
| 620 | - } else { | |
| 621 | - $suffix = self::get_forms_admin_suffix_legacy( $tab, $post_id ); | |
| 622 | - | |
| 623 | - if ( $suffix !== '' ) { | |
| 624 | - $url .= $suffix; | |
| 625 | - } | |
| 626 | - } | |
| 627 | - | |
| 628 | 553 | /** |
| 629 | 554 | * Filters the Forms admin page URL. |
| 630 | 555 | * |
| 631 | 556 | * @module contact-form |
| @@ -642,11 +567,10 @@ | ||
| 642 | 567 | |
| 643 | 568 | /** |
| 644 | 569 | * Returns the URL of the standalone single response page for a given response. |
| 645 | 570 | * |
| 646 | - * The standalone page is a wp-build route (`/response/<id>`). The legacy | |
| 647 | - * dashboard has no equivalent, so it falls back to the responses list with the | |
| 648 | - * response selected — as does a missing/empty post ID. | |
| 571 | + * The standalone page is a wp-build route (`/response/<id>`). A missing or empty | |
| 572 | + * post ID falls back to the responses list. | |
| 649 | 573 | * |
| 650 | 574 | * @since 7.25.0 |
| 651 | 575 | * |
| 652 | 576 | * @param int|null $post_id Post ID of the response to open. |
| @@ -655,15 +579,31 @@ | ||
| 655 | 579 | */ |
| 656 | 580 | public static function get_single_response_admin_url( $post_id = null ) { |
| 657 | 581 | $post_id = ! empty( $post_id ) ? absint( $post_id ) : null; |
| 658 | 582 | |
| 659 | - // `get_forms_admin_url()` owns the URL scheme for both dashboards. The | |
| 660 | - // 'response' tab resolves to the standalone page on wp-build, and falls | |
| 661 | - // through to the responses list on legacy, which has no such route. | |
| 662 | 583 | return self::get_forms_admin_url( $post_id ? 'response' : 'inbox', $post_id ); |
| 663 | 584 | } |
| 664 | 585 | |
| 665 | 586 | /** |
| 587 | + * The tab the standalone Forms page opens on when the URL names no route. | |
| 588 | + * | |
| 589 | + * A cookie, not a user preference: this redirect runs before any script could read one. | |
| 590 | + * | |
| 591 | + * @return string Tab slug understood by get_forms_admin_url(). | |
| 592 | + */ | |
| 593 | + public static function get_default_tab() { | |
| 594 | + if ( ! Contact_Form_Plugin::has_editor_feature_flag( 'central-form-management' ) ) { | |
| 595 | + // The Forms tab is not rendered at all here, so honouring a stored 'forms' | |
| 596 | + // would strand the user on a tab they cannot leave. | |
| 597 | + return 'inbox'; | |
| 598 | + } | |
| 599 | + | |
| 600 | + $remembered = sanitize_key( wp_unslash( $_COOKIE[ self::LAST_TAB_COOKIE ] ?? '' ) ); | |
| 601 | + | |
| 602 | + return in_array( $remembered, self::TOP_TABS, true ) ? $remembered : 'forms'; | |
| 603 | + } | |
| 604 | + | |
| 605 | + /** | |
| 666 | 606 | * WP-Build path for the forms admin URL. |
| 667 | 607 | * |
| 668 | 608 | * @param string|null $tab Tab to open. |
| 669 | 609 | * @param int|null $post_id Post ID of response. |
| @@ -683,8 +623,9 @@ | ||
| 683 | 623 | 'inbox' => '/responses/inbox', |
| 684 | 624 | 'spam' => '/responses/spam', |
| 685 | 625 | 'trash' => '/responses/trash', |
| 686 | 626 | 'forms' => '/forms', |
| 627 | + 'responses' => '/responses/inbox', | |
| 687 | 628 | 'responses/inbox' => '/responses/inbox', |
| 688 | 629 | ); |
| 689 | 630 | |
| 690 | 631 | if ( $tab !== null && $tab !== '' && isset( $path_map[ $tab ] ) ) { |
| @@ -698,35 +639,8 @@ | ||
| 698 | 639 | return '/responses/inbox'; |
| 699 | 640 | } |
| 700 | 641 | |
| 701 | 642 | /** |
| 702 | - * Legacy (hash-based) URL suffix for the forms admin page. | |
| 703 | - * | |
| 704 | - * @param string|null $tab Tab to open. | |
| 705 | - * @param int|null $post_id Post ID of response. | |
| 706 | - * @return string URL suffix (e.g. '#/responses?status=inbox&r=123', or '#/forms'). | |
| 707 | - */ | |
| 708 | - private static function get_forms_admin_suffix_legacy( $tab, $post_id ) { | |
| 709 | - $post_id = ! empty( $post_id ) ? absint( $post_id ) : null; | |
| 710 | - $valid_tabs = array( 'spam', 'inbox', 'trash' ); | |
| 711 | - $r_param = ! empty( $post_id ) ? '&r=' . $post_id : ''; | |
| 712 | - | |
| 713 | - if ( in_array( $tab, $valid_tabs, true ) ) { | |
| 714 | - return '#/responses?status=' . $tab . $r_param; | |
| 715 | - } | |
| 716 | - | |
| 717 | - if ( $tab === 'forms' ) { | |
| 718 | - return '#/forms'; | |
| 719 | - } | |
| 720 | - | |
| 721 | - if ( ! empty( $post_id ) ) { | |
| 722 | - return '#/responses?status=inbox' . $r_param; | |
| 723 | - } | |
| 724 | - | |
| 725 | - return ''; | |
| 726 | - } | |
| 727 | - | |
| 728 | - /** | |
| 729 | 643 | * Returns true if the current screen is the Jetpack Forms admin page. |
| 730 | 644 | * |
| 731 | 645 | * @return boolean |
| 732 | 646 | */ |
| @@ -740,14 +654,9 @@ | ||
| 740 | 654 | if ( ! $screen || ! isset( $screen->id ) ) { |
| 741 | 655 | return false; |
| 742 | 656 | } |
| 743 | 657 | |
| 744 | - $forms_admin_screens = array( | |
| 745 | - 'jetpack_page_' . self::ADMIN_SLUG, | |
| 746 | - 'jetpack_page_' . self::FORMS_WPBUILD_ADMIN_SLUG, | |
| 747 | - ); | |
| 748 | - | |
| 749 | - return in_array( $screen->id, $forms_admin_screens, true ); | |
| 658 | + return $screen->id === 'jetpack_page_' . self::FORMS_WPBUILD_ADMIN_SLUG; | |
| 750 | 659 | } |
| 751 | 660 | |
| 752 | 661 | /** |
| 753 | 662 | * Returns true if form notes feature is enabled. |