Skip to content

Instantly share code, notes, and snippets.

@nikazooz
Created August 29, 2018 22:12
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nikazooz/6cce7944dbef8db376bd73ed240220bd to your computer and use it in GitHub Desktop.
Save nikazooz/6cce7944dbef8db376bd73ed240220bd to your computer and use it in GitHub Desktop.
Tags and archives with Jigsaw
<?php
namespace App\Listeners;
use TightenCo\Jigsaw\Jigsaw;
use App\PseudoCollectionGenerator;
use Illuminate\Support\Collection;
class AddArchivePages extends PseudoCollectionGenerator
{
/**
* Helpers that should be registered.
*
* @return array
*/
protected static function helpers()
{
return [
'getPostsForYear' => function ($page, $posts) {
return $posts->filter(function ($post) use ($page) {
return date('Y', $post->date) === $page->year;
});
},
'getPostsForYearAndMonth' => function ($page, $posts) {
return $page->getPostsForYear($posts)->filter(function ($post) use ($page) {
return date('m', $post->date) === $page->month;
});
},
'getPostsForYearMonthAndDay' => function ($page, $posts) {
return $page->getPostsForYearAndMonth($posts)->filter(function ($post) use ($page) {
return date('d', $post->date) === $page->day;
});
},
];
}
/**
* Get new collections configurations.
*
* @return \Illuminate\Support\Collection
*/
protected function getCollectionsConfigurations()
{
$collections = collect();
$dates = $this->getDates($this->jigsaw);
$this->setPostsByYearCollection($dates, $collections);
$this->setPostsByMonthCollection($dates, $collections);
$this->setPostsByDayCollection($dates, $collections);
return $collections;
}
/**
* Get all dates when we have posts in form of array with year, month and day.
*
* @param \TightenCo\Jigsaw\Jigsaw $jigsaw
* @return \Illuminate\Support\Collection
*/
protected function getDates(Jigsaw $jigsaw)
{
return $jigsaw->getCollection('posts')->map(function ($post) {
return [
'year' => date('Y', $post->date),
'month' => date('m', $post->date),
'day' => date('d', $post->date),
];
})->values()->toBase();
}
/**
* Add remote collection `posts by year` into configuration.
*
* @param \Illuminate\Support\Collection $dates
* @return void
*/
protected function setPostsByYearCollection(Collection $dates, Collection $collections)
{
$collections->put('posts_by_year', [
'extends' => '_posts_by_year._index',
'path' => 'blog/{year}',
'items' => $this->getYearItems($dates),
]);
}
/**
* Add remote collection `posts by month` into configuration.
*
* @param \Illuminate\Support\Collection $dates
* @return void
*/
protected function setPostsByMonthCollection(Collection $dates, Collection $collections)
{
$collections->put('posts_by_month', [
'extends' => '_posts_by_month._index',
'path' => 'blog/{year}/{month}',
'items' => $this->getMonthItems($dates),
]);
}
/**
* Add remote collection `posts by day` into configuration.
*
* @param \Illuminate\Support\Collection $dates
* @return void
*/
protected function setPostsByDayCollection(Collection $dates, Collection $collections)
{
$collections->put('posts_by_day', [
'extends' => '_posts_by_day._index',
'path' => 'blog/{year}/{month}/{day}',
'items' => $this->getDayItems($dates),
]);
}
/**
* Get items for posts by year.
*
* @param \Illuminate\Support\Collection $dates
* @return \Illuminate\Support\Collection
*/
protected function getYearItems(Collection $dates)
{
return $this->getYears($dates)->map(function ($year) {
return [
'title' => 'Archive',
'year' => $year,
];
});
}
/**
* Get items for posts by month.
*
* @param \Illuminate\Support\Collection $dates
* @return \Illuminate\Support\Collection
*/
protected function getMonthItems(Collection $dates)
{
return $this->getYears($dates)->map(function ($year) use ($dates) {
return $this->getMonths($dates, $year)->map(function ($month) use ($year) {
return $this->getMonthItem($year, $month);
});
})->flatten(1);
}
/**
* Get items for posts by day.
*
* @param \Illuminate\Support\Collection $dates
* @return \Illuminate\Support\Collection
*/
protected function getDayItems(Collection $dates)
{
return $this->getYears($dates)->map(function ($year) use ($dates) {
return $this->getMonths($dates, $year)->map(function ($month) use ($dates, $year) {
return $this->getDays($dates, $year, $month)->map(function ($day) use ($year, $month) {
return $this->getDayItem($year, $month, $day);
});
});
})->flatten(2);
}
/**
* Get years where we have posts.
*
* @param \Illuminate\Support\Collection $dates
* @return \Illuminate\Support\Collection
*/
protected function getYears(Collection $dates)
{
return $dates->pluck('year')->unique()->values();
}
/**
* Get months of given year where we have posts.
*
* @param \Illuminate\Support\Collection $dates
* @param string $year
* @return \Illuminate\Support\Collection
*/
protected function getMonths(Collection $dates, $year)
{
return $dates->where('year', $year)->pluck('month')->unique()->values();
}
/**
* Get days in given month of given year where we have posts.
*
* @param \Illuminate\Support\Collection $dates
* @param string $year
* @param string $month
* @return \Illuminate\Support\Collection
*/
protected function getDays(Collection $dates, $year, $month)
{
return $dates->where('year', $year)->where('month', $month)->pluck('day')->unique()->values();
}
/**
* Get one posts by month item with metadata.
*
* @param string $year
* @param string $month
* @return array
*/
protected function getMonthItem($year, $month)
{
return [
'title' => 'Archive',
'year' => $year,
'month' => $month,
];
}
/**
* Get one posts by day item with metadata.
*
* @param string $year
* @param string $month
* @param string $day
* @return array
*/
protected function getDayItem($year, $month, $day)
{
return [
'title' => 'Archive',
'year' => $year,
'month' => $month,
'day' => $day,
];
}
}
<?php
namespace App\Listeners;
use TightenCo\Jigsaw\Jigsaw;
use App\PseudoCollectionGenerator;
use Illuminate\Support\Collection;
class AddTagsPages extends PseudoCollectionGenerator
{
/**
* Helpers that should be registered.
*
* @return array
*/
protected static function helpers()
{
return [
'getPostsByTag' => function ($page, $posts) {
return $posts->filter(function ($post) use ($page) {
return in_array($page->tag, $post->tags ?? []);
});
},
];
}
/**
* Get new collections configurations.
*
* @return \Illuminate\Support\Collection
*/
protected function getCollectionsConfigurations()
{
return collect([
'posts_by_tag' => [
'extends' => '_posts_by_tag._index',
'path' => 'blog/tags/{tag}',
'items' => $this->getTagItems(),
],
]);
}
/**
* Map tags to page metadata.
*
* @return \Illuminate\Support\Collection
*/
protected function getTagItems()
{
return $this->getTags()->map(function ($tag) {
return [
'title' => strtoupper($tag),
'tag' => $tag,
];
});
}
/**
* Get all tags used in the posts.
*
* @return \Illuminate\Support\Collection
*/
protected function getTags()
{
return $this->jigsaw->getCollection('posts')
->flatMap->tags
->filter()
->unique()
->values()
->toBase();
}
}
<?php
namespace App;
use Illuminate\Support\Arr;
use TightenCo\Jigsaw\Jigsaw;
use Illuminate\Support\Collection;
use Illuminate\Container\Container;
use TightenCo\Jigsaw\Loaders\DataLoader;
use TightenCo\Jigsaw\Loaders\CollectionRemoteItemLoader;
abstract class PseudoCollectionGenerator
{
/**
* @var \TightenCo\Jigsaw\Jigsaw
*/
protected $jigsaw;
/**
* @var \Illuminate\Support\Collection
*/
protected $collectionData;
/**
* @var \TightenCo\Jigsaw\Loaders\DataLoader
*/
protected $dataLoader;
/**
* @var \TightenCo\Jigsaw\Loaders\CollectionRemoteItemLoader
*/
protected $remoteItemLoader;
/**
* Construct new instance.
*
* @param \TightenCo\Jigsaw\Loaders\DataLoader $dataLoader
* @param \TightenCo\Jigsaw\Loaders\CollectionRemoteItemLoader $remoteItemLoader
*/
public function __construct(DataLoader $dataLoader, CollectionRemoteItemLoader $remoteItemLoader)
{
$this->dataLoader = $dataLoader;
$this->remoteItemLoader = $remoteItemLoader;
}
/**
* Register bindings for listener in the container and start listening for the event.
*
* @param \Illuminate\Container\Container $container
* @return void
*/
public static function register(Container $container)
{
static::registerHelpers($container);
$container->bind(static::class, function ($c) {
return new static($c[DataLoader::class], $c[CollectionRemoteItemLoader::class]);
});
$container->events->afterCollections(function ($jigsaw) use ($container) {
$container->make(static::class)->handle($jigsaw);
});
}
/**
* Register helpers in config.
*
* @param \Illuminate\Container\Container $container
* @return void
*/
protected static function registerHelpers($container)
{
$helpers = static::helpers();
if (empty($helpers)) {
return;
}
$config = $container->config;
foreach($helpers as $helperName => $helper) {
Arr::set($config, $helperName, $helper);
}
$container->instance('config', $config);
}
/**
* Helpers that should be registered.
*
* @return array
*/
protected static function helpers()
{
return [];
}
/**
* Handle `afterCollections` hook to add new collections based on data from existing ones.
*
* @param \TightenCo\Jigsaw\Jigsaw $jigsaw
* @return void
*/
public function handle(Jigsaw $jigsaw)
{
$collectionData = $this->generateCollectionData($jigsaw);
$jigsaw->getSiteData()->addCollectionData($collectionData);
}
/**
* Generate new collection with included new data.
*
* @param \TightenCo\Jigsaw\Jigsaw $jigsaw
* @return \Illuminate\Support\Collection
*/
protected function generateCollectionData(Jigsaw $jigsaw)
{
return $this->setJigsawInstance($jigsaw)
->appendNewCollectionsToConfigurations()
->scheduleCleanup()
->loadCollectionData();
}
/**
* Set working Jigsaw instance.
*
* @param \TightenCo\Jigsaw\Jigsaw $jigsaw
* @return $this
*/
protected function setJigsawInstance(Jigsaw $jigsaw)
{
$this->jigsaw = $jigsaw;
return $this;
}
/**
* Add new collections data to jigsaw site data.
*
* @return $this
*/
protected function appendNewCollectionsToConfigurations()
{
$collections = $this->jigsaw->app->config->get('collections');
$this->appendNewCollectionsTo($collections);
return $this;
}
/**
* Append new collections to given old collections.
*
* @param \Illuminate\Support\Collection $collections
* @return void
*/
protected function appendNewCollectionsTo($collections)
{
$this->getCollectionsConfigurations()
->each(function ($collectionSettings, $collectionName) use ($collections) {
$collections->put($collectionName, $collectionSettings);
});
}
/**
* Get new collections configurations.
*
* @return \Illuminate\Support\Collection
*/
abstract protected function getCollectionsConfigurations();
/**
* Generate collections data for remote collections.
*
* @return $this
*/
protected function loadCollectionData()
{
$siteData = $this->loadSiteData();
$this->writeTempSiteData($siteData);
return $this->dataLoader->loadCollectionData($siteData, $this->jigsaw->getSourcePath());
}
/**
* Load site data with added configurations.
*
* @return \TightenCo\Jigsaw\SiteData
*/
protected function loadSiteData()
{
return $this->dataLoader->loadSiteData($this->jigsaw->app->config);
}
/**
* Write temporary collection pages.
*
* @param \TightenCo\Jigsaw\SiteData $siteData
* @return void
*/
protected function writeTempSiteData($siteData)
{
$this->remoteItemLoader->write($siteData->collections, $this->jigsaw->getSourcePath());
}
/**
* Cleanup temporary collection items.
*
* @return $this
*/
protected function scheduleCleanup()
{
$this->jigsaw->app->events->afterBuild(function () {
$this->remoteItemLoader->cleanup();
});
return $this;
}
}
<?php
App\Listeners\AddArchivePages::register($container);
App\Listeners\AddTagsPages::register($container);
{
"require": {
"tightenco/jigsaw": "^1.2",
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
<?php
return [
'collections' => [
'posts' => [
'extends' => '_layouts.post',
'path' => 'blog/{date|Y/m/d}/{-title}',
'sort' => ['-date'],
],
],
];
date title tags
2018-08-30
Sample post
jigsaw
php

Lorem ipsum dolor sit amet, enim quas patrioque id eum, vis mutat paulo eu, nec cu graecis consequat scribentur. Augue postea verear has ea, in eligendi urbanitas sea. His discere diceret ea. Everti tritani mentitum mei ad.

Ea impetus evertitur mnesarchum vel, nulla vulputate duo et. Oporteat consulatu vim et, esse dissentiunt sit ad. Vis ea summo veritus ancillae. Sed posse accusam delicatissimi no, graecis phaedrum nec eu, utroque corpora volutpat cum ex. Eum explicari expetendis ea.

@extends('_layouts.page')
@section('pageContent')
<h1 class="text-4xl md:text-5xl lg:text-6xl font-normal">Archives</h1>
<p class="text-base md:text-lg lg:text-xl uppercase text-grey">for {{ \Carbon\Carbon::createFromDate($page->year, $page->month, $page->day)->format('F, j Y') }}</p>
<main class="mt-6 sm:mt-12 text-lg antialiased leading-normal" role="main">
@each('_partials.post', $page->getPostsForYearMonthAndDay($posts), 'post')
</main>
@endsection
@extends('_layouts.page')
@section('pageContent')
<h1 class="text-4xl md:text-5xl lg:text-6xl font-normal">Archives</h1>
<p class="text-base md:text-lg lg:text-xl uppercase text-grey">for {{ \Carbon\Carbon::createFromDate($page->year, $page->month, 1)->format('F Y') }}</p>
<main class="mt-6 sm:mt-12 text-lg antialiased leading-normal" role="main">
@each('_partials.post', $page->getPostsForYearAndMonth($posts), 'post')
</main>
@endsection
@extends('_layouts.page')
@section('pageContent')
<h1 class="text-4xl md:text-5xl lg:text-6xl font-normal">{{ $page->tag }}</h1>
<main class="mt-6 sm:mt-12 text-lg antialiased leading-normal" role="main">
@each('_partials.post', $page->getPostsByTag($posts), 'post')
</main>
@endsection
@extends('_layouts.page')
@section('pageContent')
<h1 class="text-4xl md:text-5xl lg:text-6xl font-normal">Archives</h1>
<p class="text-base md:text-lg lg:text-xl uppercase text-grey">for {{ $page->year }}</p>
<main class="mt-6 sm:mt-12 text-lg antialiased leading-normal" role="main">
@each('_partials.post', $page->getPostsForYear($posts), 'post')
</main>
@endsection
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment