Skip to content

Organization, Websiteのマークアップを追加 - #6139

Merged
dotani1111 merged 9 commits into
EC-CUBE:4.4from
tao-s:json-ld-org
Aug 7, 2026
Merged

Organization, Websiteのマークアップを追加#6139
dotani1111 merged 9 commits into
EC-CUBE:4.4from
tao-s:json-ld-org

Conversation

@tao-s

@tao-s tao-s commented Apr 11, 2024

Copy link
Copy Markdown
Contributor

概要(Overview・Refs Issue)

#6136 店舗情報などの基本的な構造化データの拡充

サイト全体共通のJSON-LDのマークアップを追加

方針(Policy)

Googleが推奨するプロパティを可能な限り追加

実装に関する補足(Appendix)

現状のEC-CUBEからは取得できない情報はコメントアウトしてあります

テスト(Test)

リッチリザルトテストで確認済み
スクリーンショット 2024-04-11 9 30 15

相談(Discussion)

会社情報やショップの稼働開始日、最終更新日時など現状では取得できないプロパティに関して店舗設定などに追加するかどうかを相談したいです。

マイナーバージョン互換性保持のための制限事項チェックリスト

  • 既存機能の仕様変更はありません
  • フックポイントの呼び出しタイミングの変更はありません
  • フックポイントのパラメータの削除・データ型の変更はありません
  • twigファイルに渡しているパラメータの削除・データ型の変更はありません
  • Serviceクラスの公開関数の、引数の削除・データ型の変更はありません
  • 入出力ファイル(CSVなど)のフォーマット変更はありません

レビュワー確認項目

  • 動作確認
  • コードレビュー
  • E2E/Unit テスト確認(テストの追加・変更が必要かどうか)
  • 互換性が保持されているか
  • セキュリティ上の問題がないか
    • 権限を超えた操作が可能にならないか
    • 不要なファイルアップロードがないか
    • 外部へ公開されるファイルや機能の追加ではないか
    • テンプレートでのエスケープ漏れがないか

Summary by CodeRabbit

  • 新機能
    • トップページと「当サイトについて」に、サイト名・URL・検索機能・運営者情報を含む構造化データ(JSON-LD)を追加しました。
    • ロゴ、連絡先、住所、請求書登録番号など、設定済みの情報を検索エンジン向けに提供します。
  • 改善
    • 商品説明の構造化データにおけるHTML除去、空白整理、文字数制限を統一しました。
  • テスト
    • JSON-LDの生成内容、任意項目の省略、対象ページでの出力条件を検証するテストを追加しました。

@tao-s tao-s changed the title ref: #6136 Organization, Websiteのマークアップを追加 Organization, Websiteのマークアップを追加 Apr 11, 2024
@codecov

codecov Bot commented Apr 11, 2024

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.11765% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.22%. Comparing base (aafc564) to head (5985f08).
⚠️ Report is 50 commits behind head on 4.4.

Files with missing lines Patch % Lines
src/Eccube/Service/SiteStructuredDataService.php 92.78% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              4.4    #6139      +/-   ##
==========================================
+ Coverage   77.21%   77.22%   +0.01%     
==========================================
  Files         563      566       +3     
  Lines       28111    28193      +82     
==========================================
+ Hits        21705    21772      +67     
- Misses       6406     6421      +15     
Flag Coverage Δ
Unit 77.22% <94.11%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ikeike9o9o ikeike9o9o added this to the 4.3.x milestone Apr 15, 2024
@ikeike9o9o

ikeike9o9o commented Apr 15, 2024

Copy link
Copy Markdown
Contributor

@tao-s
ありがとうございます。動作確認して、マージします。

@tao-s

tao-s commented Apr 17, 2024

Copy link
Copy Markdown
Contributor Author

ref: #6147

@ttokoro20240902
ttokoro20240902 changed the base branch from 4.3 to 4.4 July 22, 2026 02:07
Copilot AI lite review requested due to automatic review settings July 22, 2026 02:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

BaseInfo から WebSite と Organization の JSON-LD を生成するサービスを追加しました。対象ルートで Twig グローバルに登録し、既定フレームから JSON-LD script として出力します。説明文の正規化処理も共通化しました。

Changes

構造化データ出力

Layer / File(s) Summary
説明文の正規化
src/Eccube/Service/StructuredDataDescriptionTrait.php, src/Eccube/Service/ProductStructuredDataService.php
説明文の HTML、空白、前後空白を正規化し、最大300文字に制限する処理を共通化しました。商品構造化データサービスがこの処理を使用します。
JSON-LD 生成と検証
src/Eccube/Service/SiteStructuredDataService.php, tests/Eccube/Tests/Service/SiteStructuredDataServiceTest.php
BaseInfo から WebSite、Organization、検索アクション、住所、連絡先、ロゴ、iso6523Code を条件付きで生成します。URL形式、空値、省略項目をテストします。
Twig への登録と出力
src/Eccube/EventListener/TwigInitializeListener.php, src/Eccube/Resource/template/default/default_frame.twig, tests/Eccube/Tests/Web/SiteStructuredDataOutputTest.php
homepagehelp_about で JSON-LD を Twig グローバルに登録します。既定フレームは値がある場合に application/ld+json を出力します。対象ルートと非対象ルートをテストします。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant TwigInitializeListener
  participant SiteStructuredDataService
  participant default_frame.twig
  participant Browser
  Request->>TwigInitializeListener: フロント変数を初期化
  TwigInitializeListener->>SiteStructuredDataService: createWebSiteJsonLd()
  SiteStructuredDataService-->>TwigInitializeListener: site_json_ld
  TwigInitializeListener->>default_frame.twig: Twigグローバルを登録
  default_frame.twig-->>Browser: JSON-LD scriptを出力
Loading

Possibly related PRs

  • EC-CUBE/ec-cube#6883: 商品構造化データと Twig の json_ld 出力に関連します。
  • EC-CUBE/ec-cube#6957: SiteStructuredDataServiceTwigInitializeListener、既定フレームを拡張する変更に関連します。
  • EC-CUBE/ec-cube#6980: Twig から JSON-LD を出力する構造化データ追加に関連します。

Suggested reviewers: copilot, nanasess

Poem

ぴょんと跳ねたら JSON-LD、
WebSite と店名を記録。
Organization が住所を示し、
Twig がページへ届ける。
うさぎも変更を祝います。 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルはOrganizationとWebSiteのマークアップ追加という主要な変更内容を明確に示しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ttokoro20240902

Copy link
Copy Markdown
Contributor

メンテナ作業として、マージに向けて本PRを更新しました(maintainerCanModify 有効のため fork ブランチへ直接反映)。

変更点

  1. base を 4.3 → 4.4 に変更

  2. 不具合修正を追加fix(schema): ...

    • Schema/organization.twigaddressRegionBaseInfo.Pref.name を無ガード参照しており、店舗設定で都道府県が未選択(pref_id が null)の場合に全フロントページが 500 になっていました(Impossible to access an attribute ("name") on a null variable)。デフォルトインストール状態で再現します。
    • Pref は nullable な FK のため、null 合体演算子でガードし未設定時は空文字を出力するよう修正(他の任意項目と同挙動)。

ローカル検証(Docker / PostgreSQL)

sameAs・営業時間・稼働開始日など現状の店舗設定で取得できない項目はコメントアウトのままです(#6147 の残タスクとして BaseInfo 拡張時に対応)。

Refs #6136 #6147

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/Eccube/Resource/template/default/Schema/website.twig (1)

8-14: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

廃止済みのSearchAction出力を見直してください。

Googleのサイトリンク検索ボックスは2024年11月21日に終了し、現在はRich Results TestやSearch Consoleでもサポートされていません。WebSitename/urlは残しつつ、Google向けだけであればpotentialActionは削除するのが適切です。 (developers.google.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Eccube/Resource/template/default/Schema/website.twig` around lines 8 -
14, Remove the obsolete potentialAction SearchAction block from the WebSite
structured-data markup in the website template, while preserving the existing
WebSite name and url fields.
src/Eccube/Resource/template/default/default_frame.twig (1)

190-192: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

WebSite/Organizationの出力をホームページに限定してください。

default_frame.twigは共通フレームのため、Line 190-192 はこれを継承する全ページへ出力されます。Googleのサイト名用WebSite構造化データはホームページに配置する必要があり、全ページへの出力は不要です。ホームページ専用テンプレートへ移すか、実際のホームページルートで条件分岐してください。 (developers.google.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Eccube/Resource/template/default/default_frame.twig` around lines 190 -
192,
default_frame.twigの共通フレームにあるWebSite/Organization構造化データ出力を削除し、ホームページ専用テンプレートへ移すか、ホームページのルートでのみ実行される条件分岐を追加してください。Schema/website.twigの内容がサイト内の全ページへ出力されないようにしてください。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Eccube/Resource/template/default/Schema/organization.twig`:
- Around line 4-27: Replace the interpolated JSON-LD values in organization.twig
with a single object passed through the existing json_ld filter, preserving the
current Organization properties and structure. Apply the same json_ld-based
output to website.twig, including its author value, so both templates use the
shared escaping path; update
src/Eccube/Resource/template/default/Schema/organization.twig lines 4-27 and
src/Eccube/Resource/template/default/Schema/website.twig lines 4-7 accordingly.

---

Nitpick comments:
In `@src/Eccube/Resource/template/default/default_frame.twig`:
- Around line 190-192:
default_frame.twigの共通フレームにあるWebSite/Organization構造化データ出力を削除し、ホームページ専用テンプレートへ移すか、ホームページのルートでのみ実行される条件分岐を追加してください。Schema/website.twigの内容がサイト内の全ページへ出力されないようにしてください。

In `@src/Eccube/Resource/template/default/Schema/website.twig`:
- Around line 8-14: Remove the obsolete potentialAction SearchAction block from
the WebSite structured-data markup in the website template, while preserving the
existing WebSite name and url fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88556e13-120f-4cb7-af24-011ff4cc43ac

📥 Commits

Reviewing files that changed from the base of the PR and between b978d3a and b36d6a5.

📒 Files selected for processing (3)
  • src/Eccube/Resource/template/default/Schema/organization.twig
  • src/Eccube/Resource/template/default/Schema/website.twig
  • src/Eccube/Resource/template/default/default_frame.twig

Comment thread src/Eccube/Resource/template/default/Schema/organization.twig Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 02:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Eccube/Service/SiteStructuredDataService.php`:
- Around line 107-109: Update the invoice registration number check in
SiteStructuredDataService so both null and empty-string values are excluded
before assigning data['iso6523Code']; preserve the existing 0221: prefix for
non-empty values and add a regression test covering an empty registration
number.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c2495ce0-3531-40ed-93c6-acdb75b76b27

📥 Commits

Reviewing files that changed from the base of the PR and between b36d6a5 and 8efe90a.

📒 Files selected for processing (4)
  • src/Eccube/EventListener/TwigInitializeListener.php
  • src/Eccube/Resource/template/default/default_frame.twig
  • src/Eccube/Service/SiteStructuredDataService.php
  • tests/Eccube/Tests/Service/SiteStructuredDataServiceTest.php

Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Organization / WebSite の JSON-LD をテンプレートの文字列補間で組み立てていたため、
店名等に " や </script> が含まれると構造化データが壊れる/XSS 経路になりうる問題があった
(CodeRabbit 指摘)。EC-CUBE#6883 で導入済みの json_ld フィルタ(JSON_HEX_* でエスケープ)に揃える。

- SiteStructuredDataService を新設し WebSite / Organization の連想配列を組み立て
- TwigInitializeListener で site_json_ld を front グローバルに注入
- default_frame.twig は {{ site_json_ld|json_ld }} で出力
- 旧 Schema/organization.twig・website.twig を削除
- 値が空の任意プロパティは出力しない(ProductStructuredDataService と同方針)
- 都道府県未設定(Pref=null)でもフロントが 500 にならない(元 PR の不具合も解消)
- SiteStructuredDataServiceTest を追加

出力される JSON-LD は、値のある項目については従来と同一
(空の任意プロパティが省略される点のみ差分)。

Refs EC-CUBE#6136 EC-CUBE#6147

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 22, 2026 02:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@ttokoro20240902

Copy link
Copy Markdown
Contributor

CodeRabbit の指摘(iso6523Code の空文字チェック漏れ)に対応しました(commit 2c79b6b)。

  • SiteStructuredDataService の適格請求書登録番号の判定を !== null から !== null && !== '' に変更し、空文字保存時に iso6523Code: "0221:" が出力されないようにしました(他の任意プロパティと同じ空判定に統一)。
  • 空文字ケースの回帰テスト testEmptyInvoiceRegistrationNumberIsOmitted を追加。

ローカル QA: php-cs-fixer 0 / phpstan(level6) No errors / phpunit 6 tests 20 assertions OK

Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Packages::getUrl() はルート相対パス(/html/user_data/...)を返すため,
logo.contentUrl が相対パスのまま JSON-LD に出力されていた.
ProductStructuredDataService の画像URLと同様に絶対URLへ揃える.

- generateAbsoluteAssetUrl() を追加し, ルーティングコンテキストの
  スキーム込みホストを前置する(base_urls 設定済みで既に絶対URLならそのまま)
- logo.contentUrl が絶対URLであることを検証するテストを追加

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 29, 2026 01:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@nanasess nanasess left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュー: サイト共通の構造化データ(WebSite / Organization)

差分(4 files / +349 -1)を読み、SiteStructuredDataService が出力する各プロパティを BaseInfo の実際の格納値・フォーム制約と突き合わせて確認しました。あわせて Google の Organization 構造化データのドキュメントと Peppol の ISO 6523 ICD リストを参照しています。

Service への切り出し・json_ld フィルタ経由の出力・空値の省略方針は ProductStructuredDataService と揃っていて、方向性は良いと思います。テストも配列を直接アサートできる形になっていて読みやすいです。

一方で、出力される値そのものに確認したい点がいくつかありました。

マージ前に対応したい点

  • telephone+81- を無条件で前置しているため +81-0312345678 になります。PhoneNumberType の制約上、電話番号を設定した国内店舗はほぼ全てこの値です。国番号は必須ではないので、保存値をそのまま出す形を提案します。→ [1]
  • Organization.emailemail01(送信元メールアドレス / 全送信メールの BCC 先)を出力している。公開する連絡先としては email02(問い合わせ専用)が妥当だと考えます。→ [2]

相談したい点

  • logofavicon.ico(ICO 形式・既定は EC-CUBE のアイコン)から、ファイル管理でアップロードする user_data/assets/img/common/logo.png に変える案。未設定なら logo を出力しない形です。→ [3]
  • Organization を全フロントページに出す是非(Google は「every page に入れる必要はない」としています)。→ [4]
  • WebSite.author ではなく publisher / @graph にする案。→ [5]

既定インストールの状態について

動作確認の前提として共有です。インストーラが dtb_base_info に設定するのは shop_nameemail01email04 だけ(src/Eccube/Controller/Install/InstallController.php:853-865)で、phone_number / postal_code / addr01 / addr02 / pref_id / company_name / good_traded / messageNULL のまま です。

そのため素の環境では telephoneaddress が一切出力されず、CI でもこの経路は通っていません(Codecov の 8 lines missing)。リッチリザルトテストで確認する際は、店舗設定に値を入れた状態でお願いします。

確認して問題がなかった点

  • json_ld フィルタ(JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT)経由の出力なので、店舗設定の値に </script>" が入っても JSON 破壊・XSS にはなりません。
  • iso6523Code0221: は Peppol の ISO 6523 ICD リスト上「The registered number of the qualified invoice issuer (Japan)」(発行機関: 国税庁)で、T 付きの適格請求書発行事業者登録番号をそのまま入れる用途として正しいです。
  • FilemtimeVersionStrategy はファイル不在時に例外を投げず空バージョンを返すため、logo.contentUrl の生成で 500 になることはありません。
  • getPref()?->getName() の null 安全化により、PR コメントで報告されていた「都道府県未設定で全フロントページが 500」は解消されています。
  • preview 時は setFrontVariables() が早期 return するため site_json_ld グローバルが未定義になりますが、テンプレート側が is defined でガードしているので問題ありません。

CI は全ジョブ green(PHPUnit 8.5/pgsql・PHPStan・php-cs-fixer・E2E・plugin-test)、Codecov patch coverage は 89.74%(8 lines missing)です。

@ttokoro20240902 ご確認をお願いします。

Comment thread src/Eccube/Service/SiteStructuredDataService.php
Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread src/Eccube/Resource/template/default/default_frame.twig
Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread tests/Eccube/Tests/Service/SiteStructuredDataServiceTest.php
Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread src/Eccube/Service/SiteStructuredDataService.php
Comment thread src/Eccube/EventListener/TwigInitializeListener.php Outdated
@ttokoro20240902

Copy link
Copy Markdown
Contributor

@nanasess 詳細なレビューをありがとうございます。全 11 件を実コードと突き合わせて確認しました。対応方針をまとめます。

まず前提の共有です。本 PR と同じ SiteStructuredDataService私の #6957 も新規追加してしまっていました(出力項目は本 PR の上位集合で sameAs / foundingDate / numberOfEmployees / openingHoursSpecification が増えているだけ)。サイト共通の構造化データについてのレビューは本 PR に蓄積されているので、#6957 を draft に戻し、本 PR を先に仕上げてから #6957 を「既存サービスへの差分」に作り直す方針にしました。二重レビューをお願いしてしまい申し訳ありません。

対応する(8 件)

指摘 対応
[1] +81- の無条件前置 修正します。 94 行と 147 行の 2 箇所にあり、ご指摘のとおり PhoneNumberType の制約で保存値は 0312345678 なので +81- は付けず保存値をそのまま出力します
[2] emailemail01 修正します。 From かつ全メールの BCC 先である項目を全ページで公開するのは避けます
[3] logo がファビコン 差し替える方向で対応します。差し替え先について別途スレッドで確認させてください(ご提案の assets/pdf/logo.png は店頭テンプレート配下に存在せず、実体が帳票 PDF 用のため)
[6] telephone のテスト 追加します。 [1] のフォーマットを固定する意味でも必要ですね。既定インストールで phone_number が NULL のため未実行だったという分析もそのとおりでした
[7] description の無加工 修正します。 ProductStructuredDataService::buildDescription()strip_tags → 空白正規化 → 300 文字丸めを共通化して同じ扱いにします
[8] contactType なし 追加します。 参照先が email02(問い合わせ専用)と contact ルートなので用途は確定しています
[9] プロトコル相対URL 修正します。 181 行の早期 return から // を外し、スキームを補って絶対URLに寄せます
logo の絶対URL(@dotani1111 ba23dae4 で対応済みです。testLogoContentUrlIsAbsolute も追加してあります。スレッドは解決済みにします

方針を確認したい(2 件)

  • [4] 出力ページの限定 — トップページ(homepage)と「当サイトについて」(help_about)の 2 ページに限定する案をスレッドに書きました。TwigInitializeListener 側で絞り、対象外では JSON-LD の組み立て自体を行わない形を考えています
  • [5] @graph + publisher — ご提案に同意です。authorpublisher@context はトップレベルに 1 つ、@id 参照に変更します

[4] と [5] は出力構造そのものが変わるため、テストの書き換えが [1]〜[9] の修正と重なります。先に [4] の方針を確定させてから、まとめて 1 回で修正・テスト更新を行いたいと考えています。[4] についてご意見をいただければ着手します。

nanasess のレビュー指摘と dotani1111 の指摘に対応。

- telephone: `+81-` の無条件前置を廃止し保存値をそのまま出力する。
  phone_number は PhoneNumberType の TruncateHyphenListener と Assert\Type('digit')
  によりハイフンなしの数字列(例 0312345678)で保存されるため、+81 を前置すると
  国内トランクプレフィックスの 0 が残った不正な値になっていた。Organization と
  ContactPoint の 2 箇所を修正。
- email: email01(送信元 From かつ全送信メールの BCC 先)ではなく
  email02(問い合わせ専用)を出力する。送信専用・店舗内部の運用アドレスが
  全ページで公開されるのを避ける。
- logo: ファビコン(ICO は Google Images の対応形式外)から、帳票 PDF と共通の
  店舗ロゴ assets/pdf/logo.png へ変更。優先順は OrderPdfService に合わせ、
  user_data に配置されていればそれを使い、無ければ管理画面テンプレート同梱の
  既定ロゴへフォールバックする。
- 構造: WebSite に Organization を author として内包する形をやめ、@graph で並列の
  トップレベルノードにし WebSite.publisher から @id 参照する。@context も
  トップレベルに 1 つだけ置き重複を解消。
- description: ProductStructuredDataService の正規化(strip_tags → 空白正規化 →
  300 文字丸め)を StructuredDataDescriptionTrait に切り出して共通化し、
  good_traded と message に適用する。
- ContactPoint: contactType(customer support)を追加。
- アセットURL: プロトコル相対URL(//cdn...)にスキームを補って絶対URLにする。
  JSON-LD では @base の無い相対 IRI となり解決先が曖昧になるため。
- 出力ページ: TwigInitializeListener でトップページ(homepage)と
  「当サイトについて」(help_about)の 2 ページに限定する。Google の Organization
  ドキュメントが全ページへの出力を必要としていないため、対象外では組み立て自体を行わない。
- テスト: @graph 構造・publisher の @id 参照・telephone の書式・description の正規化・
  email の出力先を検証。出力ページの限定は Web テストで検証し、ガードを外すと
  落ちることも確認済み。
Copilot AI review requested due to automatic review settings August 5, 2026 06:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@ttokoro20240902

Copy link
Copy Markdown
Contributor

@nanasess ご指摘とご提案をすべて反映して push しました(29d692cfe8)。方針をご確認いただく前に着手した点はご容赦ください。

対応内容

指摘 対応
[1] +81- の無条件前置 前置を廃止し保存値をそのまま出力(0312345678)。Organization と ContactPoint の 2 箇所とも修正しました
[2] emailemail01 email02(問い合わせ専用)へ変更。送信元・BCC 先のアドレスは公開しません
[3] logo がファビコン 帳票 PDF と共通の assets/pdf/logo.png へ変更。優先順は OrderPdfService に揃え、user_data に配置されていればそれを使い、無ければ管理画面テンプレート同梱の既定ロゴにフォールバックします
[4] 出力ページの限定 トップページ(homepage)と「当サイトについて」(help_about)の 2 ページに限定。TwigInitializeListener で絞り、対象外では JSON-LD の組み立て自体を行いません
[5] @graph + publisher ご提案どおり @graph で並列のトップレベルノードにし、WebSite.publisher から @id 参照する形へ。@context はトップレベルに 1 つだけになりました
[6] telephone のテスト 追加しました。[1] の書式を固定しています
[7] description の無加工 ProductStructuredDataService::buildDescription() の正規化を StructuredDataDescriptionTrait に切り出して共通化し、good_tradedmessage に適用しました
[8] contactType なし customer support を追加しました
[9] プロトコル相対URL // のときはスキームを補って絶対URLにするようにしました

出力例(既定インストール+電話番号設定時)

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "name": "EC-CUBE SHOP",
      "url": "https://example.com/",
      "potentialAction": { "@type": "SearchAction", "...": "..." },
      "publisher": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "url": "https://example.com/",
      "logo": { "@type": "ImageObject", "contentUrl": "https://example.com/html/user_data/assets/pdf/logo.png" },
      "name": "EC-CUBE SHOP",
      "telephone": "0312345678",
      "contactPoint": { "@type": "ContactPoint", "contactType": "customer support", "...": "..." }
    }
  ]
}

テスト

  • SiteStructuredDataServiceTest: 11 tests → 16 tests / 44 assertions@graph 構造・publisher@id 参照・telephone の書式・description の正規化・email の出力先を追加で検証しています
  • SiteStructuredDataOutputTest(新規): 出力ページの限定を実リクエストで検証(//help/about は出力、/products/list /cart /help/privacy は非出力)。ガードを外すと 3 件落ちることも確認済みです
  • ProductStructuredDataServiceTest: 共通化の影響なし(8 tests / 28 assertions)
  • PHPStan(src 全体・level 6)/ PHP-CS-Fixer / Rector いずれもクリーン

1 点ご相談

[3] のロゴについて、user_data/assets/pdf/logo.png.gitignore 対象(/html/user_data/*)で環境依存のため、テストでは user_data 側と admin 既定ロゴのどちらでも通るよう正規表現でアサートしています。既定インストールで user_data 側に必ず配置されるのであれば、そちらに固定したほうが検証は強くなります。ご存知でしたら教えていただけますでしょうか。

Rector が追加した use 文の位置が ordered_imports に反しており CI の
php-cs-fixer ジョブが落ちていた。ローカルの局所実行は .php-cs-fixer.cache の
キャッシュヒットで検出できなかったため --using-cache=no で適用した。
Copilot AI review requested due to automatic review settings August 5, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Eccube/Service/SiteStructuredDataService.php`:
- Around line 208-216: Update SiteStructuredDataService::buildLogoUrl so it
never falls back to the admin report logo: return the user_data logo only when
it is a configured SEO-compliant logo, otherwise return null, and ensure the
caller omits the Organization.logo property when no valid logo exists. In
tests/Eccube/Tests/Service/SiteStructuredDataServiceTest.php lines 102-107,
remove the assertion accepting the admin fallback and verify omission when unset
or inclusion only for a compliant dedicated logo.

In `@src/Eccube/Service/StructuredDataDescriptionTrait.php`:
- Around line 33-35: Update the description normalization in
StructuredDataDescriptionTrait so br and block-level HTML elements are replaced
with spaces before strip_tags() removes tags, preserving separation between
adjacent content such as neighboring p elements. Keep the existing whitespace
normalization and trimming, and add a regression test covering adjacent block
elements.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f7a672e-967d-4a35-a3e6-958f896c519b

📥 Commits

Reviewing files that changed from the base of the PR and between ba23dae and 29d692c.

📒 Files selected for processing (6)
  • src/Eccube/EventListener/TwigInitializeListener.php
  • src/Eccube/Service/ProductStructuredDataService.php
  • src/Eccube/Service/SiteStructuredDataService.php
  • src/Eccube/Service/StructuredDataDescriptionTrait.php
  • tests/Eccube/Tests/Service/SiteStructuredDataServiceTest.php
  • tests/Eccube/Tests/Web/SiteStructuredDataOutputTest.php

Comment thread src/Eccube/Service/SiteStructuredDataService.php Outdated
Comment thread src/Eccube/Service/StructuredDataDescriptionTrait.php
- logo: 要件を満たす画像が無ければ出力しない。Google の Organization ドキュメントは
  幅・高さともに 112px 以上を求めており、既定の帳票ロゴは 301x38 で満たさない。
  file_exists だけでは画像サイズを保証できないため getimagesize で判定し、
  満たさない場合は logo を省略する(logo は任意プロパティ)。
- 説明文の正規化: strip_tags はタグを削除するだけなので
  <p>商品A</p><p>商品B</p> が「商品A商品B」と連結してしまう。br とブロック要素の
  境界を空白へ置換してからタグを除去する。隣接ブロック要素の回帰テストを追加。
- TwigInitializeListener: onKernelRequest で取得済みの BaseInfo を
  setFrontVariables へ渡し、同一リクエスト内の二重取得を解消。
  引数は後方互換のため任意にして未指定時は従来どおり取得する。
Copilot AI review requested due to automatic review settings August 5, 2026 06:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

ロゴの参照先を帳票 PDF 共通の assets/pdf/logo.png から、構造化データ専用の
html/user_data/assets/img/common/logo.png へ変更する。

帳票ロゴは LoadDataFixturesEccubeCommand がインストール時に管理画面同梱の
301x38 を user_data へコピーするため既定で必ず存在し、共有するとロゴを
差し替えていない店舗でも EC-CUBE 既定のロゴが Organization.logo として
出力される。また OrderPdfService は幅 40mm 固定・高さアスペクト比で描画するため、
Google の要件(112x112 以上)を満たす画像を置くと帳票のレイアウトが崩れる。

あわせて getimagesize() によるサイズ判定を撤去し、ファイルの有無だけで
出力を決める。サイズ・形式の要件はドキュメントで案内する。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 6, 2026 07:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@nanasess nanasess left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

5985f081 までの対応を確認しました。指摘した 10 点すべてが解消されています。

対応確認

指摘 対応
[1] telephone への +81- 無条件前置 前置を廃止し保存値をそのまま出力。Organization / ContactPoint の 2 箇所とも
[2] Organization.emailemail01 email02(問い合わせ専用)へ変更
[3] logo がファビコン 構造化データ専用パス user_data/assets/img/common/logo.png へ移動。帳票ロゴとは非共有、実行時のサイズ判定なし
[4] 全フロントページへの出力 homepage / help_about に限定。対象外では組み立て自体を行わない
[5] WebSite.author へのネスト / @context 重複 @graph で並列ノード化し publisher から @id 参照。@context はトップレベルに 1 つ
[6] telephone のテスト不足 testTelephoneIsOutputAsStored を追加
[7] description の無加工 StructuredDataDescriptionTrait へ共通化。ブロック要素境界の区切り保持まで改善
[8] contactPoint.contactType なし customer support を追加
[9] プロトコル相対URL スキームを補って絶対URL化
[10] BaseInfo の二重取得 setFrontVariables() へ引き渡し(引数は任意で BC 維持)

こちらで確認した点

  • CI は 128 pass(dockerbuild / merge のみ matrix 由来の skipping)
  • assets/img/common/logo.pngeccube_file_uploadable_extensionspng があるためファイル管理から配置可能です(app/config/eccube/packages/eccube.yaml:174-187)。同ディレクトリは favicon の配置先として LoadDataFixturesEccubeCommand が作成するのでディレクトリ新設も不要で、既存参照との衝突もありません
  • logo の出力経路は、帳票ロゴ流用時は既定画像がサイズ要件を満たさず CI で一度も実行されない状態でしたが、testPlacedLogoIsOutputAsAbsoluteUrl が 1x1 PNG を配置して検証するようになったため通るようになっています
  • StructuredDataDescriptionTrait への共通化により、マージ済みの ProductStructuredDataService#6883)の出力も <p>A</p><p>B</p> → 「A B」に変わりますが、改善方向でテストも追加されているため問題ないと判断しました

ドキュメント(doc4)への補足は別途起票いただけるとのことなので、そちらでお願いします。

@ttokoro20240902 丁寧な対応ありがとうございました。

@dotani1111

Copy link
Copy Markdown
Contributor

LGTM

@dotani1111
dotani1111 merged commit 36b5808 into EC-CUBE:4.4 Aug 7, 2026
131 checks passed
ttokoro20240902 added a commit that referenced this pull request Aug 9, 2026
#6139 が 4.4 へマージされ、SiteStructuredDataService とそのテストが本体側に
入ったため、本ブランチの「新規追加」を 4.4 版への追記へ組み替える。

- BaseInfo: 4.4 の mcp_enabled と本ブランチの構造化データ項目を両方残す
- SiteStructuredDataService: 4.4 版(@graph・publisher 参照・normalizeDescription・
  buildLogoUrl・email02)を土台にし、本ブランチ固有の copyrightYear / image /
  foundingDate / numberOfEmployees / sameAs / openingHours を載せる
  - WebSite.author に Organization を内包する形は 4.4 の publisher 参照へ寄せた
  - description は normalizeDescription 経由、email は email01 でなく email02
- テスト: copyrightYear 検証を @graph 構造へ追随させる

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants