diff --git a/seojak.php b/seojak.php index 94b3597..b42d4a9 100644 --- a/seojak.php +++ b/seojak.php @@ -28,6 +28,7 @@ function seojak_defaults(): array { 'default_image' => '', 'twitter_site' => '', 'same_as' => '', + 'redirects' => '', 'noindex_category' => 1, 'noindex_tag' => 1, 'noindex_author' => 1, @@ -347,12 +348,32 @@ add_filter( 'wp_sitemaps_posts_query_args', function ( $args ) { return $args; } ); -// Старый адрес карты сайта и ключ IndexNow. +/* ===================== Редиректы ===================== */ + +/** Правила из настроек: «/откуда/ куда» по строке, # — комментарий. Ключ — путь без крайних слешей, в нижнем регистре. */ +function seojak_redirects(): array { + $rules = array(); + foreach ( explode( "\n", (string) seojak_opt( 'redirects' ) ) as $line ) { + $parts = preg_split( '/\s+/', trim( $line ) ); + if ( 2 === count( $parts ) && '#' !== $parts[0][0] ) { + $rules[ mb_strtolower( trim( rawurldecode( $parts[0] ), '/' ) ) ] = $parts[1]; + } + } + return $rules; +} + +// Старый адрес карты сайта, ключ IndexNow и свои редиректы. add_action( 'template_redirect', function () { + $path = trim( rawurldecode( (string) wp_parse_url( $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH ) ), '/' ); + $to = seojak_redirects()[ mb_strtolower( $path ) ] ?? ''; + if ( $to ) { + // Внешний адрес — как есть (партнёрские ссылки), свой путь — от корня сайта. + wp_redirect( preg_match( '#^https?://#i', $to ) ? $to : home_url( '/' . ltrim( $to, '/' ) ), 301, 'SEOJak' ); // phpcs:ignore WordPress.Security.SafeRedirect -- адреса задаёт админ + exit; + } if ( defined( 'AIOSEO_VERSION' ) ) { return; } - $path = trim( (string) wp_parse_url( $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH ), '/' ); if ( in_array( $path, array( 'sitemap.xml', 'sitemap_index.xml', 'post-sitemap.xml', 'page-sitemap.xml' ), true ) ) { wp_safe_redirect( home_url( '/wp-sitemap.xml' ), 301 ); exit; @@ -504,7 +525,7 @@ add_action( 'admin_init', function () { $out[ $key ] = empty( $in[ $key ] ) ? 0 : 1; } elseif ( in_array( $key, array( 'person_image', 'default_image' ), true ) ) { $out[ $key ] = esc_url_raw( $in[ $key ] ?? '' ); - } elseif ( in_array( $key, array( 'home_description', 'same_as' ), true ) ) { + } elseif ( in_array( $key, array( 'home_description', 'same_as', 'redirects' ), true ) ) { $out[ $key ] = sanitize_textarea_field( $in[ $key ] ?? '' ); } else { $out[ $key ] = sanitize_text_field( $in[ $key ] ?? '' ); @@ -551,6 +572,9 @@ function seojak_settings_page() { + + +

По правилу в строке: путь на этом сайте, пробел, куда вести (полный адрес или путь). Строки с # — комментарии.

Индексация $label ) : ?>
@@ -621,10 +645,31 @@ register_activation_hook( __FILE__, function () { add_option( SEOJAK_OPTION, $opts ); } seojak_import_aioseo(); + seojak_import_redirects(); } ); +/** Дописывает к своим редиректам правила Simple 301 Redirects, которых ещё нет. Возвращает число добавленных. */ +function seojak_import_redirects(): int { + $have = seojak_redirects(); + $lines = array(); + foreach ( (array) get_option( '301_redirects', array() ) as $from => $to ) { + if ( $to && ! isset( $have[ mb_strtolower( trim( rawurldecode( $from ), '/' ) ) ] ) ) { + $lines[] = "$from $to"; + } + } + if ( $lines ) { + $opts = (array) get_option( SEOJAK_OPTION, array() ); + $opts['redirects'] = trim( ( $opts['redirects'] ?? '' ) . "\n" . implode( "\n", $lines ) ); + update_option( SEOJAK_OPTION, $opts ); + } + return count( $lines ); +} + if ( defined( 'WP_CLI' ) && WP_CLI ) { WP_CLI::add_command( 'seojak import-aioseo', function () { WP_CLI::success( 'Перенесено записей: ' . seojak_import_aioseo() ); } ); + WP_CLI::add_command( 'seojak import-redirects', function () { + WP_CLI::success( 'Добавлено редиректов из Simple 301 Redirects: ' . seojak_import_redirects() ); + } ); }