Redirects From a CSV File
Reads redirect rules from a redirects.csv file in wp-content, one "old path, new address, status" line each, so you can manage hundreds of redirects in a spreadsheet without a plugin.
Opens WPIDE on
Code
// The redirect file: one rule per line as old-path,new-address[,status] for example
// /old-page/,/new-page/,301
// /spring-sale/,https://shop.example.com/sale/,302
// Kept outside the uploads folder so only people with file access can change it.
$wpide_redirects_file = WP_CONTENT_DIR . '/redirects.csv';
add_action( 'template_redirect', function () use ( $wpide_redirects_file ) {
if ( ! is_readable( $wpide_redirects_file ) ) {
return;
}
$stamp = filemtime( $wpide_redirects_file ) . '-' . filesize( $wpide_redirects_file );
$cache = get_transient( 'wpide_csv_redirects' );
// Parse the file only when it changes.
if ( ! is_array( $cache ) || ! isset( $cache['stamp'] ) || $cache['stamp'] !== $stamp ) {
$rules = array();
$handle = fopen( $wpide_redirects_file, 'r' ); // phpcs:ignore WordPress.WP.AlternativeFunctions
while ( $handle && false !== ( $row = fgetcsv( $handle, 2048, ',', '"', '' ) ) ) {
if ( count( $row ) < 2 || '' === trim( (string) $row[0] ) || 0 === strpos( trim( (string) $row[0] ), '#' ) ) {
continue;
}
$from = strtolower( untrailingslashit( (string) wp_parse_url( trim( $row[0] ), PHP_URL_PATH ) ) );
$status = isset( $row[2] ) ? (int) $row[2] : 301;
$rules[ '' === $from ? '/' : $from ] = array(
'to' => trim( $row[1] ),
'status' => in_array( $status, array( 301, 302, 307, 308, 410 ), true ) ? $status : 301,
);
}
if ( $handle ) {
fclose( $handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions
}
$cache = array( 'stamp' => $stamp, 'rules' => $rules );
set_transient( 'wpide_csv_redirects', $cache, DAY_IN_SECONDS );
}
$path = isset( $_SERVER['REQUEST_URI'] ) ? strtolower( untrailingslashit( (string) wp_parse_url( wp_unslash( $_SERVER['REQUEST_URI'] ), PHP_URL_PATH ) ) ) : '';
$path = '' === $path ? '/' : $path;
if ( empty( $cache['rules'][ $path ] ) ) {
return;
}
$rule = $cache['rules'][ $path ];
if ( 410 === $rule['status'] ) {
status_header( 410 );
nocache_headers();
return;
}
$to = preg_match( '#^https?://#i', $rule['to'] ) ? $rule['to'] : home_url( $rule['to'] );
if ( strtolower( untrailingslashit( (string) wp_parse_url( $to, PHP_URL_PATH ) ) ) === $path && wp_parse_url( $to, PHP_URL_HOST ) === wp_parse_url( home_url(), PHP_URL_HOST ) ) {
return; // Would redirect to itself.
}
wp_redirect( esc_url_raw( $to ), $rule['status'] ); // phpcs:ignore WordPress.Security.SafeRedirect -- rules come from the site owner's file.
exit;
}, 1 );
Notes
Nothing happens until the file exists; it is re-read only when it changes. Supports 301, 302, 307, 308 and 410.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.