Skip to content

Commit

Permalink
Collections & taxonomies sitemaps with rapidez/sitemap (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinmeijer97 authored Dec 6, 2024
1 parent 01e1904 commit eeef1be
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 1 deletion.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ For example; If you created a global with the handle `header` and added a field

When you create a form you could use `rapidez-statamic::emails.form` as HTML template which uses the [Laravel mail template](https://laravel.com/docs/master/mail#customizing-the-components) with all fields in a table, make sure you enable markdown!

### Sitemap

We hook into the [Rapidez Sitemap](https://github.com/rapidez/sitemap) generation by adding our Statamic-specific sitemaps to the store's sitemap index.

For each store, we generate sitemaps for collections and taxonomies that have actual routes and content. The XML files will be stored in the configured sitemap disk (defaults to 'public') under the configured path (defaults to 'rapidez-sitemaps') with the following structure:
```shell
rapidez-sitemaps/{store_id}/{sitemap_prefix}_collection_{collection_handle}.xml
rapidez-sitemaps/{store_id}/{sitemap_prefix}_taxonomy_{taxonomy_handle}.xml
```

The sitemap prefix can be configured in the `rapidez.statamic.sitemap.prefix` config.

### Upgrading

Since 3.0.0 we have started using optionalDeep for the $globals, and $content variables.
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@
"prefer-stable": true,
"require": {
"php": "^8.1|^8.2",
"justbetter/statamic-glide-directive": "^2.1",
"rapidez/blade-directives": "^0.6",
"rapidez/core": "^2.13",
"justbetter/statamic-glide-directive": "^2.1",
"rapidez/sitemap": "^1.1",
"spatie/once": "*",
"statamic-rad-pack/runway": "^7.6",
"statamic/cms": "^5.0",
Expand Down
4 changes: 4 additions & 0 deletions config/rapidez/statamic.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,9 @@
'disabled' => false,
],
],
],

'sitemap' => [
'prefix' => env('STATAMIC_SITEMAP_PREFIX', 'statamic_sitemap_')
]
];
16 changes: 16 additions & 0 deletions src/Actions/GenerateSitemapsAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Rapidez\Statamic\Actions;

use Statamic\Facades\Site;
use Rapidez\Statamic\Jobs\GenerateStoreSitemapJob;

class GenerateSitemapsAction
{
public static function generate(): void
{
Site::all()->each(function ($site) {
GenerateStoreSitemapJob::dispatchSync($site);
});
}
}
50 changes: 50 additions & 0 deletions src/Jobs/GenerateCollectionSitemapJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Rapidez\Statamic\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Storage;
use Rapidez\Sitemap\Actions\GenerateSitemapAction;
use Statamic\Sites\Site;
use Statamic\Entries\Collection;
use Statamic\Entries\Entry;

class GenerateCollectionSitemapJob implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable;

public function __construct(
protected Site $site,
protected Collection $collection,
) {}

public function handle(GenerateSitemapAction $sitemapGenerator): void
{
$storeId = $this->site->attribute('magento_store_id');
$path = trim(config('rapidez-sitemap.path', 'rapidez-sitemaps'), '/');
$storageDirectory = $path.'/'.$storeId.'/';

$sitemapPath = $storageDirectory
. config('rapidez.statamic.sitemap.prefix')
. 'collection_'
. $this->collection->handle()
. '.xml';

$sitemapContent = $sitemapGenerator->createSitemapUrlset($this->generateCollectionSitemap());
$storageDisk = Storage::disk(config('rapidez-sitemap.disk', 'public'));
$storageDisk->put($sitemapPath, $sitemapContent);
}

protected function generateCollectionSitemap() : array
{
$entries = $this->collection->queryEntries()->where('site', $this->site->handle())->whereStatus('published')->get();
return $entries->map(fn (Entry $entry) => [
'loc' => $entry->url(),
'lastmod' => $entry->lastModified()
])->toArray();
}
}
86 changes: 86 additions & 0 deletions src/Jobs/GenerateStoreSitemapJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Rapidez\Statamic\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Storage;
use Statamic\Facades\Collection as StatamicCollection;
use Statamic\Facades\Taxonomy as TaxonomyFacade;
use Statamic\Sites\Site;
use Statamic\Entries\Collection;
use TorMorten\Eventy\Facades\Eventy;

class GenerateStoreSitemapJob implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable;

public function __construct(
protected Site $site
) {}

public function handle(): void
{
$this->createCollectionSitemaps();
$this->createTaxonomySitemaps();
$this->addSitemapFilter();
}

protected function createCollectionSitemaps() : void
{
$collections = StatamicCollection::all();
$collections = $collections->filter(fn (Collection $collection) => $collection->route($this->site->handle()));

foreach ($collections as $collection) {
/* @var Collection $collection */
if ($collection->queryEntries()->where('site', $this->site->handle())->whereStatus('published')->count()) {
GenerateCollectionSitemapJob::dispatchSync($this->site, $collection);
}
}
}

protected function createTaxonomySitemaps() : void
{
$taxonomies = TaxonomyFacade::all()
->filter(function ($taxonomy) {
$terms = $taxonomy->queryTerms()
->where('site', $this->site->handle())
->get();

return $terms
->filter(function ($term) {
return view()->exists($term->template());
})->isNotEmpty();
});

foreach ($taxonomies as $taxonomy) {
/* @var Taxonomy $taxonomy */
GenerateTermSitemapJob::dispatchSync($this->site, $taxonomy);
}
}

protected function addSitemapFilter() : void
{
$storeId = $this->site->attribute('magento_store_id');
$storageDisk = Storage::disk(config('rapidez-sitemap.disk', 'public'));
$path = trim(config('rapidez-sitemap.path', 'rapidez-sitemaps'), '/');
$storageDirectory = $path.'/'.$storeId.'/';

$sitemapPrefix = config('rapidez.statamic.sitemap.prefix');

$sitemaps = collect($storageDisk->files($storageDirectory))
->filter(fn($item) => str_starts_with($item, $storageDirectory . $sitemapPrefix))
->map(fn($item) => [
'loc' => url($item),
'lastmod' => $storageDisk->lastModified($item)
? date('Y-m-d H:i:s', $storageDisk->lastModified($item))
: null
])
->toArray();

Eventy::addFilter('rapidez.sitemap.' . $storeId, fn($rapidezSitemaps) => array_merge($rapidezSitemaps, $sitemaps));
}
}
67 changes: 67 additions & 0 deletions src/Jobs/GenerateTermSitemapJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Rapidez\Statamic\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Storage;
use Rapidez\Sitemap\Actions\GenerateSitemapAction;
use Statamic\Facades\Taxonomy as TaxonomyFacade;
use Statamic\Sites\Site;
use Statamic\Taxonomies\LocalizedTerm;
use Statamic\Taxonomies\Taxonomy;

class GenerateTermSitemapJob implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable;

public function __construct(
protected Site $site,
protected Taxonomy $taxonomy,
) {}

public function handle(GenerateSitemapAction $sitemapGenerator): void
{
$storeId = $this->site->attribute('magento_store_id');
$path = trim(config('rapidez-sitemap.path', 'rapidez-sitemaps'), '/');
$storageDirectory = $path.'/'.$storeId.'/';

$sitemapPath = $storageDirectory
. config('rapidez.statamic.sitemap.prefix')
. 'taxonomy_'
. $this->taxonomy->handle()
. '.xml';

$sitemapContent = $sitemapGenerator->createSitemapUrlset($this->generateTermSitemap());
$storageDisk = Storage::disk(config('rapidez-sitemap.disk', 'public'));
$storageDisk->put($sitemapPath, $sitemapContent);
}


protected function generateTermSitemap() : array
{
$terms = $this->publishedTerms();
return $terms->map(fn (LocalizedTerm $term) => [
'loc' => $term->absoluteUrl(),
'lastmod' => $term->lastModified()
])->toArray();
}

protected function publishedTerms()
{
return TaxonomyFacade::all()
->flatMap(fn ($taxonomy) => $taxonomy->queryTerms()
->where('site', $this->site->handle())
->whereNotNull('uri')
->get()
)
->filter
->published()
->filter(function ($term) {
return view()->exists($term->template());
});
}
}
10 changes: 10 additions & 0 deletions src/RapidezStatamicServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Statamic\Events\GlobalSetDeleted;
use Illuminate\Support\ServiceProvider;
use Illuminate\View\View as RenderedView;
use Rapidez\Statamic\Actions\GenerateSitemapsAction;
use Rapidez\Statamic\Commands\ImportBrands;
use Rapidez\Statamic\Commands\InstallCommand;
use Rapidez\Statamic\Forms\JsDrivers\Vue;
Expand Down Expand Up @@ -54,6 +55,7 @@ public function boot()
->bootComposers()
->bootPublishables()
->bootUtilities()
->bootSitemaps()
->bootStack();

Vue::register();
Expand Down Expand Up @@ -215,6 +217,14 @@ public function bootUtilities() : static
return $this;
}

public function bootSitemaps(): static
{
Eventy::addAction('rapidez.sitemap.generate', fn() => GenerateSitemapsAction::generate(), 20, 1);

return $this;
}


public function bootStack() : static
{
if (! $this->app->runningInConsole()) {
Expand Down

0 comments on commit eeef1be

Please sign in to comment.