【WordPress財務データアプリ】詳細ページ作成

WordPress

前回は、アプリの検索ページを作成しました。

今回は、詳細ページを作成します。

概要

詳細ページには、大きく2つの機能があります。
1. 企業の財務データの表の作成
2. グラフの作成

グラフ

表

詳細ページのURLにはsecCodeというパラメーターを持たせ、各企業のページを表示可能にします。

財務データの表は、DBから対象のsecCodeのデータを取得し、表示します。
表示は見やすくするためにDataTable.jsを使いました。

グラフは、取得した財務データを折れ線もしくは棒グラフに表示できるようにしたものです。

どのデータをどうやって表示するか選択できるようにして、グラフを更新できるようにします。
グラフ部分はcanvasとchart.jsを使います。

全体のコード

検索ページと同様にして詳細ページを作成します。
詳細ページのIDは検索ページでも使っていますので、そちらに入力してください。(詳しくは前回の記事を確認してください)
また、IDは別途functions.phpでも使います。

ページテンプレート financial-data-detail.php

<?php
/*
Template Name: Financial Data Details
*/

if (isset($_GET['secCode'])) {
    global $wpdb;
    $secCode = sanitize_text_field($_GET['secCode']);

    // secCodeに基づく全データの取得
    $data = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}financial_data WHERE secCode = %s ORDER BY date DESC",
            $secCode
        )
    );
    // データをチェックして、存在する場合はJSONにエンコード
    if ($data) {
        // 全てのデータ行を配列に変換
        $chart_data = array_map(function($row) {
            $row_data = [];
            foreach ($row as $key => $value) {
                $row_data[$key] = $value;
            }
            return $row_data;
        }, $data);

        // JSON形式に変換
        $chart_data_json = json_encode($chart_data);

        // グローバル変数として設定
        $GLOBALS['chart_data_json'] = $chart_data_json;  // ここでグローバル変数に設定
    }
}

// データフィールドのリストを取得(最初のデータから)
$data_fields = !empty($data) ? array_keys(get_object_vars($data[0])) : [];
$exclude_fields = array('id', 'docID','date','secCode','filerName','EndDate');
$exclude_fields_tb = array('id', 'secCode','filerName');

// 除外項目を取り除く
$filtered_data_fields = array_filter($data_fields, function($field) use ($exclude_fields) {
    return !in_array($field, $exclude_fields);
});
$data_fields_tb = array_filter($data_fields, function($field) use ($exclude_fields_tb) {
    return !in_array($field, $exclude_fields_tb);
});

$million_fields = array('sales', 'gross_profit_loss', 'operating_income_loss', 'ordinary_income_loss', 'net_income_loss', 'parent_net_income_loss', 'operating_cf', 'investing_cf', 'financing_cf', 'assets', 'liabilities', 'current_assets', 'current_liabilities', 'net_assets', 'shareholders_equity', 'retained_earnings', 'short_term_debt', 'long_term_debt', 'corporate_taxes', 'sg_and_a', 'depreciation', 'interest_income_dividends', 'interest_expenses', 'shares_outstanding');

// 英語のフィールド名を日本語にマッピング
$field_labels = array(
    'docID' => 'docID',
    'date' => '提出日',
    'secCode' => '証券コード',
    'filerName' => '企業名',
    'EndDate' => '会計期間終了日',
    'sales' => '売上高(百万)',
    'gross_profit_loss' => '売上総利益(百万)',
    'operating_income_loss' => '営業利益(百万)',
    'ordinary_income_loss' => '経常利益(百万)',
    'net_income_loss' => '当期純利益(百万)',
    'parent_net_income_loss' => '親会社株主に帰属する当期純利益(百万)',
    'operating_cf' => '営業活動によるCF(百万)',
    'investing_cf' => '投資活動によるCF(百万)',
    'financing_cf' => '財務活動によるCF(百万)',
    'assets' => '資産(百万)',
    'liabilities' => '負債(百万)',
    'current_assets' => '流動資産(百万)',
    'current_liabilities' => '流動負債(百万)',
    'net_assets' => '純資産(百万)',
    'shareholders_equity' => '株主資本(百万)',
    'retained_earnings' => '利益剰余金(百万)',
    'short_term_debt' => '短期借入金(百万)',
    'long_term_debt' => '長期借入金(百万)',
    'corporate_taxes' => '法人税等(百万)',
    'sg_and_a' => '販管費(百万)',
    'depreciation' => '減価償却費(百万)',
    'interest_income_dividends' => '受取利息及び配当金(百万)',
    'interest_expenses' => '支払利息(百万)',
    'per' => '株価収益率',
    'shares_outstanding' => '発行済株式総数(百万)',
    'dividend_per_share' => '1株当たり配当額'
);
?>


<?php get_header(); ?>

<!-- DataTables CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css">

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- DataTables JS -->
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>


<div class="container">
    <?php if (!empty($data)): ?>
        <h1>Data for <?php echo esc_html($data[0]->filerName); ?> (<?php echo esc_html($secCode); ?>)</h1>

        <!-- チャート更新フォームとチャートを動的に生成 -->
        <?php 
        $chart_count = 4; // チャートの数
        $default_values = [
            1 => ['data_field' => 'sales', 'chart_type' => 'line'],
            2 => ['data_field' => 'gross_profit_loss', 'chart_type' => 'bar'],
            3 => ['data_field' => 'operating_income_loss', 'chart_type' => 'line'],
            4 => ['data_field' => 'net_income_loss', 'chart_type' => 'bar']
        ];
        ?>
        <div class="charts-container">
            <?php for ($i = 1; $i <= $chart_count; $i++): ?>
            <div class="chart-item">
                <!-- チャート更新フォーム -->
                <form class="chart-form" id="chartForm<?php echo $i; ?>">
                    <select name="data_field">
                        <?php foreach ($filtered_data_fields as $field): ?>
                            <option value="<?php echo esc_attr($field); ?>" <?php selected($default_values[$i]['data_field'], $field); ?>>
                                <?php echo esc_html(ucfirst(str_replace('_', ' ', $field))); ?>
                            </option>
                        <?php endforeach; ?>
                    </select>
                    <select name="chart_type">
                        <option value="line" <?php selected($default_values[$i]['chart_type'], 'line'); ?>>Line</option>
                        <option value="bar" <?php selected($default_values[$i]['chart_type'], 'bar'); ?>>Bar</option>
                    </select>
                    <button type="button" class="btn btn-cyan" onclick="updateChart('financialChart<?php echo $i; ?>')">Update Chart <?php echo $i; ?></button>
                </form>
                <canvas id="financialChart<?php echo $i; ?>"></canvas>
            </div>
            <?php endfor; ?>
        </div>





        <!-- 他のデータ表示 -->
        <div class="table-container">
            <button id="downloadCsvBtn" class="btn btn-cyan">Download CSV</button> <!-- CSVダウンロードボタンを追加 -->

            <table id="myDataTable"> <!-- ここでidを追加 -->
                <thead>
                    <tr>
                        <th>詳細データ</th> <!-- 「詳細データ」ボタンのための列を追加 -->
                        <?php foreach ($data_fields_tb as $field): ?>
                            <th><?php echo esc_html($field_labels[$field]); ?></th>
                        <?php endforeach; ?>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($data as $row): ?>
                        <tr>
                            <td>
                                <!-- 詳細データボタン -->
                                <a href="<?php echo esc_url(add_query_arg(array(
                                    'page_id' => 55,
                                    'doc_id'  => $row->docID
                                ), home_url())); ?>" class="btn btn-cyan" target="_blank">詳細データ</a>
                            </td>
                            <?php foreach ($data_fields_tb as $field): ?>
                                <td>
                                <?php 
                                // 数値データの場合
                                if (is_numeric($row->$field)) {
                                    // 100万単位に変換するフィールドかどうかをチェック
                                    if (in_array($field, $million_fields)) {
                                        // 100万単位に変換
                                        echo esc_html(number_format($row->$field / 1000000));
                                    } else {
                                        // 通常の数値フォーマット
                                        echo esc_html(number_format($row->$field));
                                    }
                                } else {
                                    // 数値でない場合はそのまま表示
                                    echo esc_html($row->$field);
                                }
                                ?>
                                </td>
                            <?php endforeach; ?>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>

        </div>


    <?php else: ?>
        <p>Data not found for the specified secCode.</p>
    <?php endif; ?>
</div>

<?php get_footer(); ?>

<style>


.chart-form select {
    font-size: 14px; /* フォントサイズを調整 */
    height: auto; /* 高さを自動に設定してテキストに合わせる */
    line-height: 1.5; /* 行の高さを設定してテキストが見やすくなるように調整 */
    padding: 5px; /* 内側の余白を設定 */
    border-radius: 4px; /* 角を丸くする */
    border: 1px solid #ccc; /* ボーダーのスタイルを設定 */
    box-sizing: border-box; /* ボーダーとパディングを含めたサイズを指定 */
    margin-right: 10px; /* 要素間の余白を設定 */
}

.chart-form select option {
    font-size: 14px; /* オプション要素のフォントサイズを調整 */
    padding: 5px; /* オプション要素の内側の余白を設定 */
}


.chart-form button {
    margin-right: 10px; /* 要素間の余白を設定 */
    font-size: 14px; /* フォントサイズを調整 */
    height: 30px; /* ボタンの高さを調整 */
    padding: 0 10px; /* ボタンの内側の余白を設定 */
    line-height: 30px; /* テキストの行の高さをボタンの高さに合わせる */

}



  .charts-container {
        display: grid;
        grid-template-columns: repeat(2, 1fr); /* デフォルトは2列 */
        gap: 20px; /* グリッド間のスペースを設定 */
    }

    /* 画面幅が768px未満の場合に1列に変更 */
    @media (max-width: 768px) {
        .charts-container {
            grid-template-columns: 1fr; /* 1列のグリッドレイアウト */
        }
    }

    .chart-item {
        display: flex;
        flex-direction: column;
        gap: 10px; /* フォームとキャンバス間のスペースを設定 */
    }

    .chart-form {
        display: flex;
        flex-direction: column;
        gap: 5px; /* フォーム内の要素間のスペースを設定 */
    }

    canvas {
        width: 100% !important; /* キャンバスを100%幅に設定 */
        height: auto !important; /* 高さを自動調整 */
    }



    .table-container {
        width: 100%;
        margin-bottom: 20px;
        overflow-x: auto;  /* 横スクロールを有効にする */
    }

    .dataTables_wrapper {
        width: 100%;
        overflow-x: auto;  /* DataTablesのラッパーで横スクロールを有効にする */
    }

    table.dataTable {
        width: 100%;
        margin: 0 auto; /* テーブルの中央配置 */
    }

    th, td {
        white-space: nowrap; /* テキストの折り返しを防ぐ */
    }


</style>
<script>
$(document).ready(function() {
    let table = $('#myDataTable').DataTable({
        "scrollY": "400px",  // 縦スクロールの最大高さ
        "scrollX": true,  // 横スクロールを有効にする
        "scrollCollapse": true,  // コンテンツが少ない場合にはスクロールを無効にする
        "paging": true,  // ページネーションを有効にする
        "searching": true,  // 検索ボックスを有効にする
        "ordering": true,  // ソートを有効にする
        "info": true  // テーブル情報を表示する
    });

    // CSVダウンロードボタンのクリックイベント
    $('#downloadCsvBtn').on('click', function(e) {
        e.preventDefault();

        // CSVデータの作成
        let csv = [];

        // 除外したい列のインデックス(0が1列目に相当)
        let excludeColumnIndex = 0;

        // テーブルヘッダーの取得(除外列を除く)
        let headers = table.columns().header().toArray().map((header, index) => {
            if (index !== excludeColumnIndex) {
                return '"' + $(header).text().replace(/"/g, '""') + '"';
            }
        }).filter(Boolean); // undefined を除外
        csv.push(headers.join(','));

        // テーブルデータの取得(除外列を除く)
        let data = table.rows().data().toArray();
        data.forEach(row => {
            let rowData = row.map((cell, index) => {
                if (index !== excludeColumnIndex) {
                    return '"' + cell.replace(/"/g, '""') + '"';
                }
            }).filter(Boolean); // undefined を除外
            csv.push(rowData.join(','));
        });

        // CSV文字列をBlobに変換
        let csvString = csv.join('\n');
        let blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });

        // ダウンロードリンクを作成してクリックイベントをトリガー
        let link = document.createElement('a');
        if (navigator.msSaveBlob) { // IE 10+
            navigator.msSaveBlob(blob, 'data.csv');
        } else {
            let url = URL.createObjectURL(blob);
            link.href = url;
            link.setAttribute('download', 'data.csv');
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
    });
});

</script>

グラフ表示部分は複雑なので、別のjsファイルにまとめ、function.phpで使えるようにします。
templateフォルダのjsフォルダかない場合は、フォルダを作成して、js/custom-ajax-script.jsを作成します。Cocoonの場合は、このファイルは、親テーマのjsフォルダに作成します。

custom-ajax-script.js

jQuery(document).ready(function($) {
    var charts = {};

    function createChart(chartId, labels, data, chartType, dataField) {
        const ctx = document.getElementById(chartId).getContext('2d');

        if (charts[chartId]) {
            charts[chartId].destroy();
        }

        charts[chartId] = new Chart(ctx, {
            type: chartType,
            data: {
                labels: labels,
                datasets: [{
                    label: dataField,
                    data: data,
                    borderColor: getChartColor(chartId),
                    fill: false
                }]
            },
            options: {
                responsive: true,
                scales: {
                    x: {
                        display: true,
                        title: {
                            display: true,
                            text: 'Date'
                        }
                    },
                    y: {
                        display: true,
                        title: {
                            display: true,
                            text: 'Amount'
                        }
                    }
                }
            }
        });
    }

    function getChartColor(chartId) {
        switch(chartId) {
            case 'financialChart1': return 'rgba(75, 192, 192, 1)';
            case 'financialChart2': return 'rgba(153, 102, 255, 1)';
            case 'financialChart3': return 'rgba(255, 159, 64, 1)';
            case 'financialChart4': return 'rgba(54, 162, 235, 1)';
            default: return 'rgba(0, 0, 0, 1)';
        }
    }

    function getFormData(formId) {
        const form = document.getElementById(formId);
        if (!form) {
            console.error("フォームが見つかりませんでした。");
            return null; // または適切なエラーハンドリング
        }
        return {
            dataField: form.querySelector('select[name="data_field"]').value,
            chartType: form.querySelector('select[name="chart_type"]').value
        };
    }

    function initializeCharts() {
        const chartData = JSON.parse(ajax_object.chart_data); // PHPから渡されたデータを使用
        const chartCount = 4; // チャートの数

        for (let i = 1; i <= chartCount; i++) {
            const chartId = `financialChart${i}`;
            const formId = `chartForm${i}`;
            const { dataField, chartType } = getFormData(formId);
            const data = chartData.map(item => item[dataField]);
            const labels = chartData.map(item => item.date);
            createChart(chartId, labels, data, chartType, dataField);
        }
    }

    // 初期チャートの描画
    initializeCharts();

    window.updateChart = function(chartId) {
        const formId = chartId.replace('financialChart', 'chartForm');
        const { dataField, chartType } = getFormData(formId);

        const chartData = JSON.parse(ajax_object.chart_data); // PHPから渡されたデータを使用
        const data = chartData.map(item => item[dataField]);
        const labels = chartData.map(item => item.date);

        createChart(chartId, labels, data, chartType, dataField);
    };
});

functions.phpに以下を追加します。
functions.php


function enqueue_custom_scripts() {
    if (is_page(21)) {
        wp_enqueue_script('jquery');
        wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js');

        wp_enqueue_script('custom-ajax-script', get_template_directory_uri() . '/js/custom-ajax-script.js', array('jquery'), null, true);

        // secCodeの取得
        $secCode = isset($_GET['secCode']) ? sanitize_text_field($_GET['secCode']) : '';

        if ($secCode) {
            global $wpdb;
            $secCode = sanitize_text_field($_GET['secCode']);

            // secCodeに基づく全データの取得
            $data = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT * FROM {$wpdb->prefix}financial_data WHERE secCode = %s ORDER BY date DESC",
                    $secCode
                )
            );
            // データをチェックして、存在する場合はJSONにエンコード
            if ($data) {
                // 全てのデータ行を配列に変換
                $chart_data = array_map(function($row) {
                    $row_data = [];
                    foreach ($row as $key => $value) {
                        $row_data[$key] = $value;
                    }
                    return $row_data;
                }, $data);

                // JSON形式に変換
                $chart_data_json = json_encode($chart_data);
                $GLOBALS['chart_data_json'] = $chart_data_json; 
            }

            // JavaScriptにデータを渡す
            wp_localize_script('custom-ajax-script', 'ajax_object', array(
                'ajax_url' => admin_url('admin-ajax.php'),
                'secCode' => $secCode,
                'chart_data' => isset($GLOBALS['chart_data_json']) ? $GLOBALS['chart_data_json'] : '[]'  
            ));
        }
    }
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');

financial-data-detail.phpの詳細

テンプレートの設定と初期処理

<?php
/*
Template Name: Financial Data Details
*/

if (isset($_GET['secCode'])) {
    global $wpdb;
    $secCode = sanitize_text_field($_GET['secCode']);
    ...
}
  • Template Name: Financial Data Details は、このファイルがWordPressテンプレートであることを示します。WordPress管理画面でページを編集する際に、このテンプレートを選択できます。
  • $_GET['secCode'] が設定されている場合、$secCode 変数にユーザーが入力した証券コードが格納されます。sanitize_text_field() 関数を使ってユーザー入力をサニタイズし、不正な入力から守ります。
  • global $wpdb; はWordPressのデータベースアクセスオブジェクト $wpdb を使用可能にします。

データベースからデータを取得

$data = $wpdb->get_results(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}financial_data WHERE secCode = %s ORDER BY date DESC",
        $secCode
    )
);
  • $wpdb->prepare() は安全にSQLクエリを構築するための関数です。ユーザーの入力をプレースホルダー(%s)として使用し、SQLインジェクションを防ぎます。
  • get_results() は、クエリを実行して複数の行をオブジェクトの配列として返します。
  • ORDER BY date DESC は日付順にデータを降順でソートします。

データの処理とJSONへのエンコード

if ($data) {
    $chart_data = array_map(function($row) {
        $row_data = [];
        foreach ($row as $key => $value) {
            $row_data[$key] = $value;
        }
        return $row_data;
    }, $data);

    $chart_data_json = json_encode($chart_data);
    $GLOBALS['chart_data_json'] = $chart_data_json;
}
  • $data が存在する場合に処理が行われます。
  • array_map() 関数で $data 内の各行を配列に変換し、チャート描画に使用するために $chart_data 配列を作成します。
  • json_encode() でデータをJSON形式に変換し、JavaScriptで使用できるようにします。
  • $GLOBALS['chart_data_json'] に変換したデータをグローバル変数として保存します。

データフィールドのフィルタリング

$data_fields = !empty($data) ? array_keys(get_object_vars($data[0])) : [];
$exclude_fields = array('id', 'docID','date','secCode','filerName','EndDate');
$filtered_data_fields = array_filter($data_fields, function($field) use ($exclude_fields) {
    return !in_array($field, $exclude_fields);
});
  • $data_fields はデータのフィールド名(カラム名)の配列です。
  • array_filter() を使って、除外フィールド(id, docIDなど)を取り除いたフィールドのリスト $filtered_data_fields を作成します。

英語のフィールド名を日本語にマッピング

$field_labels = array(
    'docID' => 'docID',
    'date' => '提出日',
    'secCode' => '証券コード',
    ...
);
  • $field_labels は、英語のフィールド名を日本語のラベルに変換するための連想配列です。これにより、表やチャートに表示されるフィールド名をわかりやすくします。

チャート生成フォームの構築

<div class="charts-container">
    <?php for ($i = 1; $i <= $chart_count; $i++): ?>
        <div class="chart-item">
            <form class="chart-form" id="chartForm<?php echo $i; ?>">
                <select name="data_field">
                    <?php foreach ($filtered_data_fields as $field): ?>
                        <option value="<?php echo esc_attr($field); ?>" <?php selected($default_values[$i]['data_field'], $field); ?>>
                            <?php echo esc_html(ucfirst(str_replace('_', ' ', $field))); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
                <select name="chart_type">
                    <option value="line" <?php selected($default_values[$i]['chart_type'], 'line'); ?>>Line</option>
                    <option value="bar" <?php selected($default_values[$i]['chart_type'], 'bar'); ?>>Bar</option>
                </select>
                <button type="button" class="btn btn-cyan" onclick="updateChart('financialChart<?php echo $i; ?>')">Update Chart <?php echo $i; ?></button>
            </form>
            <canvas id="financialChart<?php echo $i; ?>"></canvas>
        </div>
    <?php endfor; ?>
</div>
  • チャート生成フォームを表示するためのHTMLです。
  • for ループで複数のチャートを動的に生成します。
  • select 要素を使用して、ユーザーがデータフィールドやチャートタイプを選択できるようにします。

データのテーブル表示とCSVダウンロード

<table id="myDataTable">
    <thead>
        <tr>
            <th>詳細データ</th>
            <?php foreach ($data_fields_tb as $field): ?>
                <th><?php echo esc_html($field_labels[$field]); ?></th>
            <?php endforeach; ?>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($data as $row): ?>
            <tr>
                <td>
                    <a href="<?php echo esc_url(add_query_arg(array('page_id' => 55, 'doc_id'  => $row->docID), home_url())); ?>" class="btn btn-cyan" target="_blank">詳細データ</a>
                </td>
                <?php foreach ($data_fields_tb as $field): ?>
                    <td>
                        <?php
                        if (is_numeric($row->$field)) {
                            if (in_array($field, $million_fields)) {
                                echo esc_html(number_format($row->$field / 1000000));
                            } else {
                                echo esc_html(number_format($row->$field));
                            }
                        } else {
                            echo esc_html($row->$field);
                        }
                        ?>
                    </td>
                <?php endforeach; ?>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>
  • <table> タグを使用してデータを表形式で表示します。
  • 各行のデータを繰り返し表示し、特定のフィールドにはリンクを追加して詳細ページに移動できるようにしています。
  • 数値フィールドは、100万単位で変換するかどうかのチェックを行い、適切な形式で表示します。

JavaScriptとCSSによるページのスタイルと動作

<!-- DataTables CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css">

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- DataTables JS -->
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
  • DataTables ライブラリを使用して、データテーブルをインタラクティブにします。検索、ソート、ページネーションなどの機能が自動的に追加されます。

custom-ajax-script.jsの詳細

このコードは、JavaScriptとjQueryを使用して複数のチャートを描画・更新する機能を実装しています。

初期化と変数設定

jQuery(document).ready(function($) {
    var charts = {};
  • jQuery(document).ready(function($) {...});:
  • この部分は、DOM(HTML構造)が完全に読み込まれた後に実行される関数を定義しています。$は、jQueryのショートカットです。

  • var charts = {};:

  • chartsという空のオブジェクトを定義しています。ここには、作成されたチャートのインスタンスを格納します。

チャート作成関数

function createChart(chartId, labels, data, chartType, dataField) {
    const ctx = document.getElementById(chartId).getContext('2d');

    if (charts[chartId]) {
        charts[chartId].destroy();
    }

    charts[chartId] = new Chart(ctx, {
        type: chartType,
        data: {
            labels: labels,
            datasets: [{
                label: dataField,
                data: data,
                borderColor: getChartColor(chartId),
                fill: false
            }]
        },
        options: {
            responsive: true,
            scales: {
                x: {
                    display: true,
                    title: {
                        display: true,
                        text: 'Date'
                    }
                },
                y: {
                    display: true,
                    title: {
                        display: true,
                        text: 'Amount'
                    }
                }
            }
        }
    });
}
  • function createChart(chartId, labels, data, chartType, dataField):
  • チャートを作成する関数です。引数として、チャートのID、ラベル、データ、チャートのタイプ、データのフィールド名を受け取ります。

  • const ctx = document.getElementById(chartId).getContext('2d');:

  • 指定されたIDの<canvas>要素を取得し、そのコンテキスト(描画用のコンテキスト)を取得します。

  • if (charts[chartId]) { charts[chartId].destroy(); }:

  • もしすでに指定されたIDのチャートが存在する場合、そのチャートを破棄して新しいチャートを作成します。

  • charts[chartId] = new Chart(ctx, {...});:

  • Chart.jsライブラリを使用して新しいチャートを作成し、chartsオブジェクトに格納します。

チャートの色を決定する関数

function getChartColor(chartId) {
    switch(chartId) {
        case 'financialChart1': return 'rgba(75, 192, 192, 1)';
        case 'financialChart2': return 'rgba(153, 102, 255, 1)';
        case 'financialChart3': return 'rgba(255, 159, 64, 1)';
        case 'financialChart4': return 'rgba(54, 162, 235, 1)';
        default: return 'rgba(0, 0, 0, 1)';
    }
}
  • function getChartColor(chartId):
  • チャートのIDに基づいてチャートの線の色を決定します。switch文を使って、IDに応じた色を返します。

フォームデータ取得関数

function getFormData(formId) {
    const form = document.getElementById(formId);
    if (!form) {
        console.error("フォームが見つかりませんでした。");
        return null; // または適切なエラーハンドリング
    }
    return {
        dataField: form.querySelector('select[name="data_field"]').value,
        chartType: form.querySelector('select[name="chart_type"]').value
    };
}
  • function getFormData(formId):
  • フォームのIDを指定して、そのフォームからデータを取得する関数です。指定されたIDのフォームが見つからない場合はエラーメッセージを表示します。

  • form.querySelector('select[name="data_field"]').value:

  • フォーム内のdata_fieldという名前の<select>要素から選択された値を取得します。

  • form.querySelector('select[name="chart_type"]').value:

  • フォーム内のchart_typeという名前の<select>要素から選択された値を取得します。

チャートの初期化

function initializeCharts() {
    const chartData = JSON.parse(ajax_object.chart_data); // PHPから渡されたデータを使用
    const chartCount = 4; // チャートの数

    for (let i = 1; i <= chartCount; i++) {
        const chartId = `financialChart${i}`;
        const formId = `chartForm${i}`;
        const { dataField, chartType } = getFormData(formId);
        const data = chartData.map(item => item[dataField]);
        const labels = chartData.map(item => item.date);
        createChart(chartId, labels, data, chartType, dataField);
    }
}
  • function initializeCharts():
  • すべてのチャートを初期化する関数です。

  • const chartData = JSON.parse(ajax_object.chart_data);:

  • PHPから渡されたJSONデータを解析してchartDataに格納します。

  • for (let i = 1; i <= chartCount; i++) {...}:

  • ループを使って、指定された数のチャートを作成します。ここでは4つのチャートを作成する設定になっています。

  • const { dataField, chartType } = getFormData(formId);:

  • フォームからチャートのデータフィールドとタイプを取得します。

  • const data = chartData.map(item => item[dataField]);:

  • データフィールドに基づいて、チャートに表示するデータを抽出します。

  • const labels = chartData.map(item => item.date);:

  • データのラベルとして、日付を抽出します。

  • createChart(chartId, labels, data, chartType, dataField);:

  • 取得したデータを使ってチャートを作成します。

チャートの更新

window.updateChart = function(chartId) {
    const formId = chartId.replace('financialChart', 'chartForm');
    const { dataField, chartType } = getFormData(formId);

    const chartData = JSON.parse(ajax_object.chart_data); // PHPから渡されたデータを使用
    const data = chartData.map(item => item[dataField]);
    const labels = chartData.map(item => item.date);

    createChart(chartId, labels, data, chartType, dataField);
};
  • window.updateChart = function(chartId) {...}:
  • チャートを更新する関数をwindowオブジェクトに追加しています。この関数は指定されたチャートIDを使ってチャートを再描画します。

  • const formId = chartId.replace('financialChart', 'chartForm');:

  • チャートIDから対応するフォームIDを生成します。

  • const { dataField, chartType } = getFormData(formId);:

  • フォームから最新のデータフィールドとチャートタイプを取得します。

  • createChart(chartId, labels, data, chartType, dataField);:

  • 新しいデータでチャートを再作成します。

このコード全体の流れとしては、まず初期化関数で最初にチャートを描画し、次に必要に応じてチャートを更新する関数を用意しています。フォームからの入力に応じて、チャートの表示内容やスタイルを変更することができます。

functions.phpの詳細

このコードは、サーバーサイドからデータを取得してJavaScriptに渡す機能を実装しています。

スクリプトのエンキュー

function enqueue_custom_scripts() {
    if (is_page(21)) {
        wp_enqueue_script('jquery');
        wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js');

        wp_enqueue_script('custom-ajax-script', get_template_directory_uri() . '/js/custom-ajax-script.js', array('jquery'), null, true);
  • function enqueue_custom_scripts():
  • この関数は、WordPressでカスタムスクリプトをエンキュー(読み込む)するために使用します。

  • if (is_page(21)):

  • ページIDが21のページでのみスクリプトをエンキューします。この条件が満たされると、以下のスクリプトが読み込まれます。この数字は詳細ページのIDに変更してください。(ほかのページで不用意に処理が走らないようにしています)

  • wp_enqueue_script('jquery');:

  • jQueryライブラリをエンキューします。WordPressの標準機能で、必要なスクリプトを追加します。

  • wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js');:

  • Chart.jsライブラリをCDNから読み込みます。これにより、グラフやチャートを作成するための機能が使えるようになります。

  • wp_enqueue_script('custom-ajax-script', get_template_directory_uri() . '/js/custom-ajax-script.js', array('jquery'), null, true);:

  • カスタムのJavaScriptファイル(custom-ajax-script.js)をエンキューします。このスクリプトは、jQueryに依存していることを示すため、array('jquery')を指定しています。trueは、スクリプトをフッターで読み込むことを意味します。

データの取得と加工

        // secCodeの取得
        $secCode = isset($_GET['secCode']) ? sanitize_text_field($_GET['secCode']) : '';

        if ($secCode) {
            global $wpdb;
            $secCode = sanitize_text_field($_GET['secCode']);

            // secCodeに基づく全データの取得
            $data = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT * FROM {$wpdb->prefix}financial_data WHERE secCode = %s ORDER BY date DESC",
                    $secCode
                )
            );
            // データをチェックして、存在する場合はJSONにエンコード
            if ($data) {
                // 全てのデータ行を配列に変換
                $chart_data = array_map(function($row) {
                    $row_data = [];
                    foreach ($row as $key => $value) {
                        $row_data[$key] = $value;
                    }
                    return $row_data;
                }, $data);

                // JSON形式に変換
                $chart_data_json = json_encode($chart_data);
                $GLOBALS['chart_data_json'] = $chart_data_json; 
            }
  • // secCodeの取得:
  • URLのクエリパラメータからsecCodeを取得し、サニタイズして安全な文字列にします。

  • if ($secCode) {...}:

  • secCodeが存在する場合にのみ、以下の処理を実行します。

  • global $wpdb;:

  • WordPressのデータベース操作用グローバルオブジェクト$wpdbを使用します。

  • $data = $wpdb->get_results(...);:

  • secCodeに基づいてデータベースからデータを取得します。$wpdb->prepareを使ってSQLクエリを安全に実行しています。

  • if ($data) {...}:

  • データが存在する場合、データを配列に変換し、JSON形式にエンコードします。

データをJavaScriptに渡す

            // JavaScriptにデータを渡す
            wp_localize_script('custom-ajax-script', 'ajax_object', array(
                'ajax_url' => admin_url('admin-ajax.php'),
                'secCode' => $secCode,
                'chart_data' => isset($GLOBALS['chart_data_json']) ? $GLOBALS['chart_data_json'] : '[]'  
            ));
        }
    }
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');
  • wp_localize_script('custom-ajax-script', 'ajax_object', array(...));:
  • wp_localize_scriptは、custom-ajax-script.jsファイルにPHPからデータを渡すために使用します。この関数を使って、ajax_objectという名前でJavaScriptのオブジェクトを定義し、以下のデータを渡しています。

    • ajax_url:AJAXリクエストのURL
    • secCode:現在のsecCode
    • chart_data:JSON形式のチャートデータ
  • add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');:

  • wp_enqueue_scriptsアクションにenqueue_custom_scripts関数をフックして、WordPressのスクリプトキューにこの関数を追加します。これにより、ページがロードされるときにスクリプトがエンキューされるようになります。

このコードは、指定されたページID(21)のページで、必要なJavaScriptライブラリやカスタムスクリプトをエンキューし、データベースからデータを取得してJSON形式でJavaScriptに渡す仕組みを実装しています。IDは必要に応じて変更してください。

次回

これで詳細ページが完成しました。
次回は、ダウンロードページを作成します。

タイトルとURLをコピーしました