前回は、アプリの検索ページを作成しました。
今回は、詳細ページを作成します。
概要
詳細ページには、大きく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リクエストのURLsecCode
:現在の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は必要に応じて変更してください。
次回
これで詳細ページが完成しました。
次回は、ダウンロードページを作成します。