# Redirect Trashed Posts to Their Category

> Remembers the address of each post or page you move to the trash and sends later visitors to its category, parent page or the blog page instead of a 404, even after the trash is emptied.

- Type: PHP
- Runs: Run everywhere
- Category: [Redirects](https://wpide.com/library/category/redirects/)
- Tags: redirects, 404, trash
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/removed-posts-redirect-to-category/

## Code

```php
// Post types to remember; when one is trashed, its old address leads to its first category (posts)
// or its parent page (pages), and otherwise to the blog page.
$wpide_removed_types = array( 'post', 'page' );
// How many old addresses to remember (oldest are dropped first).
$wpide_removed_limit = 500;

add_action( 'wp_trash_post', function ( $post_id ) use ( $wpide_removed_types, $wpide_removed_limit ) {
    $post = get_post( $post_id );

    if ( ! $post || 'publish' !== $post->post_status || ! in_array( $post->post_type, $wpide_removed_types, true ) ) {
        return;
    }

    $target = '';

    if ( 'post' === $post->post_type ) {
        $cats   = wp_get_post_categories( $post->ID );
        $target = $cats ? get_category_link( (int) $cats[0] ) : '';
    } elseif ( $post->post_parent && 'publish' === get_post_status( $post->post_parent ) ) {
        $target = get_permalink( $post->post_parent );
    }

    if ( ! $target ) {
        $blog   = (int) get_option( 'page_for_posts' );
        $target = $blog ? get_permalink( $blog ) : home_url( '/' );
    }

    $path = untrailingslashit( (string) wp_parse_url( get_permalink( $post ), PHP_URL_PATH ) );
    $map  = (array) get_option( 'wpide_removed_post_redirects', array() );

    unset( $map[ $path ] );
    $map[ $path ] = array( 'to' => $target, 'id' => $post->ID );

    update_option( 'wpide_removed_post_redirects', array_slice( $map, -absint( $wpide_removed_limit ), null, true ), false );
} );

// Restoring a post from the trash removes its redirect.
add_action( 'untrashed_post', function ( $post_id ) {
    $map = (array) get_option( 'wpide_removed_post_redirects', array() );

    foreach ( $map as $path => $item ) {
        if ( isset( $item['id'] ) && (int) $item['id'] === (int) $post_id ) {
            unset( $map[ $path ] );
        }
    }

    update_option( 'wpide_removed_post_redirects', $map, false );
} );

add_action( 'template_redirect', function () {
    if ( ! is_404() ) {
        return;
    }

    $map  = get_option( 'wpide_removed_post_redirects', array() );
    $path = isset( $_SERVER['REQUEST_URI'] ) ? untrailingslashit( (string) wp_parse_url( wp_unslash( $_SERVER['REQUEST_URI'] ), PHP_URL_PATH ) ) : '';

    if ( ! is_array( $map ) || '' === $path || empty( $map[ $path ]['to'] ) ) {
        return;
    }

    wp_safe_redirect( $map[ $path ]['to'], 301 );
    exit;
} );
```

## Notes

Restoring a post removes its redirect; up to 500 addresses are remembered.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Redirect Trashed Posts to Their Category" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
