Skip to content
Grav 2.0 is officially stable. Read the announcement →

Community guidelines

Please keep discussions civil and on-topic. Repeated violations may lead to a temporary ban.

Support

Grav as Headless CMS

Started by björn 6 years ago · 22 replies · 6157 views
6 years ago

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

6 years ago

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?

3 years ago

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

@bleutzinn:
You are referring to Grav Pages as Data Plugin

Thanks to pages as data plugin and this comment

@pamtbaau:
@bjorn, Although I do not know much about your specific requirements, the rest-API of WP comes to mind.

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

PHP
<?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:

TXT
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:

@bleutzinn:
I kind of just stumbled upon Awesome Grav Stuff which includes a link to a rather lengthy and detailed article “Grav as Headless CMS Tied to Gatsby with GraphQL Schema”.

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

Suggested topics

Topic Participants Replies Views Activity
Support · by Thomas, 1 week ago
2 57 15 hours ago
Support · by Anna, 3 days ago
2 65 18 hours ago
Support · by Justin Young, 18 hours ago
1 33 18 hours ago
Support · by Duc , 1 week ago
2 68 5 days ago
Support · by Colin Hume, 1 week ago
2 60 6 days ago