😆Laravel 9 Generate and Read Sitemap XML File Tutorial (ok)

https://www.positronx.io/laravel-generate-and-read-sitemap-xml-file-tutorial/

Site map có 2 loại, loại thứ nhất là xml, loại thứ 2 là html.

Ví dụ 1: loại thứ nhất là xml

composer require roumen/sitemap
// Link: https://github.com/LaraPalCom/laravel-sitemap

C:\xampp82\htdocs\testvn\config\app.php

'providers' => [
...
Laravelium\Sitemap\SitemapServiceProvider::class
...
]

C:\xampp82\htdocs\testvn\routes\web.php

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
  return view('welcome');
});
Route::get('post-detail/{id}',[PostController::class,'detail'])->name('post.detail');

C:\xampp82\htdocs\testvn\app\Models\Post.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
  use HasFactory;
  protected $fillables = [
    'detail',
    'slug'
  ];
}
php artisan make:command CreateSiteMap --command=sitemap:create

C:\xampp82\htdocs\testvn\app\Console\Commands\CreateSiteMap.php

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
class CreateSiteMap extends Command
{
  /**
   * The name and signature of the console command.
   *
   * @var string
   */
  protected $signature = 'sitemap:create';
  /**
   * The console command description.
   *
   * @var string
   */
  protected $description = 'Command description';
  /**
   * Create a new command instance.
   *
   * @return void
   */
  public function __construct()
  {
    parent::__construct();
  }
  /**
   * Execute the console command.
   *
   * @return int
   */
  public function handle()
  {
    $sitemap = \App::make('sitemap');
    // add home pages mặc định
    $sitemap->add(\URL::to('/'), Carbon::now(), '1.0', 'daily');
    // add bài viết
    $posts = \DB::table('posts')
      ->orderBy('created_at', 'desc')
      ->get();
    foreach ($posts as $post) {
      $sitemap->add(route('post.detail', [$post->slug]), $post->created_at, '0.6', 'daily');
    }
    // lưu file và phân quyền
    $sitemap->store('xml', 'sitemap');
    if (\File::exists(public_path() . '/sitemap.xml')) {
      chmod(public_path() . '/sitemap.xml', 0777);
    }
  }
}

C:\xampp82\htdocs\testvn\app\Http\Controllers\PostController.php

<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public function index()
  {
    //
  }
  public function detail(Post $post)
  {
  }
}

C:\xampp82\htdocs\testvn\public\sitemap.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/vendor/sitemap/styles/xml.xsl" type="text/xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
	<url>
	<loc>https://test.vn</loc>
		<priority>1.0</priority>
		<lastmod>2023-04-17T16:34:10+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/laboriosam</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/eligendi-sed</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/aut-cum</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/aut-nihil</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/ex-accusamus</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/reiciendis</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/animi-est-unde</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/possimus</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/consequatur</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
	<url>
	<loc>https://test.vn/post-detail/voluptates</loc>
		<priority>0.6</priority>
		<lastmod>2023-04-17T15:52:13+00:00</lastmod>
		<changefreq>daily</changefreq>
	</url>
</urlset>

C:\xampp82\htdocs\testvn\database\factories\PostFactory.php

<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class PostFactory extends Factory
{
  /**
   * Define the model's default state.
   *
   * @return array
   */
  public function definition()
  {
    $detail = $this->faker->text(15);
    // $slug = str_slug($detail, '-');
    $slug = Str::slug($detail, '-');
    return [
      'detail'    => $detail,
      'slug'    => $slug
    ];
  }
}

C:\xampp82\htdocs\testvn\database\seeders\DatabaseSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Post;

class DatabaseSeeder extends Seeder
{
  /**
   * Seed the application's database.
   *
   * @return void
   */
  public function run()
  {
    User::factory(10)->create();
    Post::factory(10)->create();
  }
}

C:\xampp82\htdocs\testvn\database\migrations\2023_04_17_130047_create_posts_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    Schema::create('posts', function (Blueprint $table) {
      $table->id();
      $table->string('detail');
      $table->string('slug');
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('posts');
  }
}

Ví dụ 2: loại thứ loại thứ nhất là xml

php artisan migrate --seed

C:\xampp81\htdocs\testcn\app\Models\Blog.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
  use HasFactory;
  protected $fillable = [
    'url',
    'description'
  ];
}

C:\xampp81\htdocs\testcn\database\migrations\2023_04_17_092922_create_blogs_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   */
  public function up(): void
  {
    Schema::create('blogs', function (Blueprint $table) {
      $table->id();
      $table->string('url');
      $table->text('description');
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   */
  public function down(): void
  {
    Schema::dropIfExists('blogs');
  }
};

C:\xampp81\htdocs\testcn\database\factories\BlogFactory.php

<?php
namespace Database\Factories;
use App\Models\Blog;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Blog>
 */
class BlogFactory extends Factory
{
  protected $model = Blog::class;
  /**
   * Define the model's default state.
   *
   * @return array<string, mixed>
   */
  public function definition(): array
  {
    return [
      'url' => $this->faker->randomNumber($nbDigits = NULL, $strict = false),
      'description' => $this->faker->text
    ];
  }
}

C:\xampp81\htdocs\testcn\database\seeders\DatabaseSeeder.php

<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        \App\Models\Blog::factory(30)->create();
        // \App\Models\User::factory()->create([
        //     'name' => 'Test User',
        //     'email' => 'test@example.com',
        // ]);
    }
}

C:\xampp81\htdocs\testcn\app\Http\Controllers\SitemapXmlController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Blog;
class SitemapXmlController extends Controller
{
  public function index()
  {
    $posts = Blog::all();
    return response()->view('index', [
      'posts' => $posts
    ])->header('Content-Type', 'text/xml');
  }
}

C:\xampp81\htdocs\testcn\routes\web.php

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SitemapXmlController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', function () {
    return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/sitemap.xml', [SitemapXmlController::class, 'index']);

C:\xampp81\htdocs\testcn\resources\views\index.blade.php

<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  @foreach ($posts as $post)
  <url>
    <loc>{{ url('/') }}/page/{{ $post->url }}</loc>
    <lastmod>{{ $post->created_at->tz('UTC')->toAtomString() }}</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>
  @endforeach
</urlset>

Last updated