Ajax request to a plugin?

Hello there,

I try to port an image gallery that I coded once into kirby but I got some problems figuring out how I could do that.
Basically the gallery gets requested once the page is loaded via an ajax post request like this:

  /**
   * Sends an Ajax request to the server and recieves the gallery
   * @return {boolean}     true on success false on failure
   */
  this.requestGallery = function() {
    var request = new XMLHttpRequest();
    request.open('POST', 'lib/Gallery.php', true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

    // check ajax requests states and show a spinner while request is pending
    request.onreadystatechange = function(){
      switch(request.readyState) {
        ... do something
      }
    };

    // handles the ajax onload event
    request.onload = function() {

      if (request.status >= 200 && request.status < 400) {

        /* Success! */
      ... do something on success

      } 
      else 
      {
        /* We reached our target server, but it returned an error */
        return false;
      }
    };

The server will calculate the gallery and sends back a json object.

But since the gallery is now in a plugin folder I don’t know how I can reach lib/gallery.php

Is something like this possible?

Cheers

What exactly does this gallery.php script contain? You could probably use a route and call functions in that script within the route?

gallery.php is the main class for building the gallery. It calculates equal distributed columns etc.

So it’s not just a simple script. You could compare it to the Guggenheim - An algorithm for a perfectly balanced Gallery for Kirby but in a vertical not a horizontal order.
You can see a demo of it on my webpage

However that was before I did any kirby related work so it was a static page without a cms etc. At the moment the gallery itself is a standalone but as I need a gallery for a recent project, I thought of integrating it to kirby as a plugin (if it is possible ^^).

Yes, ok, but if you want to create a new gallery instance from the class, you would not do it in the plugin but either in your template, in a controller or in a route.

Currently, you have two possibilities to return JSON to your Ajax call: either create a controller or template for an ajax page (so that you get an url) or via a route.

Kirby 2.4 will have content representations, so you can have different templates (and controllers) for different kinds of output.

Kirby 2.4 will have content representations, so you can have different templates (and controllers) for different kinds of output.

Is this similar to custom post types for WP? Can you tell us more? :smiling_face:

Content representations are a way to have different templates/controllers for different types of content, e.g. json, rss or whatever. As far as I know, this is not similar to WP, but I’m not that familiar with the intricacies of Wordpress.

Basically, you will be able to create e.g. a blog.json.php template next to your standard blog.php template that returns json, if you call the same URL with a suffix “.json”.

If you check out the kirby develop branch, you can already test it.

1 Like

So for a route I could do it something like this?

c::set('routes', array(
  array(
    'pattern' => '(:any)/gallery.php',
    'action'  => function() {
      multicolumn();
    },
    'method' => 'POST'
  )
));

But how would I access the current $page in the plugin? I guess passing it through in a router wouldn’t work right?

You could make the current page part of the ajax url , either by passing it to your javascript via a data attribute or extracting it from the url. Then it would be part of your pattern.

Let’s say your (:any) part in pattern was your current page, you could get it like this:

  array(
    'pattern' => '(:any)/gallery.php',
    'action'  => function($uri) {
      $page = page($uri);
      multicolumn();
    },
    'method' => 'POST'
  )
));
```

But you would still need to pass it as a parameter to your `multicolumn()` function.

As Sonja wrote, it does not have anything to do with custom post types. Kirby calls those “blueprints”. :wink:

You can read the docs of the feature already and try it out on the develop branch. :slight_smile:

1 Like

And there is also a yet unpublished cookbook recipe that makes use of the new feature.

1 Like

@texnixe @lukasbestle

Great! I can just confirm that it’s not like WP Custom Post Types.

It seems like a really nice new feature. Who come up with that idea?

Kirby feels like a black box where you unlock things in every new version. :slight_smile:

1 Like

Lukas posted a pull request with that feature quite some time ago. Now it has finally made it into the dev branch and will be in 2.4 :slight_smile:

And yes, really great feature!

1 Like

Yes, I had the idea nearly two years ago. Since I use the feature on my company site, I thought, “well, why not rewrite it to be compatible with Kirby 2.3’s registry” and so I did. :slight_smile:

1 Like

And there is also a yet unpublished cookbook recipe6 that makes use of the new feature.

The link doesn’t work anymore. Maybe it’s moved?

@lukasbestle

I hope it’s possible to also register set a content representation from a plugin. Is it? :slight_smile:

It is now on the master branch.

It sure is. :slight_smile:
You only need to register the respective template or controller to make it work.

1 Like

I found some time to work on this again. I got the ajax request working now but I’m not satisfied with how this is set up at the moment. This is my call:

  this.requestGallery = function() {
    var request = new XMLHttpRequest();
    request.open('POST', 'starterkit/gallery.php', true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

    ...
    ..

However I don’t want starterkit in the route. I would like to check if the page has some gallery element and if yes then just call gallery.php.
If I leave starterkit out and just do “gallery.php” I will get a 404. How would I solve such an issue?

You need to somehow tell the route which page you are referring to, so leaving out the page URI from the route pattern is not going to work. You can definitely just add a route with the pattern gallery.php, but how are you going to get the current page in that file?

Also: Why don’t you just include the gallery JSON directly in the HTML file without the second request?

Not sure if I understand you correctly but at the moment I get the $page object by doing this:

c::set('routes', array(
  array(
      'pattern' => '(:any)/gallery.php',
      'action'  => function($uri) {
        $page = $this->site()->activePage();
        multicolumn($page);
      },
      'method' => 'POST'
  )
));

For your second question. I am requesting the gallery via ajax for performance reasons. The gallery will just get requested when the pages content got loaded.
Further the gallery will just request the images that are in the viewport (plus some offset so you wont notice any loading times). If you scroll down the gallery you will queue additional requests to the server, requesting the missing images. This way you can reduce the number of requests on the initial load by a huge amount while also deferring all unnecessary images (this saves bandwidth on mobile because images deep down “below the fold” would not even get requested). It is just a really performance optimized image gallery that I would like to keep the way it works.

I don’t think $site->activePage() will work inside of a route.

I think you need this:

c::set('routes', array(
  array(
      'pattern' => '(:all)/gallery.json',
      'action'  => function($uri) {
        if($page = page($uri)) {
          multicolumn($page);
        } else {
          return response::error('Invalid page.');
        }
      },
      'method' => 'POST'
  )
));

You can then append /gallery.json to any page URL.

How would I do that?

If I adjust my route to the one you posted I will get error 400: bad request because $page is false: