要望や症状
商品詳細ページで獲得予定ポイントを表示したいケースがあります。
理由や原因
EC-CUBE 4系の標準仕様では、商品詳細ページで獲得予定ポイントを表示する機能が実装されていません。 コントローラーからテンプレートに対してポイント計算結果が渡されていないため、テンプレートを編集するだけでは正確なポイント表示をすることができません。
ポイント機能は、実際の購入完了後にのみポイントが計算され付与される仕組みとなっており、商品詳細ページにポイント情報を表示するには、独自カスタマイズが必要です。
解決策
EC-CUBEの商品詳細ページでは、SKU(商品規格)の選択によって価格が動的に変更されるため、Ajax APIを活用したリアルタイム計算方式がオススメです。
ポイント計算API の作成
1. SKUポイント計算サービスの作成
最初に、SKUごとのポイント計算を行うサービスクラスを作成します。
<?php
// app/Customize/Service/PointCalculationService.php
namespace Customize\Service;
use Eccube\Entity\ProductClass;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\PointInfoRepository;
class PointCalculationService
{
private $baseInfoRepository;
private $pointInfoRepository;
public function __construct(
BaseInfoRepository $baseInfoRepository,
PointInfoRepository $pointInfoRepository
) {
$this->baseInfoRepository = $baseInfoRepository;
$this->pointInfoRepository = $pointInfoRepository;
}
/**
* 商品規格からポイントを計算
*/
public function calculatePoint(ProductClass $productClass, int $quantity = 1): int
{
$baseInfo = $this->baseInfoRepository->get();
$pointInfo = $this->pointInfoRepository->getLastInsertData();
if (!$pointInfo || !$pointInfo->getPlgPointStatus()) {
return 0;
}
$price = $productClass->getPrice02IncTax();
$pointRate = $pointInfo->getPlgBasicPointRate();
return floor($price * $quantity * $pointRate / 100);
}
}
2. コントローラーの作成
次に、Ajax リクエストを受け取ってポイント計算結果を返すAPIコントローラーを作成します。
<?php
// app/Customize/Controller/Api/PointApiController.php
namespace Customize\Controller\Api;
use Eccube\Controller\AbstractController;
use Eccube\Repository\ProductClassRepository;
use Customize\Service\PointCalculationService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class PointApiController extends AbstractController
{
private $productClassRepository;
private $pointCalculationService;
public function __construct(
ProductClassRepository $productClassRepository,
PointCalculationService $pointCalculationService
) {
$this->productClassRepository = $productClassRepository;
$this->pointCalculationService = $pointCalculationService;
}
/**
* @Route("/api/point/calculate", name="api_point_calculate", methods={"POST"})
*/
public function calculate(Request $request): JsonResponse
{
$productClassId = $request->request->get('product_class_id');
$quantity = (int) $request->request->get('quantity', 1);
if (!$productClassId) {
return new JsonResponse(['error' => 'product_class_id is required'], 400);
}
$productClass = $this->productClassRepository->find($productClassId);
if (!$productClass) {
return new JsonResponse(['error' => 'ProductClass not found'], 404);
}
$point = $this->pointCalculationService->calculatePoint($productClass, $quantity);
return new JsonResponse([
'point' => $point,
'formatted_point' => number_format($point) . 'pt'
]);
}
}
3. Twigテンプレートの更新
商品詳細ページのテンプレートにポイント表示領域とJavaScriptを追加します。
{# templates/Product/detail.twig の適切な箇所に追加 #}
{# ポイント表示エリア #}
<div class="ec-productRole__btn">
<div id="point-display" class="ec-productRole__point" style="margin-bottom: 10px;">
<span class="point-label">獲得予定ポイント:</span>
<span id="point-value" class="point-value">-</span>
</div>
<button type="button" class="ec-blockBtn--action add-cart" data-cartid="{{ Product.id }}" form="form1" {{ csrf_token_for_anchor() }}>
カートに入れる
</button>
</div>
{# JavaScript #}
<script>
$(document).ready(function() {
// 初期ポイント計算
calculatePoint();
// 規格選択時のイベント
$('select[name="classcategory_id1"], select[name="classcategory_id2"]').on('change', function() {
calculatePoint();
});
// 数量変更時のイベント
$('.quantity').on('change keyup', function() {
calculatePoint();
});
function calculatePoint() {
var productClassId = $('input[name="product_class_id"]').val();
var quantity = parseInt($('.quantity').val()) || 1;
if (!productClassId) {
$('#point-value').text('-');
return;
}
$.ajax({
url: '{{ url("api_point_calculate") }}',
type: 'POST',
data: {
product_class_id: productClassId,
quantity: quantity,
_token: $('meta[name="eccube-csrf-token"]').attr('content')
},
success: function(data) {
if (data.formatted_point) {
$('#point-value').text(data.formatted_point);
} else {
$('#point-value').text('0pt');
}
},
error: function() {
$('#point-value').text('-');
}
});
}
});
</script>
4. サービスの登録
作成したサービスをDIコンテナに登録します。
# app/config/services_customize.yaml
services:
Customize\Service\PointCalculationService:
arguments:
- '@Eccube\Repository\BaseInfoRepository'
- '@Plugin\Point\Repository\PointInfoRepository'
実装のポイント
このカスタマイズでは、商品規格の選択や数量の変更に応じてリアルタイムでポイント計算を行います。Ajax APIを使用することで、ページの再読み込みなしにスムーズなユーザー体験を提供できます。
ポイント計算は実際のプラグインの計算ロジックに合わせて調整が必要な場合があります。使用されているポイントプラグインの仕様を確認して、適切な計算式を実装してください。