Skip to content

Instantly share code, notes, and snippets.

Last active December 10, 2018 16:47
What would you like to do?
Legacy Redirector for Sculpin 3

Legacy Redirector for Sculpin 3

This class listens to the AFTER_RUN event in Sculpin 3 and locates pagination files (Page 2 and above) in order to generate a placeholder file that matches the legacy version from Sculpin 2. There was a bug in Sculpin 2 that resulted in these files being named like 2.html when the intent was actually to name them 2/index.html for friendly URLs.

The output of the redirector is a very spartan HTML-based redirect. Should be sufficient for convincing search engines and the like to update their mappings.

This has been tested with Sculpin 3.0.0-ALPHA1.


Append the contents of sculpin_kernel.yml to your existing sculpin_kernel.yml.

Place LegacyRedirector.php somewhere that the composer autoloader can find it. In my case, I used a PSR-4 autoloader definition in my composer.json & ran composer update:

  "autoload": {
    "classmap": ["component-manager.php"],
    "psr-4": {
      "Beryllium\\Whateverthing\\": "app/src/"

Then I placed the file in the app/src/ folder.

Now, when generating your site, you should get both 2.html (containing the HTML redirect) and 2/index.html, containing the actual Page 2 content.

namespace Beryllium\Whateverthing;
use Sculpin\Core\Event\SourceSetEvent;
use Sculpin\Core\Output\FilesystemWriter;
use Sculpin\Core\Output\OutputInterface;
use Sculpin\Core\Permalink\Permalink;
use Sculpin\Core\Permalink\PermalinkInterface;
use Sculpin\Core\Sculpin;
use Sculpin\Core\Source\MemorySource;
use Sculpin\Core\Source\SourceInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
* Listen for the Sculpin\Core\Sculpin::EVENT_AFTER_RUN event and scan the entire SourceSetEvent space to look for
* pagination artifacts. Then, if artifacts are found, write temporary redirect files to the "old" locations (2.html).
* @package Beryllium\Whateverthing
* @author Kevin Boyd -
class LegacyRedirector implements EventSubscriberInterface {
protected $writer;
public function __construct(FilesystemWriter $writer) {
$this->writer = $writer;
public static function getSubscribedEvents() {
return [
Sculpin::EVENT_AFTER_RUN => 'onAfterRun',
public function onAfterRun(SourceSetEvent $event) {
/** @var SourceInterface $source */
foreach ($event->updatedSources() as $source) {
if (!($source instanceof MemorySource)) {
if (false === strpos($source->sourceId(), ':page=')) {
$matches = [];
if (!preg_match('#/page/([0-9]+)$#', $source->permalink()->relativeUrlPath(), $matches)) {
if ($matches[1] === '1') {
$output = $this->buildOutput($source);
public function buildOutput(SourceInterface $source) {
return new class($source) implements OutputInterface {
public $originalPermalink;
public $permalink;
public $source;
public function __construct(SourceInterface $source) {
$this->originalPermalink = $source->permalink();
$this->source = $source;
$this->permalink = new Permalink(
ltrim($source->permalink()->relativeUrlPath(), '/') . '.html',
public function outputId(): string {
return $this->source->sourceId() . '_legacy_redirect';
public function pathname(): string {
return $this->permalink->relativeFilePath();
public function permalink(): PermalinkInterface {
return $this->permalink;
public function hasFileReference(): bool {
return false;
public function file(): \SplFileInfo {
return null;
public function formattedContent(): string {
$redirectUrl = basename($this->originalPermalink->relativeUrlPath());
return <<<EOR
<meta http-equiv="refresh" content="0; URL=$redirectUrl" />
</head><body /></html>
class: Beryllium\Whateverthing\LegacyRedirector
$writer: '@sculpin.writer'
- 'kernel.event_subscriber'
public: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment