Grav as Headless CMS

Did u accomplished to access the md files with gatsby? That would be great. I mean it should be possible right?

I’ve been looking at this from all angles and coming to the conclusion it might just be easier to work with md files directly in Gatsby. As mush as I want to use Grav!

I was thinking for instance to make a symlink from the md folder in Grav to Gatsby, but then the way Grav arranges it’s md files doesn’t play well with Gatsby. Unless you can change how Gatsby looks at the md file arrangement?

Sadly, as much as I like Grav and want this to work with Gatsby, it seems the only way is going to have to be through some kind of json api setup. Similar to WordPress’s WP REST API.

After playing with Grav a bit and using it without the Admin plugin, one thing Grav showed me was, maybe it’s not that bad to work with raw md files for content. Combine that with Gatsby’s JSX in Markdown features…

This could be a pretty schweet union though if someone clever has some ideas on how to marry the two?

Well, hello.
I don’t know if you figure it out but thanks to this topic I did.

Thanks to pages as data plugin and this comment

I was able to make plugin which shows all of the information from the page child.
The plugin:

<?php
namespace Grav\Plugin;

use Composer\Autoload\ClassLoader;
use Grav\Common\Plugin;

class PageAsDataPlugin extends Plugin {
  const api = '/api/';
  /** The url of page being called */
  protected $pageUrl;

  public static function getSubscribedEvents() {
    return [
      'onPluginsInitialized' => [
        ['onPluginsInitialized', 0]
      ],
    ];
  }

  public function onPluginsInitialized() {
    if ($this->isAdmin()) {
      return;
    }
    // Enable the main events we are interested in
    $lengthApi = strlen(self::api);
    $url = $this->grav['uri']->url();

    // If the API is being called
    if (substr($url, 0, strlen(self::api)) === self::api) {
      $this->pageUrl = substr($url, $lengthApi - 1);
      $this->enable([
        'onPageInitialized' => ['deliverFormatAs', 0]
      ]);
    }
  }

  /**
   * Delivers the page as a different format.
   */
  public function deliverFormatAs($event) {
    /**
     * @var \Grav\Common\Page\Page $page
     */
    $pages = $this->grav['pages'];
    $page = $pages->find($this->pageUrl);
    $collection = $page->collection('content');
    $pageArray = $page->toArray();
    $children = array();
    foreach ($collection as $item) {
      $children[] = $item->toArray();
    }
    $pageArray['children'] = $children;
    header("Content-Type: application/json");
    echo json_encode($pageArray);
    exit();
  }
}

/**
 * Converts an array to XML
 *  http://www.devexp.eu/2009/04/11/php-domdocument-convert-array-to-xml/
 */
/**
 * Extends the DOMDocument to implement personal (utility) methods.
 * - From: http://www.devexp.eu/2009/04/11/php-domdocument-convert-array-to-xml/
 * - parent:: See http://www.php.net/manual/en/class.domdocument.php
 *
 * @throws   DOMException   http://www.php.net/manual/en/class.domexception.php
 *
 * @author Toni Van de Voorde
 */
class PageAsDataXmlDomConstructor extends \DOMDocument {
  public function fromMixed($mixed, \DOMElement $domElement = null) {
    $domElement = is_null($domElement) ? $this : $domElement;
    if (is_array($mixed)) {
      foreach ($mixed as $index => $mixedElement) {
        if (is_int($index)) {
          if ($index == 0) {
            $node = $domElement;
          } else {
            $node = $this->createElement($domElement->tagName);
            $domElement->parentNode->appendChild($node);
          }
        } else {
          $node = $this->createElement($index);
          $domElement->appendChild($node);
        }
        $this->fromMixed($mixedElement, $node);
      }
    } else {
      $domElement->appendChild($this->createTextNode($mixed));
    }
  }
}

Everytime someone checks the page (but with the URL /api/ prefix) those 2 lines are called:

header("Content-Type: application/json");
echo json_encode($pageArray);

They transform the page and its child into the JSON (which is exactly what we need).

Then the Gatsby.
This was really tricky because I tried to repair and edit the plugin described in the article @bleutzinn posted:

Sadly, some libraries didn’t work. Then I found something amazing. Gatsby has a plugin called Gatsby Source Custom API which is created for you to link it with your CMS.

Thanks to this plugin I was finally able to connect to my domain.com/api/page

And weeeell, that’s all. This do all the magic.
I know it’s after 3 years but maybe, maybe someone like me will find it useful.

1 Like