🔒 守秘義務案件のため、クライアント名・URL・スクリーンショット等の詳細情報を省略しています。
ヘアサロンチェーン公式サイト(東京都内 11 店舗展開)
こちらの案件は、下記に記載の制作会社様からの受託案件の中の一部をピックアップしたものです。
概要
| 項目 | 内容 |
|---|---|
| 種別 | ヘアサロンチェーン公式サイト(11 店舗) |
| 技術スタック | WordPress + PHP / カスタムテーマ(フルスクラッチ開発) |
| テーマ設計 | 親テーマ1つ + 11 チャイルドテーマ(変数上書きのみで店舗差分を表現) |
| WordPress 開発 | カスタム投稿タイプ 11種・SCF フィールド 30+ グループ・WP_Query 多段構成・マルチサイト同期 |
| SCSS | vw 相対計算 mixin・SP ファースト 3 ブレークポイント・変数設計によるチャイルドテーマ差分最小化 |
| フロントエンド | jQuery + Slick カルーセル・条件付きエンキューによる不要 JS ロード排除 |
| テンプレート | WP テンプレート階層フル活用(25 ファイル超) |
| 管理画面 UX | 不要メタボックス削除・投稿マニュアル導線・文字数ヒント表示 |
アーキテクチャ面
親テーマ × チャイルドテーマによるマルチサロン設計
「全店舗共通ロジックは親テーマに集約、店舗固有の外観だけチャイルドテーマで上書き」というWP標準の継承モデルを徹底することで、11 店舗分のテーマを1つのコードベースで管理。新店舗追加はチャイルドテーマ 1 枚の作成で完結する構造にした。
| レイヤー | 役割 | 主な内容 |
|---|---|---|
| 親テーマ | 全店舗共通 | カスタム投稿タイプ・SCFフィールド定義・全テンプレート・SCSS変数/mixin・JS |
チャイルドテーマ salon_name-child-* | 店舗別上書き | カラー変数の再定義・必要な場合のみテンプレートオーバーライド |
チャイルドテーマの functions.php は親・子スタイルシートのエンキューのみ。PHP ロジックの重複ゼロ。
// 親テーマ→子テーマの順でスタイルエンキュー
wp_enqueue_style( "parent-style", get_template_directory_uri() . "/style.css" );
wp_enqueue_style( "child-style", get_stylesheet_directory_uri() . "/style.css", array("parent-style"));
カスタム投稿タイプ設計(11 CPT)
サロンビジネスに必要なコンテンツを投稿タイプ単位で独立モデル化。各 CPT はクラスとして定義し、フィールド定義・SCF登録を分離することで、登録ロジックの再利用と変更の局所化を実現した。
| 投稿タイプ | スラッグ | 主な SCF フィールド |
|---|---|---|
| スタッフ | staff | 画像・担当メニュー・Instagram埋め込み・予約URL 等 15 フィールド |
| ヘアスタイル | hairstyle | 繰り返し画像・スタッフリレーション・顔型/髪質チェックボックス群 |
| ブログ | post | 関連クーポン(リレーション)・担当スタッフ(リレーション) |
| メニュー | menu | 詳細グループ(繰り返し):メニュー名・価格・注意書き |
| クーポン | coupon | 対象サービス(15種チェックボックス)・通常/クーポン価格 |
| 口コミ | review | 評価(ラジオ 1〜5)・スタッフ返信・スタッフリレーション |
| お知らせ | information | カスタムタクソノミー連携 |
| 店舗情報 | オプションページ | ロゴ・TEL・GA タグ・バナー・フッター設定 |
| トップページ | オプションページ | スライダー・コンセプト・Instagram API 認証情報 |
| オプションページ | オプションページ | 各ページ SEO(タイトル・description・H1) |
| ヘアスタイル長さ | タクソノミー拡張 | ターム単位カスタムフィールド |
CPT クラス × SCF 動的登録パターン
フィールド定義をクラスメソッドで返す設計にすることで、CPT 登録と SCF 登録の責務を分離。変更がクラス1か所に閉じる。
// CPT 側:フィールド定義を配列で返す
class CPT_Staff {
public function get_fields(): array { return [ /* フィールド群 */ ]; }
}
// functions.php 側:SCF への登録
add_filter( 'smart-cf-register-fields', 'my_register_fields', 10, 4 );
function my_register_fields( $fields, $args, $post, $page ) {
$cpt_obj = new CPT_Staff();
$Setting = SCF::add_setting( CPT_Staff::SCF_ID, CPT_Staff::SCF_TITLE );
foreach ( $cpt_obj->get_fields() as $group ) {
$Setting->add_group( $group['group'], $group['repeat'], $group['settings'] );
}
return $fields;
}
WordPress マルチサイト連携
グループメインサイトに向けて、各店舗サイトからのコンテンツ自動同期を実装。
スタッフ・ヘアスタイルタグの保存時に switch_to_blog() で対象サブサイトに切り替え、タクソノミーを書き込んで restore_current_blog() で復元する。編集者がサブサイトを意識しなくて済む構造にした。
$entrance_ids = array(1, 14);
foreach ( $entrance_ids as $ent_id ) {
switch_to_blog( $ent_id );
// タクソノミーターム同期処理
restore_current_blog();
}
WordPress カスタム開発
functions.php 主要実装
1. 不要な wp_head 出力の排除
ページ重量削減と情報漏えい防止のため、デフォルトで出力される不要なメタ情報を一括削除。
remove_action( 'wp_head', 'wp_generator' ); // バージョン情報
remove_action( 'wp_head', 'feed_links', 2 ); // RSS リンク
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
add_action( 'wp_enqueue_scripts', 'remove_block_library_style' ); // Gutenberg CSS
2. スクリプト条件分岐エンキュー
Slick カルーセル・Instagram フィードスクリプトを必要なページのみ読み込み、不要なページへの JS ロードを抑制。
function salon_name_scripts() {
// 全ページ共通
wp_enqueue_script( 'jquery-cdn', '//code.jquery.com/jquery-3.3.1.min.js', ... );
wp_enqueue_style( 'font-awesome', '...fa.5.7.2.all.min.css' );
// トップページのみ
if ( is_front_page() || is_home() ) {
wp_enqueue_script( 'slick-js', ... );
wp_enqueue_script( 'instafeed', ... );
}
// ヘアスタイル詳細のみ
if ( is_singular('hairstyle') ) {
wp_enqueue_script( 'slick-js', ... );
}
}
3. カスタムクエリ変数の登録
?staff_id=123 形式の URL をテンプレート側で参照できるよう、WP のクエリ変数に追加。
add_filter( 'query_vars', 'add_query_vars_filter' );
function add_query_vars_filter( $vars ) {
$vars[] = 'staff_id';
return $vars;
}
4. 管理画面 UI カスタマイズ
編集者向けに不要なメタボックスを削除し、投稿マニュアルページへの導線を管理メニューに追加。表示制御は PHP + admin_head への CSS インジェクションで実装。
function remove_default_post_screen_metaboxes() {
$screen = get_current_screen();
foreach ( ['custom-fields','excerpt','comments','trackbacks',
'author','slug','revisions'] as $id ) {
remove_meta_box( $id, $screen, 'normal' );
}
}
add_action( 'admin_menu', 'add_manual_pages' ); // 投稿マニュアルリンク追加
5. OGP / 構造化メタデータ生成
salon_name_get_metadata() で投稿タイプ・タクソノミー・SCF オプションページのいずれかからメタ情報を取得し、header.php で og:title / og:image / og:description を動的出力。
テンプレート構成(25 ファイル超)
WP テンプレート階層をフル活用し、投稿タイプ・タクソノミー・ページスラッグ単位でテンプレートを分岐。
| テンプレート | 役割 |
|---|---|
single-staff.php | スタイリスト詳細(Instagram埋め込み・予約ボタン) |
single-hairstyle.php | スタイル詳細(Slick ギャラリー・顔型/髪質タグ表示) |
archive-hairstyle.php | スタイルカタログ一覧(タクソノミーフィルター連動) |
taxonomy-hairstyle-length.php | 長さカテゴリー別絞り込みページ |
page-ranking.php | ランキングページ(SCF ラジオ値でソート) |
page-hairstyle-new.php | 新着スタイル特集ページ |
archive-coupon.php | クーポン一覧(カテゴリータクソノミー別) |
archive-review.php | 口コミ一覧(評価スター表示) |
page-company.php | 企業情報ページ(全サイドバーなし全幅レイアウト) |
page-shoplist.php | 全店舗一覧(SCF 店舗情報を複数クエリで集約) |
WP_Query 多段活用(トップページ構成)
トップページの各セクションを独立した WP_Query / get_posts() で構築。SCF オプションページで管理者が表示対象カテゴリーを指定し、コードを変更せずにコンテンツ構成を変更できる設計にした。
// 例:直近1年以内の特定カテゴリー記事のみ取得
$args = array(
'posts_per_page' => -1,
'category_name' => $page_category, // SCF オプションから取得
'category__not_in' => array(15),
'date_query' => array(array(
'after' => array(
'year' => $year - 1,
'month' => '1',
'day' => '1',
),
)),
);
SCSS ビルド設計
変数・mixin による共通基盤
SCSS を _base.scss / _common.scss / style.scss に分割。変数と mixin を共通化し、チャイルドテーマは変数を再定義するだけで全体のカラースキームを上書きできる構造にした。
主な変数(_common.scss):
// フォントスタック
$base-font: "游ゴシック体", YuGothic, "Hiragino Kaku Gothic Pro", ...
$serif-font: 'Noto Serif JP', serif
$playfair-font: 'Playfair Display', serif
// ブレークポイント
$body-width-sp: 640px
$bp: 768px // タブレット
$bp-pc: 1280px // PC
// ブランドカラー(チャイルドで上書き)
$title-color: #be9f31 // ゴールド(親テーマデフォルト)
$shop-color: #d9c98f
主な mixin(_base.scss):
@mixin calc-fontsize($size, $displaysize) {
font-size: $size / $displaysize * 100vw; // vw 相対フォントサイズ
}
@function calc-size($original, $displaysize, $unit) { ... } // vw/% 変換
@mixin tab { @media (min-width: $bp) { @content; } }
@mixin pc { @media (min-width: $bp-pc) { @content; } }
@mixin object-fit() // IE 対応 object-fit ポリフィル
@mixin object-fit-height()
@mixin flexbox() // クロスブラウザ flexbox
レスポンシブ設計(SP ファースト・3ブレークポイント)
モバイルファーストで記述し、タブレット・PC はそれぞれ mixin でメディアクエリを適用。フォントサイズや余白は vw 単位の計算関数で連続スケーリングさせ、固定ピクセル値の羅列を避けた。
| デバイス | 幅 | 切り替え方法 |
|---|---|---|
| スマートフォン(基準) | 〜767px | デフォルトスタイル(calc-fontsize による vw 指定) |
| タブレット | 768px〜 | @include tab { ... } |
| PC | 1280px〜 | @include pc { ... } |
チャイルドテーマでの色変数上書き
チャイルドテーマの style.scss は親の _base / _common を再インポートした上でカラー変数だけ差し替え、差分となるセレクターのみ記述(約 400 行)。親テーマの 3,600 行超に対して重複なし。
// salon_name-child-shinjuku/style.scss(抜粋)
@import "../salon_name/inc/base";
@import "../salon_name/inc/common";
$title-color: #f5a9bc; // ピンク
$title-sub-color: #ecc03d; // イエロー
$shop-color: #f5a9bc;
// 上記変数を使うセレクターのみ再定義
.section-title { border-color: $title-color; }
JavaScript インタラクション
jQuery ベースで3ファイルに役割を分離。ライブラリは Slick カルーセルと Instafeed のみ、自前 JS はシンプルに保った。
| ファイル | 実装内容 |
|---|---|
common.js | スムーズスクロール(ヘッダー高さオフセット対応)・ハンバーガーメニュー開閉・ブログ記事高さ揃え |
index.js | トップスライダー初期化(SP/PC 別設定)・スタイル推薦カルーセル(4枚/3枚レスポンシブ) |
style.js | ヘアスタイル詳細ギャラリー(3枚→1枚 レスポンシブ、ドットナビ) |
// index.js:SP / PC でスライダー設定を切り替え
$('#slider').slick({
infinite: true, autoplay: true, autoplaySpeed: 3000,
responsive: [{ breakpoint: 768, settings: { slidesToShow: 1 } }]
});
// common.js:ヘッダー高さを考慮したスムーズスクロール
$('a[href^="#"]').on('click', function () {
var target = $( $(this).attr('href') );
$('html, body').animate({ scrollTop: target.offset().top - headerH }, 500);
return false;
});
まとめ
| 項目 | 内容 |
|---|---|
| 種別 | ヘアサロンチェーン公式サイト(11 店舗) |
| 技術スタック | WordPress + PHP / カスタムテーマ(フルスクラッチ開発) |
| テーマ設計 | 親テーマ1つ + 11 チャイルドテーマ(変数上書きのみで店舗差分を表現) |
| WordPress 開発 | カスタム投稿タイプ 11種・SCF フィールド 30+ グループ・WP_Query 多段構成・マルチサイト同期 |
| SCSS | vw 相対計算 mixin・SP ファースト 3 ブレークポイント・変数設計によるチャイルドテーマ差分最小化 |
| フロントエンド | jQuery + Slick カルーセル・条件付きエンキューによる不要 JS ロード排除 |
| テンプレート | WP テンプレート階層フル活用(25 ファイル超) |
| 管理画面 UX | 不要メタボックス削除・投稿マニュアル導線・文字数ヒント表示 |