| 1 | <?php
|
|---|
| 2 | /**
|
|---|
| 3 | * Plugin Name: Must-use Plugin
|
|---|
| 4 | * Description: Custom must-use code
|
|---|
| 5 | * Author: Mike Kormendy
|
|---|
| 6 | * Author URI: https://www.mikekormendy.com
|
|---|
| 7 | */
|
|---|
| 8 |
|
|---|
| 9 | //////////////////////////////////////////////////
|
|---|
| 10 | // Preserve Query Strings on Old-Slug Redirects //
|
|---|
| 11 | //////////////////////////////////////////////////
|
|---|
| 12 | /**
|
|---|
| 13 | * WordPress's wp_old_slug_redirect() (wp-includes/query.php) builds its
|
|---|
| 14 | * redirect destination via get_permalink() and drops the original request's
|
|---|
| 15 | * query string entirely. This filter re-appends unknown query args so that
|
|---|
| 16 | * UTM tags, custom params, and any non-WP-internal values survive the 301.
|
|---|
| 17 | *
|
|---|
| 18 | * The "WP-internal" args to strip are sourced live from $wp->public_query_vars
|
|---|
| 19 | * + $wp->private_query_vars (not a hardcoded list) so the set stays in sync
|
|---|
| 20 | * with WordPress core and any plugin that registers its own query vars.
|
|---|
| 21 | */
|
|---|
| 22 | add_filter( 'old_slug_redirect_url', function ( $link ) {
|
|---|
| 23 | if ( empty( $link ) || empty( $_SERVER['QUERY_STRING'] ) ) {
|
|---|
| 24 | return $link;
|
|---|
| 25 | }
|
|---|
| 26 |
|
|---|
| 27 | parse_str( (string) $_SERVER['QUERY_STRING'], $args );
|
|---|
| 28 |
|
|---|
| 29 | $wp_internals = [];
|
|---|
| 30 | if ( isset( $GLOBALS['wp'] ) && $GLOBALS['wp'] instanceof WP ) {
|
|---|
| 31 | $wp_internals = array_merge(
|
|---|
| 32 | (array) $GLOBALS['wp']->public_query_vars,
|
|---|
| 33 | (array) $GLOBALS['wp']->private_query_vars
|
|---|
| 34 | );
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | $strip = array_merge(
|
|---|
| 38 | $wp_internals,
|
|---|
| 39 | wp_removable_query_args(),
|
|---|
| 40 | // Preview/security tokens — never carry these through a 301:
|
|---|
| 41 | [ 'preview', 'preview_id', 'preview_nonce' ],
|
|---|
| 42 | // Owned by Block_User_Enumeration above (intentionally dropped):
|
|---|
| 43 | [ 'author' ]
|
|---|
| 44 | );
|
|---|
| 45 | foreach ( $strip as $key ) {
|
|---|
| 46 | unset( $args[ $key ] );
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | if ( ! $args ) {
|
|---|
| 50 | return $link;
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | // Mirror redirect_canonical()'s encoding (canonical.php:586-593): rawurlencode
|
|---|
| 54 | // keys+values so add_query_arg() emits a query string that round-trips cleanly
|
|---|
| 55 | // (e.g. preserves '%2B' rather than letting it decode to '+').
|
|---|
| 56 | $args = array_combine(
|
|---|
| 57 | rawurlencode_deep( array_keys( $args ) ),
|
|---|
| 58 | rawurlencode_deep( array_values( $args ) )
|
|---|
| 59 | );
|
|---|
| 60 |
|
|---|
| 61 | return add_query_arg( $args, $link );
|
|---|
| 62 | } );
|
|---|