Files
wordpress-theme-aksrt/inc/classes/class-aksrt-category-rewrite.php
T

167 lines
5.3 KiB
PHP

<?php
/**
* AKSRT Category Rewrite — Remove /category/ from URLs
*
* Rewrites category URLs from /category/slug/ to /slug/.
* Adds 301 redirect for old /category/ URLs.
*
* WARNING: May conflict with other "no-category" plugins.
* Enable via Settings → SEO → Remove category base.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Category_Rewrite {
private static $instance = null;
private function __construct() {}
private function rewrite_version(): string {
return AKSRT_VERSION . ':category-rewrite-v1';
}
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
if (!$this->is_enabled()) {
// If disabled, ensure old rules are cleaned up
add_action('init', [$this, 'maybe_restore']);
return;
}
add_filter('category_link', [$this, 'remove_category_base'], 10, 2);
add_filter('term_link', [$this, 'remove_category_base_term'], 10, 3);
add_action('init', [$this, 'add_rewrite_rules']);
add_action('template_redirect', [$this, 'redirect_old_urls']);
add_action('admin_init', [$this, 'maybe_flush']);
}
/**
* Check if feature is enabled
*/
private function is_enabled(): bool {
if (!class_exists('AKSRT_Settings')) return false;
// schema key = seo_no_category; runtime alias = seo_remove_category
return (bool) (
AKSRT_Settings::get_value('seo_remove_category', false)
?: AKSRT_Settings::get_value('seo_no_category', false)
);
}
/**
* Remove /category/ from category link
*/
public function remove_category_base(string $link, $term): string {
$base = get_option('category_base');
if ($base && $base !== 'category') return $link;
// Only process category taxonomy
if ($term instanceof WP_Term && $term->taxonomy !== 'category') {
return $link;
}
$category_base_url = preg_quote(trailingslashit(home_url('/category')), '#');
return preg_replace('#' . $category_base_url . '#', trailingslashit(home_url('/')), $link, 1);
}
/**
* Remove base from term_link for categories
*/
public function remove_category_base_term(string $link, $term, $taxonomy): string {
if ($taxonomy !== 'category') return $link;
return $this->remove_category_base($link, $term);
}
/**
* Add rewrite rules for category URLs without /category/
*/
public function add_rewrite_rules(): void {
// Get all category slugs
$categories = get_categories(['hide_empty' => false]);
foreach ($categories as $cat) {
if (empty($cat->slug)) continue;
$slug = $cat->slug;
// /slug/ → index.php?category_name=$slug
add_rewrite_rule(
'^' . preg_quote($slug, '/') . '/?$',
'index.php?category_name=' . $slug,
'top'
);
// /slug/page/N/ → index.php?category_name=$slug&paged=$N
add_rewrite_rule(
'^' . preg_quote($slug, '/') . '/page/([0-9]+)/?$',
'index.php?category_name=$slug&paged=$matches[1]',
'top'
);
// /slug/feed/ → index.php?category_name=$slug&feed=$feed
add_rewrite_rule(
'^' . preg_quote($slug, '/') . '/feed/?$',
'index.php?category_name=$slug&feed=rss2',
'top'
);
}
}
/**
* 301 redirect old /category/ URLs to new ones
*/
public function redirect_old_urls(): void {
$request = $_SERVER['REQUEST_URI'] ?? '';
$home_path = wp_parse_url(home_url('/'), PHP_URL_PATH);
// Remove home path prefix
if ($home_path && strpos($request, $home_path) === 0) {
$request = substr($request, strlen($home_path));
}
// Check if request starts with /category/
if (preg_match('#^category/(.+?)/?$#', $request, $matches)) {
$new_url = home_url('/' . $matches[1] . '/');
wp_redirect($new_url, 301);
exit;
}
}
/**
* Flush rewrite rules when setting changes
*/
public function maybe_flush(): void {
$rewrite_version = $this->rewrite_version();
$stored = (string) get_option('aksrt_category_rewrite_flushed', '');
if ($stored !== $rewrite_version) {
flush_rewrite_rules();
update_option('aksrt_category_rewrite_flushed', $rewrite_version);
}
}
/**
* Restore default rewrite rules when feature is disabled
*/
public function maybe_restore(): void {
$stored = (string) get_option('aksrt_category_rewrite_flushed', '');
if ($stored !== '') {
flush_rewrite_rules();
delete_option('aksrt_category_rewrite_flushed');
}
}
/**
* Force flush (call after enabling/disabling)
*/
public static function force_flush(): void {
flush_rewrite_rules();
update_option('aksrt_category_rewrite_flushed', AKSRT_VERSION . ':category-rewrite-v1');
}
}