Laravel Seo
rankbeam/laravel-seo
메타데이터, 캐노니컬 URL, Open Graph, 연결된 JSON-LD, XML 사이트맵, 크롤러 제어를 위한 Laravel SEO 패키지입니다. 무료이며 MIT 라이선스로 제공됩니다.
Laravel SEO (코어)
Rankbeam 은 실서비스 애플리케이션을 위해 만든 Laravel SEO 패키지입니다. 무료(MIT)인 코어 패키지는 계층형 우선순위 체인으로 메타데이터를 결정하고, Laravel 모델과 설정값만으로 캐노니컬 URL, Open Graph·Twitter 카드, @id로 서로 연결된 JSON-LD 그래프, XML 사이트맵, 크롤러 제어 규칙을 렌더링합니다.
composer require rankbeam/laravel-seo프로덕션 감사·모니터링(Pro)과 Filament 관리자 UI는 별도 패키지로 제공되며, 이 패키지가 해당 패키지들을 함께 설치하는 일은 없습니다.
다국어 사이트를 염두에 두고 설계했습니다. 콘텐츠 로케일별로 SEO 메타데이터를 저장하고, hreflang과 inLanguage를 출력하며, 콘텐츠 문자 체계에 맞는 제목·설명 길이 기준을 사용합니다. 패키지 메시지는 17개 언어로 제공됩니다. 번역된 콘텐츠 자체는 애플리케이션에서 제공해야 하며, 코어가 일반 모델 속성을 자동으로 번역하지는 않습니다. 자세한 내용은 다국어 콘텐츠, 인터페이스 번역, 또는 무료 Filament 에디터의 언어 탭을 참고하세요.
NOTE
fibonoir/laravel-seo v1에서 업그레이드하시나요? UPGRADING.md를 확인하세요. v2에서는 벤더 이름이 바뀌었고, 기존의 "풀 스위트"가 이 코어로 줄어들었습니다. 분석기, 스캐너, 리디렉션 관리자, 404 모니터, 관리자 UI는 별도 패키지(laravel-seo-filament 무료, laravel-seo-pro 상용)로 이어집니다.
이 패키지가 하는 일
| 영역 | 상세 |
|---|---|
| 메타 결정 | SEOResolver가 여섯 개 계층(설정 → 전역 DB 기본값 → 모델 타입 기본값 → 라우트 기본값 → 모델에서 계산한 값 → 명시적 seo_meta 값)을 병합합니다. null은 하위 계층의 값을 덮어쓰지 않습니다. |
| 계산된 폴백 | 제목·설명·이미지·robots 값을 모델 속성에서 도출합니다. 설명 후보 필드는 설정(seo.computed.description_fields)으로 지정할 수 있고, 정규화(HTML 제거, 엔티티 디코딩)한 뒤 단어 경계에서 잘라냅니다(기본 160자, 말줄임표 없음). 모델별 robots/noindex도 내장되어 있어 getSEORobots() 훅이나 is_indexable 속성을 사용할 수 있으며, saveSEO(['robots' => …])로 페이지별로 재정의할 수 있습니다. |
| 렌더링 | TagRenderer가 HTML(@seo Blade 디렉티브), 구조화된 배열(Vue/React), Inertia Head 형식으로 출력합니다. JSON-LD는 JSON_HEX_* 이스케이프로 출력되므로 콘텐츠에 </script>가 들어 있어도 script 요소를 벗어날 수 없습니다. |
| 캐노니컬 정책 | 자동으로 도출한 캐노니컬(모델 URL / 현재 URL)은 쿼리 스트링을 제거하며, 명시적으로 지정한 캐노니컬은 그대로 유지합니다. |
| 스키마 (JSON-LD) | Article, Breadcrumb, FAQ, LocalBusiness, Organization, Product 빌더를 제공합니다. SchemaGraph는 Organization/WebSite/WebPage 노드를 고정된 @id로 서로 연결하며, 브레드크럼은 페이지의 상위 체인에서 만들어지고 순환 방지 장치가 있습니다. |
| 사이트맵 | SitemapBuilder(spatie/laravel-sitemap 래핑)가 설정 기반 모델 소스, SEO::sitemaps()->register(...)로 등록하는 이름 있는 프로그래매틱 소스, 사이트맵 인덱스, seo:sitemap 명령, 비활성화 가능한 /sitemap.xml 라우트를 지원합니다. 사이트맵은 스타일 XSL 스타일시트 덕분에 브라우저에서 읽기 좋은 브랜드 페이지로 열립니다(기본 활성화, 검색 엔진은 무시합니다). |
| llms.txt | seo:llms-txt는 사이트맵과 동일한 소스(레지스트리 + seo.sitemap.models)에서 선택 사항인 마크다운 llms.txt 인덱스를 생성하므로 둘이 어긋나지 않습니다. 이를 사용하기로 한 도구를 위한 호환용 파일이며 Google 검색은 사용하지 않습니다. /llms.txt로 제공되고 설정으로 켜고 끕니다. |
| AI 크롤러 제어 | seo:robots-txt는 목적별로 분류된, 공식 문서로 검증된 AI 크롤러 카탈로그를 바탕으로 관리형 robots.txt(및 ai.txt)를 생성합니다. 기본값은 AI 검색·어시스턴트 크롤러(ai_search/ai_assistant)는 허용하고, 콘텐츠를 학습에 사용하는 크롤러(ai_training)는 차단하는 것입니다. 붙여넣어 쓸 수 있는 블록은 SEO::robotsTxt()->aiDirectives(), 카탈로그와 정책은 SEO::aiCrawlers()로 확인합니다. robots.txt를 무시하는 봇은 권고 수준(advisory)으로 표시됩니다. |
| 봇용 마크다운 | AI 크롤러에는 HTML 대신 깔끔한 마크다운을 제공하는 콘텐츠 협상 기능입니다. Accept: text/markdown, ?format=md, 또는 (선택 사항으로) 알려진 AI 크롤러 요청 시 동작하며, 모델의 toSeoMarkdown(), SEO::markdown()->register() 소스, 제목+설명+콘텐츠로 구성한 기본 폴백 중 하나를 사용합니다. 기본값은 꺼져 있고 일반 방문자의 응답에는 영향을 주지 않습니다. |
| 인덱싱 가드 | 인덱싱 가능 여부를 Laravel 환경에 연동합니다. seo.indexing_guard.allowed_environments(기본 ['production']) 밖에서는 모든 페이지가 noindex,nofollow로 강제되고(전체 우선순위 체인보다 위에서 동작하며, 페이지별로 저장된 값도 덮어씁니다), robots.txt/ai.txt는 전체 차단으로 바뀌고 seo:audit이 경고합니다. 스테이징·로컬 복사본이 검색 색인에 노출되는 일을 막아 줍니다. 기본값은 꺼짐이며 SEO_INDEXING_GUARD=true 한 줄로 켤 수 있고, 프로덕션에서는 동작하지 않습니다. 인덱싱 가드를 참고하세요. |
| OG 이미지 생성 | 실제 헤드리스 브라우저(spatie/browsershot)로 1200×630 Open Graph 이미지를 렌더링하는 선택 기능입니다. 여러 줄 줄바꿈, CJK/악센트 문자, 말줄임 처리가 올바르게 됩니다. 게시 가능한 템플릿 세 가지(기본 / 기사 / 상품, 모델별 선택 가능)와 번들 OFL 폰트를 제공하며, seo:og-images가 카드를 미리 생성해 캐시합니다(콘텐츠 해시 기반). 리졸버는 이를 계산된 og:image 폴백으로 제공하고, 파일이 있을 때만 사용하므로 웹 요청 중에는 렌더링하지 않습니다. 기본값은 꺼짐이고, 브라우저는 권장 의존성이며, 정적 사전 생성만 지원합니다. OG 이미지 생성을 참고하세요. |
| 경고 | 관리자 UI용 SEOWarningEvaluator입니다. 문자 체계별 기준을 넘는 제목/설명(라틴 문자 60/160자, CJK 약 30/80자 — 다국어 콘텐츠 참고), 수동 입력/폴백 여부 표시, 소셜 이미지 크기 검사(최소 200x200, 권장 1200x630, 로컬 파일만)를 수행합니다. |
| 무료 감사 | seo:audit는 "지금 내 SEO의 문제가 무엇인가"를 확인하는 인프로세스 명령입니다(큐, 라이선스, 네트워크 불필요). 메타데이터 유형 검사(제목·설명 누락/과다/부족 길이, OG 이미지, robots 충돌, 캐노니컬 형식/교차 도메인/공유/비보안, hreflang 코드/중복/자기 참조, 포커스 키워드)를 실행하고, 기능 매트릭스와 함께 페이지별 통과/경고/실패 표를 출력합니다. CI에는 --strict, 도구 연동에는 --json을 사용합니다. 숫자 점수는 제공하지 않으며 Pro에서 제공합니다. |
| 다국어 콘텐츠 | 이 패키지는 사용자의 언어뿐 아니라 콘텐츠의 언어를 이해합니다. 문자 체계별 제목/설명 길이 기준(LengthPolicy, 바이트가 아닌 자소 단위), CJK는 문장 부호에서 자르는 자소 안전 말줄임, 로케일에 맞는 대소문자 변환(튀르키예어 İ/ı, 그리스어 어말 시그마, ß), hreflang 정규화와 자기 참조/x-default 정책 및 감사 코드, 스키마 그래프의 inLanguage, 크롤러 카탈로그의 Yandex/Baidu/Naver/Seznam/Sogou/360/Cốc Cốc/DuckDuckGo, 8개 검색 엔진용 사이트 소유 확인 태그, 폰트 누락을 사전 점검하는 문자 체계별 OG 이미지 폰트 스택, IDN을 허용하는 캐노니컬 검증을 지원합니다. UI 언어 17개는 --tag=seo-lang으로 게시합니다. 다국어 콘텐츠를 참고하세요. |
| 해석 과정 설명 | seo:explain "App\Models\Post" 42는 리졸버의 우선순위 추적 결과를 보여 줍니다. 필드별로 채택된 계층과 값, 덮어쓰인 하위 계층, 후처리 내용(제목 접미사, 캐노니컬 쿼리 제거, og:url 도출, 이미지 절대 경로화, 인덱싱 가드)을 확인할 수 있고, 사이트 이름·기본 로케일·캐노니컬 호스트 등 각 값의 출처를 보여 주는 사이트 단위 원장도 함께 출력합니다. route:list 스타일의 사람이 읽는 출력과 --json을 지원합니다. 읽기 전용이며 실제 렌더링 결과와 어긋날 수 없습니다. 해석 과정 설명을 참고하세요. |
| 마이그레이션 임포터 | seo:import-from ralphjsmit은 다른 Laravel 패키지의 저장소에 있는 SEO 데이터를 seo_meta로 일괄 가져옵니다. 멱등적으로 동작하며 --dry-run, --model= 범위 지정, 명시적 필드 매핑을 지원하고, 모프 행은 실제 모델로 다시 연결합니다. 다른 패키지에서 마이그레이션하기를 참고하세요. |
| WordPress 임포터 | seo:import-from wordpress-csv(CSV 내보내기 파일)와 seo:import-from yoast / rank-math(--connection=으로 지정한 실제 WordPress DB)를 지원합니다. Yoast/Rank Math 키를 명시적으로 매핑하고(OG/Twitter 재정의 포함), %%title%% 같은 템플릿 토큰을 해석하며, 슬러그로 게시물을 모델과 매칭하고, Pro용 리디렉션 CSV를 생성합니다. WordPress에서 마이그레이션하기를 참고하세요. |
데이터베이스 테이블: seo_meta(모델별 명시적 값, 모프 + 로케일)와 seo_defaults(전역/모델 타입/라우트 기본값). 그 외에는 없습니다.
요구 사항
- PHP 8.2 이상
- Laravel 11, 12 또는 13 (CI에서 전체 매트릭스를 실행하며, Laravel 13은 PHP 8.3 이상이 필요하고 PHP 8.5는 Laravel 12 또는 13이 필요합니다)
spatie/laravel-sitemap^7.0 또는 ^8.0 (권장 의존성이며 사이트맵 생성에 필요합니다)
설치
composer require rankbeam/laravel-seophp artisan vendor:publish --tag=seo-configphp artisan migrate빠른 시작
use Rankbeam\Seo\Traits\HasSEO;
class Post extends Model
{
use HasSEO;
public function getUrlForSEO(): string
{
return route('posts.show', $this);
}
}<head>
@seo($post)
</head>관리자 화면 등에서 명시적인 값을 저장하려면 다음과 같이 합니다.
$post->saveSEO([
'title' => 'Custom SEO Title',
'description' => 'Custom meta description',
]);헤드리스 / Inertia 환경에서는 다음과 같이 사용합니다.
use Rankbeam\Seo\Facades\SEO;
return Inertia::render('Post', [
'seo' => SEO::forInertia($post),
]);사이트맵 소스는 다음과 같이 지정합니다.
// config/seo.php
'sitemap' => ['models' => [Post::class => ['priority' => 0.8]]],
// 또는 코드로 등록 (예: 서비스 프로바이더에서)
SEO::sitemaps()->register('pages', fn () => ['/about', '/contact']);그다음 파일을 생성합니다(spatie/laravel-sitemap 필요). 패키지의 /sitemap.xml 라우트는 이 명령이 기록한 파일을 제공합니다.
composer require spatie/laravel-sitemapphp artisan seo:sitemap직접 만든 정적 /sitemap.xml을 제공하고 있다면 패키지의 라우트를 비활성화하세요.
// config/seo.php
'routes' => ['enabled' => false],SEO 감사하기
# seo.audit.models / seo.sitemap.models 에 지정된 모델을 감사합니다php artisan seo:audit# 특정 모델만 지정하거나, 문제가 하나라도 있으면 CI를 실패시키거나, JSON으로 출력할 수도 있습니다php artisan seo:audit --model="App\Models\Post" --strictphp artisan seo:audit --json메타데이터 유형 검사에 대한 무료 인프로세스 통과/경고/실패 리포트입니다. 렌더링된 HTML과 실제 캐노니컬 검사, 그리고 숫자 점수는 Pro 스캔에서 제공되며, 이 명령은 실행할 때마다 그 경계를 출력합니다.
llms.txt 생성하기
php artisan seo:llms-txt # public/llms.txt 를 생성합니다php artisan seo:llms-txt --print # 표준 출력으로 출력합니다 (드라이 런)AI 크롤러를 위한 사이트 마크다운 인덱스(llms.txt)로, 사이트맵과 동일한 소스(등록된 소스 + seo.sitemap.models, noindex·미공개 항목 제외 규칙도 동일)에서 만들어지므로 둘이 어긋나지 않습니다. /llms.txt로 제공되며(이 라우트는 seo.llms_txt.route로 비활성화), 사이트맵과 함께 스케줄에 등록할 수도 있습니다.
Schedule::command('seo:llms-txt')->daily();AI 크롤러 제어 (robots.txt / ai.txt)
php artisan seo:robots-txt # public/robots.txt 를 생성합니다php artisan seo:robots-txt --print # 표준 출력으로 출력합니다 (드라이 런)php artisan seo:robots-txt --ai-txt # public/ai.txt 도 함께 생성합니다AI 시대를 위한 관리형 robots.txt로, 목적별로 분류된 공식 문서 검증 AI 크롤러 카탈로그에서 생성됩니다. 기본 정책은 AI 검색·어시스턴트 크롤러(ai_search / ai_assistant)는 허용하고, 콘텐츠를 학습에 사용하는 크롤러(ai_training)는 차단하는 것이며, seo.ai_crawlers에서 목적별 또는 봇별로 재정의할 수 있습니다. 기존 파일에 붙일 관리 블록만 필요하면 SEO::robotsTxt()->aiDirectives()를 사용하고, /robots.txt를 동적으로 제공할 수도 있습니다(기본값은 꺼짐이며 정적 파일을 가리지 않습니다). robots.txt를 따르지 않는 것으로 문서화된 봇은 권고 수준(advisory)으로 표시됩니다. AI 크롤러 제어를 참고하세요.
가이드
이 패키지를 자기 자신에게 적용해 운영하는 Laravel 앱인 Rankbeam 블로그의 장문 글입니다.
- Laravel SEO: the complete guide
- Best Laravel SEO packages compared
- Laravel meta tags
- Canonical URLs in Laravel
- JSON-LD schema graphs
- Laravel sitemaps
- Laravel SEO audit in CI
- hreflang done right
- Answer engine optimization
- Filament SEO fields
테스트 현황
코어 3.20.0의 전체 테스트 스위트 기록: PHP 8.4 / Laravel 13 환경에서 1036개 통과(어서션 4363개), 실패 0개이며, 기본 스킵은 17개입니다(선택형 Chrome 이미지 검사 16개와 ext-xsl 검사 1개). 실제 OG/PDF 렌더링과 런타임 소비자 검사는 별도로 실행되며, 기본 스킵이 해당 경로가 실행되었다는 증거는 아닙니다. 공개 CI는 지원하는 PHP 8.2–8.5 / Laravel 11–13 조합을 다룹니다. Laravel 13은 PHP 8.3 이상이 필요하고, PHP 8.5는 Laravel 12 및 13과 함께 테스트됩니다.
git clone https://github.com/rankbeam/laravel-seo.gitcd laravel-seocomposer installvendor/bin/pest이 패키지에 포함되지 않는 것
대기열 기반 사이트 스캔, 콘텐츠 분석, 리디렉션 관리자, 404 모니터, SEO 대시보드는 laravel-seo-pro(상용)로 제공되고, Filament 관리자 폼 필드는 laravel-seo-filament(무료)로 제공됩니다. 예전의 seo:install 스텁 게시 흐름은 없어졌습니다.
기여하기
번역은 언제든 환영합니다. 언어 파일, 용어집, 동등성 테스트는 TRANSLATING.md를 참고하세요.
버그 리포트, 수정, 기능 제안도 환영합니다. 패키지 경계(코어와 Filament/Pro 패키지 중 어디에 속하는지), 테스트 스위트 실행 방법, 렌더링 계약, 버전 관리 및 하위 호환 정책은 CONTRIBUTING.md를 참고하세요.
보안
보안 취약점은 공개 이슈가 아닌 비공개로 제보해 주세요. 자세한 방법은 SECURITY.md를 참고하세요.
라이선스
MIT — LICENSE.md를 참고하세요.