WordPress年代別分布円グラフの作成と設定手順

# WordPress年代別分布円グラフの作成と設定手順

WordPressで年代別分布を美しい円グラフで表示する方法を詳しく解説します。このグラフはSmart Custom Fieldsと連携して管理画面から簡単に数値を変更できる仕組みになっています。グラフ内には自動計算されたパーセンテージが表示され、視覚的にわかりやすい年代別の分布を表現できます。

## 完成イメージ

このチュートリアルでは、「20代〜60代」の年代別分布を円グラフで表示します。特徴は以下の通りです：

- 各年代のデータをWordPress管理画面から簡単に変更可能
- グラフ内に各年代の割合がパーセント表示（数字は大きく、%記号は小さく右下に表示）
- 5%未満の小さいセグメントにはパーセント表示なし（見やすさ配慮）
- ホバー時にツールチップで詳細情報（年代、人数、パーセント）を表示

## 必要なもの

1. WordPress（最新版推奨）
2. プラグイン「Smart Custom Fields」
3. Chart.jsを利用するためのインターネット接続

## 手順1: Smart Custom Fieldsのインストールと設定

1. WordPressの管理画面から「プラグイン」→「新規追加」を選択
2. 検索欄に「Smart Custom Fields」と入力し、検索
3. プラグインを「インストール」→「有効化」

プラグインを有効化したら、以下の手順でカスタムフィールドを設定します：

1. WordPress管理画面 → Smart Custom Fields → カスタムフィールドの追加 をクリック
2. グループ名を「年代別データ」など分かりやすい名前に設定
3. 以下のフィールドを作成します：
  
  | フィールド名 | タイプ | キー | 初期値 | 備考 |
  |------------|------|-----|------|------|
  | 20代 | 数値 | twenties | 25 | 20代の人数 |
  | 30代 | 数値 | thirties | 30 | 30代の人数 |
  | 40代 | 数値 | forties | 20 | 40代の人数 |
  | 50代 | 数値 | fifties | 15 | 50代の人数 |
  | 60代 | 数値 | sixties | 10 | 60代の人数 |

4. 「表示条件」タブをクリック
5. 「投稿タイプ」を選択し、「固定ページ」にチェック
6. 「保存」ボタンをクリック

## 手順2: テンプレートファイルの作成

1. お使いのテーマフォルダに新しいファイル「template-age-chart.php」を作成します
2. 以下のコード全体をコピーして貼り付けます：

```php
<?php
/**
* Template Name: 年代別分布円グラフ
*/
get_header();
?>

<div class="content-area">
   <main id="main" class="site-main">
       <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
           <header class="entry-header">
               <h1 class="entry-title"><?php the_title(); ?></h1>
           </header>

           <div class="entry-content">
               <?php the_content(); ?>
               
               <!-- 円グラフ表示エリア -->
               <div class="chart-container" style="position: relative; width: 100%; max-width: 500px; margin: 0 auto;">
                   <canvas id="ageChart"></canvas>
               </div>
               
               <div class="total-count" style="text-align: center; margin-top: 10px; font-weight: bold;">
                   合計: <span id="totalValue">0</span>人
               </div>
               
               <?php
               // Smart Custom Fieldsの値を取得
               $twenties = get_post_meta(get_the_ID(), 'twenties', true) ?: 0;
               $thirties = get_post_meta(get_the_ID(), 'thirties', true) ?: 0;
               $forties = get_post_meta(get_the_ID(), 'forties', true) ?: 0;
               $fifties = get_post_meta(get_the_ID(), 'fifties', true) ?: 0;
               $sixties = get_post_meta(get_the_ID(), 'sixties', true) ?: 0;
               ?>
               
               <!-- Chart.jsライブラリの読み込み -->
               <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
               <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js"></script>
               
               <script>
               document.addEventListener('DOMContentLoaded', function() {
                   // PHPから渡された値を取得
                   const twenties = <?php echo $twenties; ?>;
                   const thirties = <?php echo $thirties; ?>;
                   const forties = <?php echo $forties; ?>;
                   const fifties = <?php echo $fifties; ?>;
                   const sixties = <?php echo $sixties; ?>;
                   
                   // 合計を計算して表示
                   const total = twenties + thirties + forties + fifties + sixties;
                   document.getElementById('totalValue').textContent = total;
                   
                   // グラフの初期設定
                   const ctx = document.getElementById('ageChart').getContext('2d');
                   
                   // 色の設定
                   const backgroundColors = [
                       'rgba(255, 99, 132, 0.7)',
                       'rgba(54, 162, 235, 0.7)',
                       'rgba(255, 206, 86, 0.7)',
                       'rgba(75, 192, 192, 0.7)',
                       'rgba(153, 102, 255, 0.7)'
                   ];
                   
                   // データセット
                   let ageData = {
                       labels: ['20代', '30代', '40代', '50代', '60代'],
                       datasets: [{
                           data: [twenties, thirties, forties, fifties, sixties],
                           backgroundColor: backgroundColors,
                           borderColor: backgroundColors.map(color => color.replace('0.7', '1')),
                           borderWidth: 1
                       }]
                   };
                   
                   // グラフのオプション
                   const options = {
                       responsive: true,
                       plugins: {
                           legend: {
                               position: 'bottom',
                           },
                           tooltip: {
                               enabled: true,
                               callbacks: {
                                   label: function(context) {
                                       const label = context.label || '';
                                       const value = context.raw || 0;
                                       const total = context.dataset.data.reduce((a, b) => a + b, 0);
                                       const percentage = Math.round((value / total) * 100);
                                       return `${label}: ${value}人 (${percentage}%)`;
                                   }
                               }
                           },
                           datalabels: {
                               display: false
                           }
                       }
                   };
                   
                   // パーセント表示の設定
                   Chart.register({
                       id: 'percentLabels',
                       afterDatasetsDraw: function(chart) {
                           const ctx = chart.ctx;
                           
                           chart.data.datasets.forEach((dataset, i) => {
                               const meta = chart.getDatasetMeta(i);
                               if (!meta.hidden) {
                                   meta.data.forEach((element, index) => {
                                       // 各セグメントの値と合計を取得
                                       const value = dataset.data[index];
                                       const total = dataset.data.reduce((t, v) => t + v, 0);
                                       const percentage = Math.round((value / total) * 100);
                                       
                                       // 5%未満は表示しない
                                       if (percentage < 5) return;
                                       
                                       // 角度の中間点を計算
                                       const startAngle = element.startAngle;
                                       const endAngle = element.endAngle;
                                       const midAngle = startAngle + (endAngle - startAngle) / 2;
                                       
                                       // 半径の中間点を計算
                                       const radius = (element.outerRadius + element.innerRadius) / 2 * 0.8;
                                       
                                       // セグメントの中心座標
                                       const x = element.x + Math.cos(midAngle) * radius;
                                       const y = element.y + Math.sin(midAngle) * radius;
                                       
                                       // 数字を大きく表示
                                       ctx.save();
                                       ctx.textAlign = 'center';
                                       ctx.textBaseline = 'middle';
                                       ctx.fillStyle = '#fff';
                                       ctx.font = 'bold 18px Arial';
                                       ctx.fillText(percentage, x, y);
                                       
                                       // %記号を小さく右下に表示
                                       ctx.font = 'bold 10px Arial';
                                       ctx.fillText('%', x + 14, y + 8);
                                       ctx.restore();
                                   });
                               }
                           });
                       }
                   });
                   
                   // Chart.jsにプラグインを登録
                   Chart.register(ChartDataLabels);
                   
                   // グラフの作成
                   let myChart = new Chart(ctx, {
                       type: 'pie',
                       data: ageData,
                       options: options,
                       plugins: [ChartDataLabels]
                   });
               });
               </script>
           </div>
       </article>
   </main>
</div>

<?php get_footer(); ?>
```

## 手順3: テンプレートの使用方法

1. WordPress管理画面で「固定ページ」→「新規追加」をクリック
2. ページタイトルを入力（例：「年代別分布データ」）
3. 右側のサイドバーで「ページ属性」の「テンプレート」から「年代別分布円グラフ」を選択
4. ページ下部に表示されるカスタムフィールドに各年代の人数を入力
   - 初期値：20代(25人)、30代(30人)、40代(20人)、50代(15人)、60代(10人)
5. 「公開」または「更新」ボタンをクリック
6. 作成したページにアクセスして確認

## カスタマイズ方法

### 色の変更

コード内の`backgroundColors`配列を編集することで、各セグメントの色を変更できます：

```javascript
const backgroundColors = [
    'rgba(255, 99, 132, 0.7)',  // 20代（ピンク）
    'rgba(54, 162, 235, 0.7)',  // 30代（青）
    'rgba(255, 206, 86, 0.7)',  // 40代（黄色）
    'rgba(75, 192, 192, 0.7)',  // 50代（緑）
    'rgba(153, 102, 255, 0.7)'  // 60代（紫）
];
```

## フォントサイズの変更
パーセント表示のフォントサイズを変更するには、以下の部分を編集します：
```javascript
// 数字の表示サイズ（初期値: 18px）
ctx.font = 'bold 18px Arial';

// パーセント記号のサイズ（初期値: 10px）
ctx.font = 'bold 10px Arial';
```

## グラフのサイズ変更
グラフのサイズを変更するには、.chart-containerのCSSを編集します：
```html
<div class="chart-container" style="position: relative; width: 100%; max-width: 500px; margin: 0 auto;">
```

## トラブルシューティング
グラフが表示されない場合

ブラウザのコンソールでエラーがないか確認してください
インターネット接続が有効で、CDNからChart.jsが読み込めることを確認してください
Smart Custom Fieldsの設定が正しいか確認してください

パーセント表示が見づらい場合
小さなセグメントの場合、パーセント表示が見づらくなることがあります。その場合は以下の値を調整してください：
```javascript
// 5%未満は表示しない設定（値を変更可能）
if (percentage < 5) return;
```