5

I want to generate Dynamic sitemap for my laravel project. I had already searched in so many sites for an answer. some of them describes it using composer. I didn't get how to do that. and in some other sites they wrote codes to get urls from db in loops. In my project db I didn't saved any urls. my project is a site for doctor and patients. so is there any one knows how to write php / laravel codes for dynamic sitemap generation.?

Edit

I'm a newbie to laravel so i'm just unfamiliar with this composer. can anyone please tell me if i download the laravel-sitemap-master.zip from github where i can extract it and saves in my project directory? it will be so much helpful if anyone please answer this.

Zammuuz
  • 708
  • 4
  • 18
  • 43

3 Answers3

19

Add this line to your routes.php

Route::get('/sitemap', function()
{
   return Response::view('sitemap')->header('Content-Type', 'application/xml');
});

Create new file app\Http\Middleware\sitemap.php

<?php namespace App\Http\Middleware;

use Closure;
use Carbon\Carbon;
use Illuminate\Contracts\Auth\Guard;

class sitemap {

    /**
     * The Guard implementation.
     *
     * @var Guard
     */
    protected $auth;

    public function __construct(Guard $auth)
    {
        $this->auth = $auth;
    }


    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure                 $next
     *
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ( !$request->is("sitemap") && $request->fullUrl() != '' && $this->auth->guest() )
        {
            $aSiteMap = \Cache::get('sitemap', []);
            $changefreq = 'always';
            if ( !empty( $aSiteMap[$request->fullUrl()]['added'] ) ) {
                $aDateDiff = Carbon::createFromTimestamp( $aSiteMap[$request->fullUrl()]['added'] )->diff( Carbon::now() );
                if ( $aDateDiff->y > 0 ) {
                    $changefreq = 'yearly';
                } else if ( $aDateDiff->m > 0) {
                    $changefreq = 'monthly';
                } else if ( $aDateDiff->d > 6 ) {
                    $changefreq = 'weekly';
                } else if ( $aDateDiff->d > 0 && $aDateDiff->d < 7 ) {
                    $changefreq = 'daily';
                } else if ( $aDateDiff->h > 0 ) {
                    $changefreq = 'hourly';
                } else {
                    $changefreq = 'always';
                }
            }
            $aSiteMap[$request->fullUrl()] = [
                'added' => time(),
                'lastmod' => Carbon::now()->toIso8601String(),
                'priority' => 1 - substr_count($request->getPathInfo(), '/') / 10,
                'changefreq' => $changefreq
            ];
            \Cache::put('sitemap', $aSiteMap, 2880);
        }
        return $next($request);
    }
}

And create new view file resources\views\sitemap.blade.php

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
        xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
    @foreach( Cache::get('sitemap') as $url => $params )
    <url>
        <loc>{{$url}}</loc>
        <lastmod>{{$params['lastmod']}}</lastmod>
        <changefreq>{{$params['changefreq']}}</changefreq>
        <priority>{{$params['priority']}}</priority>
    </url>
    @endforeach
</urlset>

Add an entry to protected $middleware array in the file app\Http\Kernel.php

'sitemap' => 'App\Http\Middleware\sitemap'
FDisk
  • 8,493
  • 2
  • 47
  • 52
  • 1
    This is vor laravel 5. This will generate site map by visiting pages. – FDisk Feb 19 '15 at 13:59
  • I don't know why your answer not have any rate. +1 – Viet Nguyen Jan 01 '16 at 03:18
  • where does he goes trough every link in the web? this looks like he gets something from cache – Raul H Mar 18 '16 at 22:38
  • No matter who goes trough links. Even you or bot or any other visitor. All visited links are cached and then from cache sitemap is generated. – FDisk Mar 20 '16 at 19:03
  • Won't this also include pages that don't exist (404 pages), but have been visited? – Sina Sep 20 '16 at 06:57
  • probably you should check the headers, but in worst scenario only one 404 page will be indexed. 404 page is still valid page - so why it should not to be in sitemap? – FDisk Oct 07 '16 at 15:39
  • 1
    I don't like and recommend this way, because: – Paul Basenko Apr 07 '17 at 09:08
  • 2
    just because? or what? – FDisk Apr 14 '17 at 20:13
  • @FDisk I want to exclude a few paths. How can I do that? Also, this adds every link, even the personalized links of users to cache. I want it to see only the pages which can be visited as guest. – vish4071 Sep 04 '18 at 12:31
  • Thanks FDisk. I did some changes to improve the middleware. https://gist.github.com/johnroyer/745ac3b0a88b2a43d8dac42427f55aa9 – Zero Huang Feb 17 '22 at 06:19
  • @vish4071: there is another solution. but I thinks it is too complicated. https://github.com/spatie/laravel-sitemap – Zero Huang Feb 17 '22 at 06:21
7

Suppose you want your website's sitemap.xml file to include links to all doctors and patients you have in the database, you can do so like this:

in routes.php file..

Route::get("sitemap.xml", array(
    "as"   => "sitemap",
    "uses" => "HomeController@sitemap", // or any other controller you want to use
));

in HomeController.php file (if you decided to use HomeController)..

public function sitemap()
{
    $doctors = Doctor::remember(59) // chach this query for 59 minutes
        ->select(["id", "updated_at"]) 
        // you may want to add where clauses here according to your needs
        ->orderBy("id", "desc")
        ->take(50000) // each Sitemap file must have no more than 50,000 URLs and must be no larger than 10MB
        ->get();

    $patients = Patient::remember(59) // chach this query for 59 minutes
        ->select(["id", "updated_at"]) 
        // you may want to add where clauses here according to your needs
        ->orderBy("id", "desc")
        ->take(50000) // each Sitemap file must have no more than 50,000 URLs and must be no larger than 10MB
        ->get();

    $content = View::make('sitemap', ['doctors' => $doctors, 'patients' => $patients]);
    return Response::make($content)->header('Content-Type', 'text/xml;charset=utf-8');
}

in views/sitemap.blade.php file..

<?php echo '<?xml version="1.0" encoding="UTF-8"?>' ?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@foreach($doctors as $doctor)
    <url>
        <loc>{{ URL::route("doctors.show", [$doctor->id]) }}</loc>
        <lastmod>{{ gmdate(DateTime::W3C, strtotime($doctor->updated_at)) }}</lastmod>
        <changefreq>daily</changefreq>
        <priority>1.0</priority>
    </url>
@endforeach

@foreach($patients as $patient)
    <url>
        <loc>{{ URL::route("patients.show", [$patient->id]) }}</loc>
        <lastmod>{{ gmdate(DateTime::W3C, strtotime($patient->updated_at)) }}</lastmod>
        <changefreq>daily</changefreq>
        <priority>1.0</priority>
    </url>
@endforeach
</urlset>
Amr
  • 4,809
  • 6
  • 46
  • 60
4

check https://github.com/RoumenDamianoff/laravel-sitemap

A simple sitemap generator for Laravel 4.

Route::get('sitemap', function(){

    // create new sitemap object
    $sitemap = App::make("sitemap");

    // set cache (key (string), duration in minutes (Carbon|Datetime|int), turn on/off (boolean))
    // by default cache is disabled
    $sitemap->setCache('laravel.sitemap', 3600);

    // check if there is cached sitemap and build new only if is not
    if (!$sitemap->isCached())
    {
         // add item to the sitemap (url, date, priority, freq)
         $sitemap->add(URL::to('/'), '2012-08-25T20:10:00+02:00', '1.0', 'daily');
         $sitemap->add(URL::to('page'), '2012-08-26T12:30:00+02:00', '0.9', 'monthly');

         // get all posts from db
         $posts = DB::table('posts')->orderBy('created_at', 'desc')->get();

         // add every post to the sitemap
         foreach ($posts as $post)
         {
            $sitemap->add($post->slug, $post->modified, $post->priority, $post->freq);
         }
    }

    // show your sitemap (options: 'xml' (default), 'html', 'txt', 'ror-rss', 'ror-rdf')
    return $sitemap->render('xml');

});

i have used it. works great!

update #1

to clear the confusion, let's take an example.

let's say i have a blog table with id, title, blog

i have the route as, Route::get('blog/{blog}',['as' => 'blog.show', 'uses' => 'Blog@show'];

first i will fetch the content, by $blogs = DB::table('blog')->get();

$blogs will contain the results.

i will just loop,

foreach($blogs as $i)
{
     $sitemap->add(route('blog.show',[$i->title]), '2014-11-11', '1.0','daily');
}

all my blogs are added in the sitemap.

itachi
  • 6,323
  • 3
  • 30
  • 40
  • whats this post table store?? – Zammuuz Nov 13 '14 at 05:47
  • that's an example. you need use your own queries to get the content. – itachi Nov 13 '14 at 05:48
  • thats i understand this is an example. but i didn't get what is stored in that posts table. then only i can create my query. can u plz tell me what u gave in ur project sitemap? is that table stores urls? – Zammuuz Nov 13 '14 at 05:51
  • ok.Thanks for the explanation .. one more doubt (plz forgive i'm a newbie to laravel thats y these much doubts). i've downloaded the laravel-sitemap-master.zip file from the github link ur provided. if i store that extract folder inside the app folder of my laravel project. will this code works?? – Zammuuz Nov 13 '14 at 06:11
  • no. you have to install it via composer. if you don't want to install it via composer, there is a hack but a very ugly one and not 100% gurranteed. – itachi Nov 13 '14 at 06:32
  • I feel like adding home page, about us page etc manually is a waste as your routes are already specified in `routes.php`. Why can't all this just be done for you... – tread Aug 13 '16 at 10:07
  • I tried this in blog website where i store my blog as HTML content. I have tried to implement this but i havean error--> ```Incorrect http header content-type: "text/html; charset=UTF-8" (expected: "application/xml") ``` How will i implement this to Automatically Generate Sitemap with Laravel – Wesley-Sinde Jun 15 '22 at 07:29
  • Good explanation, i have my blog content stored as html, users save the content as raw html, how will i show this in sitemap? I have used the above example but i get an errror that my data is not xlm – Wesley-Sinde Jul 24 '22 at 09:25