feat(content): 본문 이미지 목록 썸네일·og:image 폴백 전 티어 구현

공개 이슈 https://github.com/gnuboard/g7/issues/22 — 본문에 삽입한 이미지가
카드/갤러리 목록 썸네일과 공유 미리보기(og:image)에 반영되지 않던 공백을
코어+3모듈+2템플릿에서 해소.

- 코어 7.0.9: HtmlImageExtractor(내부 이미지 한정, origin 정규화 SSoT 재사용)
 + seo.og_image_default 사이트 기본 공유 이미지 설정 + SeoMetaResolver 폴백 체인
- board 1.1.0 / ecommerce 1.2.0 / page 1.1.0: content_thumbnail_url 캐시 컬럼,
 saving 추출(html 모드 한정·첨부 우선·비밀글 게이트 유지),
 filter_content_thumbnail 훅, 기존 데이터 백필 업그레이드 스텝
- ecommerce 카테고리 og:image 생산자 신설, page og:description 死키 정정
- sirsoft-basic 1.1.2 og 바인딩 정정, admin_basic 1.0.7 SEO 탭 업로더(+ja 팩 2종)
- 검수 중 발견한 text 모드 오캐시 결함은 실패 테스트 선행 후 수정
This commit is contained in:
HeuJung committed 2026-08-22 22:21:54 +09:00
1 parent 14eb2e39e4
commit 1ba67ca7cf
98 files changed
+4640 -101

No files matched your search

@@ -97,6 +97,20 @@ class SaveSettingsRequest extends FormRequest
]);
}
// 사이트 기본 OG 이미지도 동일하게 첨부 객체 배열 → 정수 ID 배열로 정규화
$ogImageDefault = $this->input('seo.og_image_default');
if (is_array($ogImageDefault)) {
$this->merge([
'seo' => array_merge($this->input('seo', []), [
'og_image_default' => array_map(
fn ($item) => is_array($item) ? ($item['id'] ?? $item) : $item,
$ogImageDefault
),
]),
]);
}
// GeoIP 토글 필드: 신규 필드라 초기값이 settings에 없을 수 있음.
// Toggle 컴포넌트가 undefined → true 전환 시 비표준 타입을 보낼 수 있으므로
// boolean으로 명시 캐스팅하여 Laravel boolean 검증 호환 보장.
@@ -243,6 +257,8 @@ class SaveSettingsRequest extends FormRequest
'seo.bot_detection_enabled' => ['nullable', 'boolean'],
'seo.bot_detection_library_enabled' => ['nullable', 'boolean'],
'seo.og_default_site_name' => ['nullable', 'string', 'max:200'],
'seo.og_image_default' => ['nullable', 'array'],
'seo.og_image_default.*' => ['integer', Rule::exists(Attachment::class, 'id')],
'seo.og_image_default_width' => ['nullable', 'integer', 'min:'.config('core.settings_limits.seo_og_image_default_width_min', 0), 'max:'.config('core.settings_limits.seo_og_image_default_width_max', 8000)],
'seo.og_image_default_height' => ['nullable', 'integer', 'min:'.config('core.settings_limits.seo_og_image_default_height_min', 0), 'max:'.config('core.settings_limits.seo_og_image_default_height_max', 8000)],
'seo.twitter_default_card' => ['nullable', 'string', Rule::in(['summary', 'summary_large_image', 'app', 'player', ''])],
@@ -915,6 +931,7 @@ class SaveSettingsRequest extends FormRequest
'general.maintenance_mode' => __('validation.attributes.maintenance_mode'),
'general.asset_url_mode' => __('validation.attributes.asset_url_mode'),
'general.site_logo' => __('validation.attributes.site_logo'),
'seo.og_image_default' => __('validation.attributes.og_image_default'),
// mail
'mail.mailer' => __('validation.attributes.mailer'),
'mail.host' => __('validation.attributes.smtp_host'),