WordPressでブログを運営していると、カテゴリーページのURLに含まれる /category/ という文字を削除して、URLをすっきりとシンプルな構造にしたいと思うことがあるでしょう。
URLの階層を浅くすることは、読者にとっても検索エンジンにとっても見やすくなるというメリットがあります。
今回は、カテゴリーURLから /category/ を安全に削除し、SEOの評価も引き継ぐための2つの最終的なコード(functions.php用と自作プラグイン用)を作成しました。
初心者の方にも分かりやすいように、コードの内容や設定時の注意点を順を追って解説していきます。ぜひ参考にしてみてください。
カテゴリーURLから「/category/」を消去する2つのコード
まずは、安全性と処理の軽さを考慮して作成した最終コードを2パターン紹介します。ご自身のサイトの運用スタイルに合わせて、どちらか一方を選んで導入してください。
【functions.php用】無名関数でスッキリまとめた最終コード
テーマの functions.phpの末尾に追加するコードです。関数名が他のプログラムと衝突しないように、スマートな設計にしています。
/**
* カテゴリーURLから /category/ を削除する処理
* (旧URLからの301リダイレクト・WPML多言語対応)
*
* 【適応時(導入時)の注意】
* このコードを追加した直後は、必ずWordPress管理画面の「設定」>「パーマリンク」を開き、
* 何も変更せずに「変更を保存」ボタンをクリックしてください。
* (※この操作を行わないと、新しいルールが反映されずカテゴリーページが404エラーになります)
*
* 【アンインストール(削除)時の注意】
* functions.phpからこのコードを削除して元のURLに戻す場合、コードを消しただけでは
* キャッシュされたルールが残り、表示崩れやエラーの原因になります。
* 削除後も必ず「設定」>「パーマリンク」を開き、「変更を保存」をクリックして
* リライトルールを初期化(リセット)してください。
*/
// 1. パーマリンク構造の上書き
add_action('init', function () {
global $wp_rewrite;
$wp_rewrite->extra_permastructs['category']['struct'] = '%category%';
});
// 2. リライトルールの生成(WPML多言語対応)
add_filter('category_rewrite_rules', function ($category_rewrite) {
global $wp_rewrite;
$category_rewrite = array();
$categories = get_categories(array('hide_empty' => false));
foreach ($categories as $category) {
$category_nicename = $category->slug;
if ($category->parent) {
$category_nicename = get_category_parents($category->term_id, false, '/', true);
}
$category_rewrite['(' . $category_nicename . ')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?category_name=$matches&feed=$matches';
$category_rewrite['(' . $category_nicename . ')/page/?([0-8]+)/?$'] = 'index.php?category_name=$matches&paged=$matches';
$category_rewrite['(' . $category_nicename . ')/?$'] = 'index.php?category_name=$matches';
}
// リダイレクト用ルール(旧URLをキャッチするためのおまじない)
$category_rewrite['category/(.+)'] = 'index.php?category_redirect=$matches';
return $category_rewrite;
});
// 3. クエリ変数の追加
add_filter('query_vars', function ($public_query_vars) {
$public_query_vars[] = 'category_redirect';
return $public_query_vars;
});
// 4. 301リダイレクト処理(セキュアな関数への最適化済み)
add_filter('request', function ($query_vars) {
if (isset($query_vars['category_redirect'])) {
$catlink = trailingslashit(get_option('home')) . user_trailingslashit($query_vars['category_redirect'], 'category');
// WordPressネイティブの安全なリダイレクト関数を使用
wp_safe_redirect($catlink, 301);
exit();
}
return $query_vars;
});
// 5. ルールの更新(※複数フックで重複利用するため、ここだけ名前付き関数として定義)
function robust_refresh_category_rewrite_rules() {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
add_action('created_category', 'robust_refresh_category_rewrite_rules');
add_action('edited_category', 'robust_refresh_category_rewrite_rules');
add_action('delete_category', 'robust_refresh_category_rewrite_rules');PHP【自作プラグイン用】クラス化して綺麗に管理する最終コード
「テーマを変更した時に設定が消えるのを防ぎたい」「functions.phpを直接編集するのは少し不安がある」という場合は、こちらがおすすめです。
以下のコードを no-category-base-optimized.php という名前で保存し、WordPressの /wp-content/plugins/ フォルダにアップロードするか、zipファイルに圧縮して管理画面からインストールするだけで、専用のプラグインとして動作します。
<?php
/*
Plugin Name: No Category Base Optimized
Plugin URI: https://it-manabi.com/
Description: カテゴリーURLから /category/ を削除します(301リダイレクト・WPML対応の最適化版)。
Version: 1.0.0
Author: IT学び舎
License: GPL2
*/
if (!defined('ABSPATH')) {
exit; // 直接アクセスを禁止するおまじない
}
class NoCategoryBaseOptimized {
public function __construct() {
// 初期化処理
add_action('init', array($this, 'remove_category_permastruct'));
add_filter('category_rewrite_rules', array($this, 'category_rewrite_rules'));
add_filter('query_vars', array($this, 'category_query_vars'));
add_filter('request', array($this, 'category_redirect_request'));
// ルールの更新(DBのみ更新で負荷軽減)
add_action('created_category', array($this, 'refresh_rewrite_rules'));
add_action('edited_category', array($this, 'refresh_rewrite_rules'));
add_action('delete_category', array($this, 'refresh_rewrite_rules'));
// 有効化・無効化時のフック
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
}
public function remove_category_permastruct() {
global $wp_rewrite;
$wp_rewrite->extra_permastructs['category']['struct'] = '%category%';
}
public function category_rewrite_rules($category_rewrite) {
global $wp_rewrite;
$category_rewrite = array();
$categories = get_categories(array('hide_empty' => false));
foreach ($categories as $category) {
$category_nicename = $category->slug;
if ($category->parent) {
$category_nicename = get_category_parents($category->term_id, false, '/', true);
}
$category_rewrite['(' . $category_nicename . ')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?category_name=$matches&feed=$matches';
$category_rewrite['(' . $category_nicename . ')/page/?([0-8]+)/?$'] = 'index.php?category_name=$matches&paged=$matches';
$category_rewrite['(' . $category_nicename . ')/?$'] = 'index.php?category_name=$matches';
}
// 旧URL(/category/slug)からのアクセスを受け止めるクエリ用のリライトルール
$category_rewrite['category/(.+)'] = 'index.php?category_redirect=$matches';
return $category_rewrite;
}
public function category_query_vars($public_query_vars) {
$public_query_vars[] = 'category_redirect';
return $public_query_vars;
}
public function category_redirect_request($query_vars) {
if (isset($query_vars['category_redirect'])) {
$catlink = trailingslashit(get_option('home')) . user_trailingslashit($query_vars['category_redirect'], 'category');
// セキュアなリダイレクト関数を使用
wp_safe_redirect($catlink, 301);
exit();
}
return $query_vars;
}
public function refresh_rewrite_rules() {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
public function activate() {
$this->refresh_rewrite_rules();
}
public function deactivate() {
global $wp_rewrite;
// パーマリンク構造を標準のcategory付きに戻す
$wp_rewrite->extra_permastructs['category']['struct'] = 'category/%category%';
$wp_rewrite->flush_rules();
}
}
new NoCategoryBaseOptimized();PHPコードの「こだわりポイント」を解説
さて、提示したコードですが、現代のWordPress基準に合わせて4つのポイントに注意しながら実装しています。
どのような点に配慮して設計したのかは今から詳しく解説していきます。
WordPressの「コア設定」を直接書き換えるスマート設計
従来のシンプルな自作コードでは、画面に出力されるURL文字列に対して、後から str_replace などの関数で強引に /category/ を削る処理が主流でした。
しかし、そのアプローチだと、たまたま記事のスラッグの中に my-category-post のような「category」という文字列が含まれていた場合に、意図しないURLの書き換え(文字置換)が起きてしまうリスクがありました。
そこで今回のコードでは、WordPressコアの初期化(init)フックを使い、パーマリンク構造そのものを直接 %category% に上書きしています。
$wp_rewrite->extra_permastructs['category']['struct'] = '%category%';
これにより、WordPress本体が自動的に /category/ なしのURLを正しく生成するようになります。パンくずリストや投稿内のリンクなども、すべて自然に最適化されるので、やはりこの方法が一番スマートでしょう。
古いURLから新しいURLへの「301永久リダイレクト」
長年運営しているブログの場合、検索エンジンには元の /category/〇〇 というURLで登録されています。これを何も対策せずにURLだけを消してしまうと、検索エンジン経由のアクセスはすべて「404 Not Found(ページが見つかりません)」というエラーになり、SEO的にもやはり最悪です。
そこで、今回のコードでは「古いURL(/category/...)へのアクセスを検知するルール」を追加し、新しいURLへと301リダイレクトする処理を追加しています。
これによって、検索エンジンからの評価やドメインパワーもしっかり維持されます。既存のブログに導入する場合でも、これで安心できるでしょう。
セキュリティ基準を高めた wp_safe_redirect の採用
リダイレクト処理において、一般的なPHP標準の header() 関数をそのまま使用することは、セキュリティの観点から推奨されません。悪意のある第三者によって、意図しない外部サイトへ不正にユーザーが転送されてしまう脆弱性を防ぐ必要があるためです。
そのため、今回の最終コードでは、WordPress独自の安全なリダイレクト関数である wp_safe_redirect() を全面的に採用しました。
wp_safe_redirect($catlink, 301);
これにより、サイトの安全性が大幅に向上し、より高いセキュリティ基準を満たすことができます。
グローバルスコープを汚さない「無名関数」と「クラス化」
functions.php は、テーマや他のプラグインの動作を管理する重要なファイルです。ここで適当な名前の関数(例えば remove_category() など)を定義してしまうと、将来別のプラグインを導入した際に、同じ名前の関数が存在して競合エラー(Fatal Error)を引き起こし、画面が真っ白になってしまうリスクがあります。
この問題を回避するために、2つのコードでそれぞれ異なる設計をとっています。
- functions.php用
-
再利用する必要のない処理は、すべて名前を持たない「無名関数(クロージャー)」に閉じ込めました。これで名前の衝突リスクは完全になくなります。
- 自作プラグイン用
-
プラグインとして動作させる場合、無名関数を使用すると、プラグイン無効化時に設定を元に戻すクリーンアップ処理(deactivate)を正常に行うのが困難になります。そのため、プラグイン全体を1つの「クラス(Class)」にカプセル化(パッケージング)する設計をとっています。これにより、名前の競合を防ぎつつ、無効化時には確実に元の設定へ戻すことができます。
Q&A:導入前に知っておくべき知識と注意点
実際にサイトに導入する前に、つまずきやすいポイントや疑問点をQ&A形式で整理しておきましょう。
あとがき

カテゴリーのURLから /category/ を消去するカスタマイズは、URL設計をシンプルに保ち、サイトの構造を整理するのに非常に効果的です。
「functions.phpに記述するのは難しい」と思われるかもしれませんが、手順通りにパーマリンクの保存を忘れずに行えば、安全かつスムーズに実装できます。
テーマを頻繁に変更しないのであれば、プラグインを増やさずに済む「functions.php用」がおすすめです。もし、将来のテーマ変更などを考慮するなら、「自作プラグイン用」として管理するのが良いでしょう。
ご自身のサイト環境や運用方法に合わせて、最適な方法を選んで試してみてください。


コメント