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.

Plugins

Plugins and caching

Solved by pamtbaau View solution

Started by Aaron Dalton 8 years ago · 10 replies · 1512 views
8 years ago

I manage a Google Charts plugin. The problem is that if caching is on, the graphs only render on the first page hit. The graphs never render in the cached versions. Is there something I can do on the plugin end of things to rectify this?

8 years ago Solution

@Perlkonig Your plugin is using grav-plugin-shortcode-core to process the shortcode embedded in the page.

Inside your GChartShortcode::process() function you call addInlineJS to add Google's charting scripts.
ShortCode_Core calls your GChartShortcode::process() function inside Grav's onPageContentProcessed event. This event is only called once when cache is enabled.

On first run, the shortcode in the page is perfectly replaced by the placeholder for the chart. Also your inline javascript gets added to the Assets manager and added to the <head> of the page.

I'm just a Grav newbee and not that knowledgable on caching, so the following might be wrong.

While debugging the processing of a page, I noticed that Assets::js() is called on every page request. So assets are probably not cached and need to be added to the Asset manager at each request. Since your code is only called once on first page load, the required Google Charts script is no longer added. You can see in the generated page on subsequent loads that the scripts are missing.

When I change your script a little, the script is embedded into the page and also cached.

PHP
// $this->grav['assets']->addInlineJs($code);
...
return $output . "<script>$code</script>";

Now, the chart is shown on each and every page request. Cached or not...

👍 1
last edited 07/06/18 by pamtbaau
8 years ago

I will take a look, thanks. I need to look more closely at why exactly things aren't rendering, because if you're online, even a cached version should redraw. Is there a way to manually add things to a cache? Back to the docs!

8 years ago

Thanks! I'll take a look this weekend.

8 years ago

I guess I just assumed that doing it "right" by adding the code through the assets pipeline that the caching would be done automatically. I'll do some doc diving this weekend.

8 years ago

One strategy I implemented recently, to solve basically the same problem - assets would not render properly that were instantiated by a specific template (not global) - is to disable the cache for that specific template by having the plugin temporarily disable it.

8 years ago

@Perlkonig

Looking for an alternative to my previous solution where javascript is embedded in the cached page content.

Not sure which one is better, more efficient, or cleaner...

TLDR:

  • In GChartShortcode::process() save generated script into frontmatter of page.
  • Fetch javascript from page's frontmatter in google-charts.php during onTwigSiteVariables event and add to assets .
  • Charts will be drawn when cache is off and on...

Longread:
Did some tests to find the event when assest can be added. onTwigSiteVariables seems to be one of the latest. And it is after onPageContentProcessed in which your process() is running.

I made the following changes to your GChartShortcode::process():

  • Removed both addAssets()
  • Added the following right after you generated the javascript into $code:
    PHP
    $header->set('google-charts.test.script', $code);
    $this->grav['page']->header($header->items);
    $this->grav['page']->save();
    

And added the following function in google-charts.php:

PHP
public function onTwigSiteVariables()
{
    $header = $this->grav['page']->header();
    $header = new \Grav\Common\Page\Header((array) $header);
    $script = $header->get('google-charts.test.script');

    $this->grav['assets']->addJs('https://www.gstatic.com/charts/loader.js', ['group' => 'bottom']);
    $this->grav['assets']->addInlineJs($script, ['loading' => 'inline', 'group' => 'bottom']);
}

This way, the scripts are added in onTwigSiteVariables which is run when cache is both false and true.

8 years ago

This seems like the simplest solution. I'm going with this for now, but I'll do some reading this weekend on the other suggestions you made and decide if there's a "better" way. Thanks for your time, everyone!

8 years ago

Can't help being curious...

In GChartShortcode::process() you add assets in the following two ways:

PHP
1) $this->shortcode->addAssets('js', 'https://www.gstatic.com/charts/loader.js');
2) $this->grav['assets']->addInlineJs($code);

I was wondering, why does 1) get added while 2) does not when cache is enabled? Assets are not cached, so Shortcode Core must be doing something else. After some code digging...

Shortcode Core is using an approach that looks a bit like what I suggested in reply #9. However they do not store it inside the page's frontmatter (which I find kind of ugly), but in the page's metaContent, which also get's cached and can be retrieved later in onTwigSiteVariables.

Using this technique the approach could be as follows:
In your GChartShortcode::process():

  • Remove both addAssets()
  • Add the following right after you generated the javascript into $code:

    PHP
    $this->grav['page']->addContentMeta('gchart-script', $code);
    

    And add the following function in google-charts.php:

    PHP
    public function onTwigSiteVariables()
    {
    $code = $this->grav['page']->getContentMeta('gchart-script');
    
    $this->grav['assets']->addInlineJs($code);
    $this->grav['assets']->addJs('https://www.gstatic.com/charts/loader.js');
    }
    

    Pros & cons:

  • The advantage of this approach over injecting the javascript into the processed page content (reply #4), is that you gain flexibility as to how you would like to add the assets using priority, grouping, pipelining etc.
  • This disadvantage is it requires more coding...
  • The advantage of this approach over storing the script inside the page's frontmatter (reply #9) is that the end-user will not be confronted with a rather large chunk of code when editing the page.

I think I should close this chapter now...

Suggested topics

Topic Participants Replies Views Activity
Plugins · by Rene, 1 week ago
2 47 1 week ago
Plugins · by Xavier, 4 weeks ago
2 56 4 weeks ago
Plugins · by Luka Prinčič, 7 years ago
3 1183 1 month ago
Plugins · by Sebastian van de Meer, 1 month ago
1 50 1 month ago
Plugins · by PIERROT Alain, 2 months ago
3 74 2 months ago