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'); } }