{"id":546,"date":"2025-08-31T09:50:19","date_gmt":"2025-08-31T09:50:19","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=546"},"modified":"2025-08-31T09:50:21","modified_gmt":"2025-08-31T09:50:21","slug":"laravel-seo-guide-optimizing-meta-slugs-and-sitemaps","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/laravel-seo-guide-optimizing-meta-slugs-and-sitemaps\/","title":{"rendered":"Laravel SEO Guide: Optimizing Meta, Slugs, and Sitemaps"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\"><strong>Laravel SEO Guide: Optimizing Meta, Slugs, and Sitemaps<\/strong><\/h1>\n\n\n\n<p>SEO (Search Engine Optimization) is critical for visibility. Laravel doesn\u2019t ship with built-in SEO tools, but it gives you the flexibility to build them yourself. In this guide, you\u2019ll learn how to generate SEO-friendly slugs, handle duplicate slugs effectively, understand how <code>booted()<\/code> works, manage meta tags dynamically, and build a sitemap to help Google crawl your site efficiently.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Generating SEO-Friendly Slugs<\/strong><\/h2>\n\n\n\n<p>URLs should be clean and keyword-rich. Laravel\u2019s <code>Str::slug()<\/code> helper converts titles into SEO-friendly slugs.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Database<\/span>\\<span class=\"hljs-title\">Eloquent<\/span>\\<span class=\"hljs-title\">Model<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Support<\/span>\\<span class=\"hljs-title\">Str<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Post<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Model<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">booted<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        <span class=\"hljs-keyword\">static<\/span>::creating(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">($post)<\/span> <\/span>{\n            $post-&gt;slug = Str::slug($post-&gt;title);\n        });\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This automatically sets the slug when creating a new post. For example, \u201cMy First Blog Post\u201d becomes <code>my-first-blog-post<\/code>. You can then use this slug in routes.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ routes\/web.php<\/span>\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Http<\/span>\\<span class=\"hljs-title\">Controllers<\/span>\\<span class=\"hljs-title\">PostController<\/span>;\n\nRoute::get(<span class=\"hljs-string\">'\/posts\/{post:slug}'<\/span>, &#91;PostController::class, <span class=\"hljs-string\">'show'<\/span>]);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now users and search engines can access posts with clean URLs like <code>\/posts\/my-first-blog-post<\/code> instead of numeric IDs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Performance Note: How <code>booted()<\/code> Works<\/strong><\/h3>\n\n\n\n<p>The <code>booted()<\/code> method is often misunderstood. It does <em>not<\/em> run every time you initialize a model. Instead:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>booted()<\/code> runs once per request<\/strong>, when Laravel loads the model class, to register event listeners like <code>creating<\/code> or <code>updating<\/code>.<\/li>\n<li>The closure you register (e.g., slug generation) runs <strong>only when the event is fired<\/strong> \u2014 in this case, whenever a new model is saved to the database.<\/li>\n<li>Simply fetching or instantiating a model (<code>Post::first()<\/code> or <code>new Post<\/code>) does <strong>not<\/strong> trigger slug generation.<\/li>\n<\/ul>\n\n\n\n<p>This means the slug logic is only executed during <code>creating<\/code> events (new inserts), not for every model initialization or retrieval \u2014 keeping performance efficient.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Handling Duplicate Slugs (Optimized, Single Query Strategy)<\/strong><\/h3>\n\n\n\n<p>If two posts share the same title, <code>Str::slug()<\/code> will generate identical slugs, leading to conflicts. To solve this efficiently, fetch the maximum numeric suffix in one query and append the next number.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Database<\/span>\\<span class=\"hljs-title\">Eloquent<\/span>\\<span class=\"hljs-title\">Model<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Support<\/span>\\<span class=\"hljs-title\">Str<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Post<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Model<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">booted<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        <span class=\"hljs-keyword\">static<\/span>::creating(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">($post)<\/span> <\/span>{\n            $base = Str::slug($post-&gt;title);\n\n            <span class=\"hljs-keyword\">if<\/span> (! <span class=\"hljs-keyword\">static<\/span>::where(<span class=\"hljs-string\">'slug'<\/span>, $base)-&gt;exists()) {\n                $post-&gt;slug = $base;\n                <span class=\"hljs-keyword\">return<\/span>;\n            }\n\n            $pattern = <span class=\"hljs-string\">'^'<\/span> . preg_quote($base, <span class=\"hljs-string\">'\/'<\/span>) . <span class=\"hljs-string\">'(-&#91;0-9]+)?$'<\/span>;\n\n            $maxSuffix = <span class=\"hljs-keyword\">static<\/span>::whereRaw(<span class=\"hljs-string\">'slug REGEXP ?'<\/span>, &#91;$pattern])\n                -&gt;selectRaw(<span class=\"hljs-string\">\"\n                    MAX(\n                        CASE\n                            WHEN slug = ? THEN 0\n                            ELSE CAST(SUBSTRING_INDEX(slug, '-', -1) AS UNSIGNED)\n                        END\n                    ) AS max_suffix\n                \"<\/span>, &#91;$base])\n                -&gt;value(<span class=\"hljs-string\">'max_suffix'<\/span>);\n\n            $next = ((int) $maxSuffix) + <span class=\"hljs-number\">1<\/span>;\n            $post-&gt;slug = <span class=\"hljs-string\">\"{$base}-{$next}\"<\/span>;\n        });\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This ensures slugs remain unique with minimal queries. For example, creating three posts with the same title results in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>hello-world<\/code><\/li>\n<li><code>hello-world-1<\/code><\/li>\n<li><code>hello-world-2<\/code><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Database Safety: Add a Unique Index<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ database\/migrations\/xxxx_xx_xx_add_unique_index_to_posts_slug.php<\/span>\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Database<\/span>\\<span class=\"hljs-title\">Migrations<\/span>\\<span class=\"hljs-title\">Migration<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Database<\/span>\\<span class=\"hljs-title\">Schema<\/span>\\<span class=\"hljs-title\">Blueprint<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Support<\/span>\\<span class=\"hljs-title\">Facades<\/span>\\<span class=\"hljs-title\">Schema<\/span>;\n\n<span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Migration<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">up<\/span><span class=\"hljs-params\">()<\/span>: <span class=\"hljs-title\">void<\/span>\n    <\/span>{\n        Schema::table(<span class=\"hljs-string\">'posts'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n            $table-&gt;string(<span class=\"hljs-string\">'slug'<\/span>)-&gt;unique()-&gt;change();\n        });\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">down<\/span><span class=\"hljs-params\">()<\/span>: <span class=\"hljs-title\">void<\/span>\n    <\/span>{\n        Schema::table(<span class=\"hljs-string\">'posts'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n            $table-&gt;dropUnique(&#91;<span class=\"hljs-string\">'slug'<\/span>]);\n        });\n    }\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The unique index guarantees no duplicates even under concurrency. You can add retry logic on duplicate key errors if needed.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Portable Fallback (Any SQL)<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">$base = Str::slug($post-&gt;title);\n$count = <span class=\"hljs-keyword\">static<\/span>::where(<span class=\"hljs-string\">'slug'<\/span>, <span class=\"hljs-string\">'like'<\/span>, $base.<span class=\"hljs-string\">'%'<\/span>)-&gt;count();\n$post-&gt;slug = $count ? <span class=\"hljs-string\">\"{$base}-{$count}\"<\/span> : $base;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This simpler fallback avoids loops and works on any database. It may skip gaps (e.g., jump to <code>hello-world-3<\/code> if <code>hello-world-2<\/code> was deleted), but that\u2019s perfectly fine for SEO.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Dynamic Meta Tags for SEO<\/strong><\/h2>\n\n\n\n<p>Meta tags like <code>&lt;title&gt;<\/code>, <code>description<\/code>, and Open Graph tags improve click-through rates and rankings. Add them dynamically per page.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Http\/Controllers\/PostController.php<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Http<\/span>\\<span class=\"hljs-title\">Controllers<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>\\<span class=\"hljs-title\">Post<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PostController<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Controller<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">show<\/span><span class=\"hljs-params\">(Post $post)<\/span>\n    <\/span>{\n        <span class=\"hljs-keyword\">return<\/span> view(<span class=\"hljs-string\">'posts.show'<\/span>, compact(<span class=\"hljs-string\">'post'<\/span>));\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">&lt;!-- resources\/views\/posts\/show.blade.php --&gt;\n@extends(<span class=\"hljs-string\">'layouts.app'<\/span>)\n\n@section(<span class=\"hljs-string\">'head'<\/span>)\n  &lt;title&gt;{{ $post-&gt;title }} | My Blog&lt;\/title&gt;\n  &lt;meta name=<span class=\"hljs-string\">\"description\"<\/span> content=<span class=\"hljs-string\">\"{{ Str::limit($post-&gt;content, 160) }}\"<\/span>&gt;\n\n  &lt;!-- Open Graph --&gt;\n  &lt;meta property=<span class=\"hljs-string\">\"og:title\"<\/span> content=<span class=\"hljs-string\">\"{{ $post-&gt;title }}\"<\/span>&gt;\n  &lt;meta property=<span class=\"hljs-string\">\"og:description\"<\/span> content=<span class=\"hljs-string\">\"{{ Str::limit($post-&gt;content, 160) }}\"<\/span>&gt;\n  &lt;meta property=<span class=\"hljs-string\">\"og:url\"<\/span> content=<span class=\"hljs-string\">\"{{ url()-&gt;current() }}\"<\/span>&gt;\n@endsection\n\n@section(<span class=\"hljs-string\">'content'<\/span>)\n  &lt;h1&gt;{{ $post-&gt;title }}&lt;\/h1&gt;\n  &lt;p&gt;{{ $post-&gt;content }}&lt;\/p&gt;\n@endsection<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>UI Example: Adding Meta Fields<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">&lt;form action=<span class=\"hljs-string\">\"{{ route('posts.store') }}\"<\/span> method=<span class=\"hljs-string\">\"POST\"<\/span>&gt;\n  @csrf\n  &lt;label&gt;Title&lt;\/label&gt;\n  &lt;input type=<span class=\"hljs-string\">\"text\"<\/span> name=<span class=\"hljs-string\">\"title\"<\/span>&gt;\n\n  &lt;label&gt;Meta Description&lt;\/label&gt;\n  &lt;textarea name=<span class=\"hljs-string\">\"meta_description\"<\/span>&gt;&lt;\/textarea&gt;\n\n  &lt;button type=<span class=\"hljs-string\">\"submit\"<\/span>&gt;Save&lt;\/button&gt;\n&lt;\/form&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Editors can set meta descriptions manually. If empty, fall back to auto-generating from content.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Building an XML Sitemap<\/strong><\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ routes\/web.php<\/span>\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Http<\/span>\\<span class=\"hljs-title\">Controllers<\/span>\\<span class=\"hljs-title\">SitemapController<\/span>;\nRoute::get(<span class=\"hljs-string\">'\/sitemap.xml'<\/span>, &#91;SitemapController::class, <span class=\"hljs-string\">'index'<\/span>]);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Http\/Controllers\/SitemapController.php<\/span>\n<span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Http<\/span>\\<span class=\"hljs-title\">Controllers<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>\\<span class=\"hljs-title\">Post<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">SitemapController<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Controller<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">index<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        $posts = Post::all();\n        <span class=\"hljs-keyword\">return<\/span> response()\n            -&gt;view(<span class=\"hljs-string\">'sitemap'<\/span>, compact(<span class=\"hljs-string\">'posts'<\/span>))\n            -&gt;header(<span class=\"hljs-string\">'Content-Type'<\/span>, <span class=\"hljs-string\">'application\/xml'<\/span>);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-meta\">&lt;?<\/span>xml version=<span class=\"hljs-string\">\"1.0\"<\/span> encoding=<span class=\"hljs-string\">\"UTF-8\"<\/span><span class=\"hljs-meta\">?&gt;<\/span>\n&lt;urlset xmlns=<span class=\"hljs-string\">\"http:\/\/www.sitemaps.org\/schemas\/sitemap\/0.9\"<\/span>&gt;\n  @<span class=\"hljs-keyword\">foreach<\/span>($posts <span class=\"hljs-keyword\">as<\/span> $post)\n    &lt;url&gt;\n      &lt;loc&gt;{{ url(<span class=\"hljs-string\">'\/posts\/'<\/span> . $post-&gt;slug) }}&lt;\/loc&gt;\n      &lt;lastmod&gt;{{ $post-&gt;updated_at-&gt;toAtomString() }}&lt;\/lastmod&gt;\n    &lt;\/url&gt;\n  @<span class=\"hljs-keyword\">endforeach<\/span>\n&lt;\/urlset&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The XML sitemap lists all post URLs. Submit it to Google Search Console for faster indexing.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wrapping Up<\/strong><\/h2>\n\n\n\n<p>Optimizing Laravel for SEO requires three key pieces: unique slugs, dynamic meta tags, and an XML sitemap. With the optimized duplicate slug solution and database unique index, you avoid conflicts. With meta tags and Open Graph, you improve visibility and click-throughs. With sitemaps, you make crawling efficient. Together, these ensure Laravel apps are SEO-ready out of the box.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What\u2019s Next<\/strong><\/h2>\n\n\n\n<p>Keep building your SEO toolkit with these guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/how-to-generate-seo-friendly-urls-and-slugs-in-laravel\">How to Generate SEO-Friendly URLs and Slugs in Laravel<\/a><\/li>\n<li><a href=\"\/blog\/how-to-build-an-xml-sitemap-generator-in-laravel\">How to Build an XML Sitemap Generator in Laravel<\/a><\/li>\n<li><a href=\"\/blog\/adding-meta-tags-and-open-graph-data-dynamically-in-laravel\">Adding Meta Tags and Open Graph Data Dynamically in Laravel<\/a><\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>Laravel SEO Guide: Optimizing Meta, Slugs, and Sitemaps SEO (Search Engine Optimization) is critical for visibility. Laravel doesn\u2019t ship with built-in SEO tools, but it gives you the flexibility to build them yourself. In this guide, you\u2019ll learn how to generate SEO-friendly slugs, handle duplicate slugs effectively, understand how booted() works, manage meta tags dynamically, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":550,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[108,112,109,110,111],"class_list":["post-546","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-meta","tag-open-graph","tag-seo","tag-sitemaps","tag-slugs"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/546","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=546"}],"version-history":[{"count":1,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/546\/revisions"}],"predecessor-version":[{"id":549,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/546\/revisions\/549"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/550"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=546"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=546"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=546"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}