App themes are rendered via HTML templates, styled with CSS and motorized with Javascript.

Here is how to build a Theme and use the Javascript Theme API to display app content, customize rendering, communicate with app core and implement some key features like data storage or user authentication.

Build Your First Theme

Create a sub-folder in the themes folder (wp-content/themes-wp-appkit). We’ll call it my-theme for this example (wp-content/themes-wp-appkit/my-theme).

Add the following (empty) files in the my-theme folder:

  • my-theme/head.html
  • my-theme/layout.html
  • my-theme/archive.html
  • my-theme/single.html
  • my-theme/menu.html

Add also a js sub-folder (my-theme/js) and a file named functions.js inside it (my-theme/js/functions.js). Even if it’s empty for now, this file is required and is the entry point for all the JavaScript of your theme.

At this point, your theme is a valid WP-AppKit theme and can be seen and chosen in the WordPress admin panel as a theme for one of your apps.

Write “Hello nice and shiny WP-AppKit world :-)” in the layout.html template. Running the app in your browser, you should see your message.

Theme Resources

To style a theme, you can use CSS files, images, fonts… You are free to create your own folders to store your resources. A classic organization can be something like:

  • my-theme/css
  • my-theme/images
  • my-theme/fonts

As for any regular HTML page, we link to our theme’s CSS files in the <head> section. For that, we use the head.html template. As the app engine builds a page, it simply includes the content of the head.html template at the beginning of the <head> tag.

The head.html template is also where you can define your <meta> markup : charset, viewport…

Here is an example of a head.html template. It assumes that you’ve put your CSS rules in a /css/styles.css file in your theme’s folder:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="<%= TemplateTags.getThemePath() %>/css/styles.css" media="all"/>

See the head.html template section for more details.

One important thing to know is that JavaScript files must not be included in the head.html template but included as RequireJS dependencies of functions.js. RequireJS is used by WP-AppKit to handle JavaScript modules dependencies. More details below.

Template Files

Theme templates are HTML files located at the root of the WP-AppKit theme’s folder: wp-content/themes-wp-appkit/[your-theme].

Dynamic parts of templates are rendered using the UnderscoreJS template engine.

In a nutshell, here is how you can use this template engine in your theme’s HTML templates:

  • Any JavaScript can be executed anywhere in your template using <% … %>.
  • To print a JavaScript variable, use <%= my_var %> notation.
  • “if”, “else” or any JavaScript statement can be used inside <% … %>.
  • UnderscoreJS powerful tools can be used of course (eg. _.each)

Each template is loaded by the core with default global variables (title, posts etc…) that can be accessed directly in the template. Those predefined variables change according to which template you’re in and are detailed in the following reference. You can also pass your own custom variables to templates using the template-args filter.

All templates can also use the Template Tags module to retrieve and display dynamic data concerning app entities or current app context.

A short example of a template that could be used to list posts (title, excerpt and comments number) in the archive.html template:

<h1>Posts archive for <%= list_title %></h1>
<% if( posts.length ){ %>
      <ul>
            <% _.each( posts, function( post ){ %>
                  <% var nb_comments = post.nb_comments %>
                  <li>
                        <h2><a href="<%= TemplateTags.getPostLink(post.id) %>"><%= post.title %></a></h2>
                        <p><%= post.excerpt %></p>
                        <span><%= nb_comments %> comment<% nb_comments > 1 ? print('s') : '' %></span>
                  </li>
            <% }); %>
      </ul>
<% }else{ %>
      <p>No post found!</p>
<% } %>
First Templates

As an example let’s see how to display a simple WordPress page in our minimalist app using the layout.html and single.html templates:

Provided you have set a page as first navigation element on the WordPress side (by default, first navigation element is displayed at app’s launch), add the following in the layout.html template:

<h1>My app</h1>
<%= content %>

And in your single.html template:

<h2><%= post.title %></h2>
<div class="my-content">
   <%= post.content %>
</div>

Run your app in a browser, you should see your page content. Take a look at the rendered HTML, you see something like:

<body>
   <div id="app-layout">
      <h1>My app</h1>
      <div id="app-content-wrapper">
         <div class="app-screen">
            <h2><!-- Your wordpress page title --></h2>
            <div class="my-content">
               <!-- Your wordpress page content -->
            </div>
         </div>
      </div>
   </div>
</body>

Next step is probably to use the menu.html template to display the app’s menu, and the archive.html to display a list of WordPress posts. But before that you certainly want your app to look a little better using some CSS. Let’s do that with the head.html template.

Head.html

The Head.html template is where you add the resources (CSS, images… but not javascript as explained here) and define HTML metas (viewport, content-type…) needed by your app’s theme.

Internally, the content of the head.html template file is copied to the <head> tag.

Example of a head.html template that uses the Bootstrap front-end framework CSS:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title><%= app_title %></title>
<link rel="stylesheet" href="<%= TemplateTags.getThemePath() %>/css/bootstrap.min.css">
<link rel="stylesheet" href="<%= TemplateTags.getThemePath() %>/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="<%= TemplateTags.getThemePath() %>/css/styles.css" media="all"/>

In the head.html template, the following variable is automatically defined:

  • app_title: the Application Title defined in the WordPress admin panel.

The TemplateTags.getThemePath() template tag retrieves the path to your theme’s folder. Use it to be sure that your resources are located correctly by the app.

Layout.html

The layout.html template is where you define the HTML app’s skeleton. Before doing so, you may take a look back at the Layout’s areas section where the main app regions are detailed.

In the layout.html template, you set the location of the menu and the content elements, using the following layout template tags:

  • <%= menu %>: displays the menu items, using the menu.html template. The menu is rendered in a div with id #app-menu.
  • <%= content %>: displays the main content using the appropriate template (ie. single.htmlarchive.html or comments.html) depending on which app’s screen is currently displayed. The content is rendered in a div with the id #app-content-wrapper.

<%= app_title %> can be used to display the title of the application. This is the Application Title defined in the WordPress admin panel for the app (same as in the head.html template).

As explained here, don’t forget to put to good use of the fact that the HTML markup defined in this template (that is to say everything except the dynamic layout tags <%= … %>) will stay static during all the app’s life cycle, which means that the app’s core won’t modify it. So you are the only master of the JavaScript events that you may bound to it to dynamize your DOM. Layout.html is the only template where this is the case: all other templates (included via  <%= menu %> or <%= content %>) are handled (modified/created/deleted) by the app’s engine. So interact with those using JavaScript requires more binding/unbinding events logic, with the help of the app’s core events API.

In a word :

  • Put all the HTML structure you can in the layout.html because you will be able to interact with it easily in JavaScript.
  • Avoid as much as possible to define dynamic DOM elements in the other templates, where it is more difficult (yet very possible) to maintain JavaScript dynamization.

An example of a minimalist layout.html template :

<div id="my-container">
   <div id="my-topbar"><span id="my-menu-button"></span> <%= app_title %></div>
   <div id="my-menu-drawer"><%= menu %></div>
   <%= content %>
</div>
Archive.html

The archive.html template is used to render post lists, typically corresponding to the Posts List WP-AppKit component in the WordPress admin panel.

The global variables accessible in this template are:

  • list_title: the label of the Post List component defined in the WordPress admin panel.
  • posts: array of the posts to display for this archive (only for the current page of the pagination). Each post of this list is a JSON object. See the single.html template for detailed reference of what each post contains.
  • total: total number of posts for this archive (not only those present on this page of the pagination).

Archive.html example:

<h1>Posts archive for <%= list_title %> (Total <%= total %>)</h1>
<% if( posts.length ){ %>
      <ul>
            <% _.each( posts, function( post ){ %>
                  <% var nb_comments = post.nb_comments %>
                  <li>
                        <h2>
                              <a href="<%= TemplateTags.getPostLink(post.id) %>"><%= post.title %></a>
                              &nbsp;<small><%= TemplateTags.formatDate(post.date,'d/m/Y') %></small>
                        </h2>
                        <p><%= post.excerpt %></p>
                        <span><%= nb_comments %> comment<% nb_comments > 1 ? print('s') : '' %></span>
                  </li>
            <% }); %>
      </ul>
<% }else{ %>
      <p>No post found!</p>
<% } %>
Single.html

The Single.html template is used to render a post detail (and by default pages details too).

You access the post data in this template using the post JSON object. By default, this post object contains:

  • post.id: WordPress post ID.
  • post.post_type: WordPress post type.
  • post.date: post creation date (timestamp).
  • post.title: post title.
  • post.content: post content (use the wpak_posts_list_post_content or wpak_post_content_format hooks to customize it).
  • post.excerpt: post excerpt (use the wpak_post_excerpt, wpak_excerpt_length and wpak_excerpt_more hooks to customize it).
  • post.featured_img: post featured image. A JSON object containing post.featured_img.src, post.featured_img.height and post.featured_img.width.
  • post.author: post author (nickname by default).
  • post.nb_comments: number of comments for the post.

Those same fields can be used in the archive.html template when looping on the posts array.

They are fully customizable via hooks on the WordPress side of the WP-AppKit, allowing to control what post info you pass from WordPress to your app. For example, to add a post meta data (that you created on the WordPress side) to the post object used in the single.html and archive.html templates, simply add it on the WordPress side using the wpak_post_data hook, and it automatically appears in the post JSON object in your app templates. See the WP-AppKit WordPress hooks reference for detailed info about that.

Single.html example:

<h1><%= post.title %></h1>
<% if( post.nb_comments > 0 ){ %>
      <a href="<%= TemplateTags.getCommentsLink(post.id) %>">
            <% print(post.nb_comments) %>&nbsp;comment<% post.nb_comments > 1 ? print('s') : '' %>
      </a>
<% } %>
<div class="my-single-content">
      <% if( post.featured_img && post.featured_img.src && post.featured_img.src.length ){ %>
            <img src="<%= post.featured_img.src %>" />
      <% } %>
      <%= post.content %>
</div>

Here, if the post has comments, we display comments number as a link pointing to the app comments screen for this post. If the post has a featured image, we display it before post content.

Page.html

The page.html template is used to render WordPress page details. If not present, the single.html template is used instead.

You access the page data in the exact same way that you do with a post in the single.html template, using the post JSON object.

If the page is part of a page tree (ie. has a parent page or sibling pages), you can use the following template tags to retrieve information about its position in the tree:

getPageParent()getPageSiblings()getNextPage()getPreviousPage()getPageChildren()getPageDepth(), getPageBreadcrumb().

Comments.html

The comments.html template is used to render comments for a given post.

Comments can be found in the comments array, that contains comment JSON objects, ordered by descending date by default and taking comments responses imbrication into account through the comment.depth property:

  • comment.id: WordPress comment ID.
  • comment.date: comment date (timestamp).
  • comment.author: comment author (nickname).
  • comment.content: comment content.
  • comment.depth: depth starts at 1. If the comment is a response to a comment, depth equals 2. If it is a response to a response, depth equals 3…

You can customize those fields on the WordPress side using the wpak_comments_data hook. Order in which the comments appear can be changed using the wpak_comments_list_args hook.

In the comments.html template you can also use the post JSON object that corresponds to the post on which the comments have been posted. See the single.html template for details about its properties.

Example of comments.html template:

Comments on <a href="<%= TemplateTags.getPostLink(post.id) %>"><%= post.title %></a></li>
<% if(comments.length){ %>
      <ul class="media-list">
            <% _.each( comments, function( comment ){ %>
                  <li style="padding-left:<% print((comment.depth)*2) %>em">
                        <h4>
                              <%= comment.author %>&nbsp;
                              <small><%= TemplateTags.formatDate(comment.date,'d/m/Y') %></small>
                        </h4>
                        <p><%= comment.content %></p>
                  </li>
            <% }) %>
      </ul>
<% }else{ %>
      <p>No comment!</p>
<% } %>

Here, to render comment imbrication we use the comment.depth property to apply a left padding to comment list items.

Menu.html

The menu.html template renders the app menu items that are defined in the WordPress admin panel in the App Navigation box.

This menu is inserted in your HTML layout in the layout.html template using the <%= menu %> layout template tag.

Menu items can be found in the menu_items array. Each menu item is a JSON object containing :

  • menu_item.label: label of the component added to the app navigation in WordPress admin.
  • menu_item.link: internal app link to the screen targeted by the menu item.

Menu.html template example :

<ul class="my-nav-bar">
      <% if(menu_items.length){ %>
            <% _.each( menu_items, function( menu_item ){ %>
                  <li><a href="<%= menu_item.link %>"><%= menu_item.label %></a></li>
            <% }) %>
      <% } %>
</ul>
Custom templates

You can also define your own custom templates for singles, pages and lists.

This is useful if you want to have a specific template for a given category, page or post type.

You set up a custom template by :

  • creating the corresponding .html template file in your theme directory (for example “archive-my-category.html”). You are free to name your custom templates files whatever you want, there are no template naming rules according to taxonomies or post types in WP AppKit themes.
  • using the “template” filter to link your new template to the chosen screen.
“template” filter App.filter( 'template', function( template, current_screen) { ... return template; } )

Filters that allows to set a custom template for a given screen.

(Note that if you created a custom screen with the addCustomRoute() method, you don’t need to set your template with this “template” filter: the template is already set by addCustomRoute() )

For example, if you want to use a custom template of your own (let’s name it “archive-my-category.html”) for your category “my-category” (WordPress slug for your category), you will do something like this in functions.js :

App.filter( 'template', function( template, current_screen) {
      if( TemplateTags.isCategory('my-category', current_screen) ){
            template = 'archive-my-category'; //Don't need .html here.
      }
      return template;
} );

To use a custom single template (let’s say “single-my-post-type.html”) for a given WordPress post type “my-post-type” :

App.filter( 'template', function( template, current_screen) {
      //Check the screen's post type with "TemplateTags.isPostType()" : 
      //as we have to pass the current_screen as 3rd argument, we pass an empty post_id=0 as 2nd argument
      //( because we don't have to check a specific post ID here, just the post type 'my-post-type' ):
      if( TemplateTags.isPostType('my-post-type', 0, current_screen) ){
            template = 'single-my-post-type'; //Don't need .html here.
      }
      return template;
} );

Note : here we have to pass the “current_screen” argument to the isCategory() and isPostType() template tags (which you don’t have to do when using those template tags in templates). This is because when the ‘template’ filter takes action, the current_screen is not set in the global App context yet (internally we have to check if the given template is right before really switching the App engine to the new screen).

Arguments :
  • template : string : change this template value to one of your custom template to change the template used to render the current screen. No .html is needed at the end of the template name here (for example if your custom template is my-template.html, you would set template = "my-template" here.
  • current_screen : JSON object : the screen that is being rendered (see getCurrentScreen() for details about the JSON object )
Returns :

String : The modified template

“template-args” filter App.filter( 'template-args', function( template_args, view_type, view_template ) { ... return template_args; }

Filter that allows to customize variables that are passed to templates.

Each template (single.html, archive.html etc) has its own set of variables that are automatically defined and that you can use to display the different screen elements.
For example, in the archive.html template the following vars are available by default: “list_title”, “posts”, and “total”.
We also have the “TemplateTags” object that is available in all templates by default.

If you need to pass other variables or modules to your templates you can use the “template-args” filter.

Here is an example that shows how to pass some “my_stored_data” (that we stored to local storage using the PersistentStorage module for example) to the single.html template:

//In functions.js
define( [ 'core/theme-app', 'core/modules/persistent-storage', ... ], function( App, PersistentStorage, ... ) {
    
    App.filter( 'template-args', function( template_args, view_type, view_template ) { 

        //Make "my_stored_data" available in the "single.html" template:
        if( view_template == 'single' ) {
            template_args.my_stored_data = PersistentStorage.get( 'my_stored_data' );
            //('my_stored_data' is a JSON object for example)
        }

        return template_args;
    } );

} );

And in the “single.html” template you can now use “my_stored_data”:

<h1>My single title</h1>
<div class="my-custom-data">
    <p>Here's the first thing I stored to local storage: <%= my_stored_data.first_thing %></p>
    <div>
        And the second thing is a list:
        <ul>
            <% _.each( my_stored_data.second_thing, function( item ) { %>
                <li><%= item.name %>: <%= item.value %></li>
            <% } %>
        </ul>
    </div>
</div>
Arguments :
  • template_args: JSON Object: current template default variables. Add your own variables to this object.
  • view_type: String: type of template's view (one of 'archive', 'comments', 'custom-component', 'custom-page', 'head', 'layout', 'menu', 'page', 'single')
  • view_template: String: the template used to render the view (without the final '.html'): 'single', 'archive', etc, or any custom template of yours
Returns :

JSON Object: The modified 'template_args' with your custom vars and/or modules added.

“preloaded-templates” filter App.filter( 'preloaded-templates', function( preloaded_templates ) { ... return preloaded_templates; }

When the app navigates to a screen (eg. post list, post detail etc), it loads the corresponding template file (eg. archive.html, single.html etc) dynamically (RequireJS).

Loading a template is fast but it still takes some milliseconds, especially when previewing in browser, which can be disturbing when implementing transitions between screens for example.

By default, app core preloads single.html and archive.html templates at app launch so that they don’t have to be loaded on screen display.

You can use the “preloaded-templates” filter to add other native templates or templates of your own to preloaded templates.

Example to preload the “page.html” template in your theme:

//In functions.js
App.filter( 'preloaded-templates', function( preloaded_templates ) {
	preloaded_templates.push('page');
	return preloaded_templates; 
});

 

Arguments :
  • preloaded_templates: array: Array of preloaded templates : add templates you want to preload to this array before returning it.

JavaScript in Themes

In WP-AppKit apps, all JavaScript files inclusions are centralized by RequireJS. It allows to handle JavaScript module dependencies and files loading order in a robust way. To include JavaScript files in your theme you have to use the RequireJS syntax.

The default and best way to implement a JavaScript functionality (module) in a RequireJS driven application is to follow the Asynchronous Module Definition (AMD) pattern. But including a good old regular JavaScript file that doesn’t respect this pattern in your theme works also just fine. You don’t really need to know anything about RequireJS or AMD to add javascript to your theme. Just remember that you must not include your JavaScript files in the <head> (or at the bottom of the <body>) section. Instead, insert them as a dependency of the app in the theme’s functions.js file.

define(['jquery','core/theme-app','theme/js/my-javascript'],function($,App){
   //Your functions.js content here, where :
   // - $ = jQuery
   // - the theme-app core module is accessed through "App"
});

Doing that includes the [your-theme]/js/my-javascript.js file, by adding it as a dependency of the “functions” module defined in functions.js.

Note that:

  • You don’t need the “.js” at the end of “my-javascript” for the RequireJS dependency (but your javascript file must have the .js extension).
  • The path must start with “theme” which is replaced by your theme’s folder name internally.
  • Your JavaScript files can be organized freely under your theme’s folder, as long as you respect the theme/[my/path/to/my/js]/my-file format.

In the example above, our functions module is declared with 2 other dependencies: jquery and theme-app. Thereafter, jQuery is used with the $ variable and the theme-app module via the App variable.

There are 3 types of Javascript files that can be required in your theme:

  • your my-javascript file defines a module that follows the AMD pattern, you can access this module with a variable that you add after App in the function arguments.
  • your my-javascript file exports a global variable in the global context that you can access directly in the functions.js content.
  • your my-javascript implements some Javascript logic or library that is required for your theme but that does not require to be used through a variable in functions.js. That also works fine: in that case, you should require those Javascript files at the end of your dependencies declaration (with no corresponding argument after App), and your JavaScript will simply be included in the JavaScript context of the app.

For example, if you use the FitVids jQuery plugin (file theme/js/jquery.fitvids.js), you’ll include it like that:

define(
    ['jquery', 'core/theme-app', 'theme/js/jquery.fitvids'], 
    function($, App) {
        ...
    }
);

Note that theme/js/jquery.fitvids does not have a corresponding argument in function($, App), because this is a jQuery plugin that just needs to be included in the Javascript context and does not require to be accessed directly through a variable in functions.js.

Then for example if you need to include the core/modules/persistent-storage module (that has a corresponding PersistentStorage argument), you’ll have to add it before theme/js/jquery.fivids, because as said earlier, dependencies that don’t have a corresponding argument (here theme/js/jquery.fivids) must be declared at the end of the dependencies declaration:

define(
    ['jquery', 'core/theme-app', 'core/modules/persistent-storage', 'theme/js/jquery.fitvids'], 
    function($, App, PersistentStorage) {
    }
);

 

The Functions.js File

The functions.js file is the entry point of all the JavaScript used in a WP-AppKit app theme. It is required and must be located in wp-content/themes-wp-appkit/[your-app-theme]/js folder.

This is where you:

  • Follow and react to what happens in the app, binding to core events and using the ThemeApp module (typically available as the App object in functions.js).
  • Include your own JavaScript files, declaring them as app’s dependencies, as explained in the JavaScript in Themes section.
  • Hook into app core and set hookable app’s parameters.

Here is a minimalist example of functions.js file that refreshes the app’s content when user clicks the refresh button (#my-refresh-button) and updates a feedback area (#my-feedback) when refreshing ends:

define(['jquery','core/theme-app'],function($,App){

      $('#my-refresh-button').click(function(e){
            e.preventDefault();
            App.refresh(function(){
                  $('#my-feedback').html('Content updated successfully :)').show();
            });
      });

});

The best practice with functions.js is the same as with the WordPress themes’ functions.php : if possible don’t declare all your app Javascript in functions.js, prefer Javascript sub-modules that you add to your theme via the functions.js dependencies :

For example, develop your functionality in [your_theme]/js/my-module.js and add this module to your theme by requiring it in functions.js like so :

define( [ 'jquery','core/theme-app', 'theme/js/my-module' ], function ( $, App, MyModule ) {
      MyModule.myFunction();
});

Javascript Hooks

You’re probably familiar with WordPress (PHP) Hooks that allow to hook into the core of WordPress from plugins or themes.

WP-AppKit theme API uses hooks too to allow interaction with app core from themes.

The principle behind WP-AppKit app’s hooks is very similar to WordPress hooks except that they’re not implemented in PHP but in Javascript.

Most of the treatments and customization you will do in WP-AppKit themes (in functions.js for example) use those Javascript hooks.
Hooks can be filters or actions : you can use them from themes through App.filter() and App.action().

Internally, those methods use the WP-AppKit Javascript Hooks module implementation that you can find in app/core/lib/hooks.js.

filter App.filter( filter_name, filter_callback, priority )

Allows to hook into a core variable or setting to modify default app’s behavior.

Here is an example using the “template” filter to define your own custom template for a given category:

//In functions.js for example:
define( [ 'core/theme-app', 'core/theme-theme-tpl-tags' ], function( App, TemplateTags ) {

    App.filter( 'template', function( default_template, current_screen ) {

        if( TemplateTags.isCategory( 'my-category', current_screen ) ) {
            //Use the '[your-theme]/archive-my-category.html' template:
            default_template = 'archive-my-category'; //Don't need .html here.
        }

        return default_template;
    } );

} );

In this example, the core variable that the “template” filters allows to modify is “default_template”.
We change it to “archive-my-category” template and return it, then the core takes this new template value into account to render the current screen.

Filters examples: launch-routedefault-route, templatetemplate-args.

Arguments :
  • filter_name: string: Name of the filter (for example 'template-args') to hook into.
  • filter_callback: function: Callback function that receives the data to modify as first argument, followed by other arguments depending on which filter is called. The callback must return the modified version of the first argument.
  • priority: int: (Optional, default 10): Sets the order in which the functions associated with the filter are executed. Lower numbers correspond with earlier execution. (Same principle as WordPress hooks priorities)
action App.action( action_name, action_callback, priority )

Allows to hook into the core at key moments of the app processing to do your own actions.

The main purpose of actions is to allow hooking into core treatments in a synchronous way, meaning that you can be sure that the core is waiting for your action to be finished to pursue its course of action. This is different from events that are asynchronous.

WP-AppKit action hooks provide a jQuery deferred object as last argument of each callback functions called, so that synchronous actions can be handled.

Usage example using the ‘pre-start-router’ action to do some treatments before the app router is started:

App.action( 'pre-start-router', function( launch_route, app_stats, $deferred ) {
    //Do something before router is started, and resolve $deferred when finished:
    MyAsynchronousProcess( { success: function() {
        //Resolve $deferred so that core process can go on:
        $deferred.resolve();
    } } );
} );

Actions examples : ‘pre-start-router’,’screen-transition’, ‘components-fetched’

Arguments :
  • action_name: string: Name of the action (for example 'screen-transition') to hook into.
  • action_callback: function: Callback function that receives arguments depending on which action is called. The callback is passed a jQuery deferred object that can be used for actions that are handled synchronously by the core: in this case $deferred.resolve() must be called when the hooked function finishes its process.
  • priority: int: (Optional, default 10): Sets the order in which the functions associated with the action are executed. Lower numbers correspond with earlier execution. (Same principle as WordPress hooks priorities)

Template Tags

Used in themes templates, Template Tags allow to retrieve info about the current screen and to make conditional treatments such as isSingle(), isCategory()… From templates, you access them using the TemplateTags object (eg. TemplateTags.isSingle()).

They can also be used in functions.js.

getCurrentScreen TemplateTags.getCurrentScreen()

Retrieves infos about the current displayed screen.

Returns JSON object containing:

  • screen_type: list, single, comments, page.
  • fragment: unique screen URL ID (what’s after # in URL).
  • component_id: component slug ID, if displaying a component screen (list, page).
  • item_id: current post ID (the same as the WordPress post.ID ), if displaying single content (post,page).
  • label: label of the screen : for lists it is the component label (as set in WordPress Back Office), for post/page it is the post/page title.
  • data: contains more specific data depending on which screen type is displayed.

data property examples:

for post list screens, data contains:

  • query: query vars used to retrieve current screen content (taxonomy, terms…).
  • total: if list, the total number of posts in the list.
  • ids : if list, IDs of posts displayed in the list.

for single post screens, data contains:

  • post: JSON Object containing post data

getCurrentScreen() example:

var current_screen = TemplateTags.getCurrentScreen();
if( current_screen.screen_type == 'single' ){
    //do something only if displaying a post detail.
}

Retrieving current screen information is a very common need so this function has an alias in the ThemeApp module: App.getCurrentScreen(). This way you can retrieve screen information from any context or JS module in your theme where ThemeApp is available, without having to add the TemplateTags module as a dependency.

getCurrentScreenObject TemplateTags.getCurrentScreenObject() or App.getCurrentScreenObject()

Retrieves useful data corresponding to the object that is currently displayed.

If you’re familiar with WordPress development, this getCurrentScreenObject() is some kind of equivalent of WordPress’s get_queried_object().

For example, if you’re displaying a post screen (single), TemplateTags.getCurrentScreenObject() will return the displayed post data as a JSON Object.

Retrieving current screen object is a very common need so the function also has an alias in the ThemeApp Module : App.getCurrentScreenObject(). This way it can be called in functions.js or any theme JS module of your own without having to require TemplateTags as a dependency.

Returns :

JSON Object depending on current screen:

  • for lists: object containing: title (list title), posts (list of posts), ids (=post ids), total, component_id, query
  • for single: post object: id, post_type, date, title, content, excerpt, thumbnail, author, nb_comments, slug, permalink
  • for comments: object containing: post (post we retrieve the comments for) and comments (list of comments for this post)
  • for pages: page object: id, post_type, date, title, content, excerpt, thumbnail, author, nb_comments, slug, permalink, tree_data, component (page's component object)
  • for custom pages: object containing: id, route, title (if custom page data contains a 'title' property), data (custom page data), template.
  • for custom components: object containing: component_id, title, route, data, template
  • for all: field 'screen_type': can be: 'list', 'single', 'comments', 'page', 'custom-page', 'custom-component'
getPreviousScreen TemplateTags.getPreviousScreen()

Retrieves infos about the previously displayed screen, according to app’s history.

Returns a JSON object with the exact same structure as TemplateTags.getCurrentScreen().

For example, in the single.html template, if you want to retrieve the title of the list you come from :

<% var previous_list = TemplateTags.getPreviousScreen() %>
<div class="my-breadcrumb">
      <%= previous_list.label %> &gt; <%= post.title %>
</div>
getPreviousPage TemplateTags.getPreviousPage( screen )

Get previous sibling page of the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

JSON object : previous page object, null if none

getNextPage TemplateTags.getNextPage( screen )

Get next sibling page of the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

JSON object : next page object, null if none

getPageChildren TemplateTags.getPageChildren( screen )

Get children pages of the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

Array of JSON page objects : children pages

getPageSiblings TemplateTags.getPageSiblings( screen )

Get siblings pages of the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

Array of JSON page objects : siblings pages

getPageParent TemplateTags.getPageParent( screen )

Get parent page of the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

JSON object : parent page object, null if none.

getPageDepth App.getPageDepth( screen )

Get depth of the page in the page tree of the corresponding “Page component”.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

int : depth of the page. (0 if mother page, 1 if first level children page, etc...)

getPageBreadcrumb App.getPageBreadcrumb( screen )

Get the path to the given page.

Can be used only for pages that come from a “WordPress Page” component where “Include sub pages” is checked.

See https://github.com/uncatcrea/wpak-theme-bootstrap/blob/master/page.html for an example.

Arguments :
  • screen : JSON object (Optional) : use only if you want data from a different screen than the current one.
Returns :

Array of JSON pages objects : array of all mother pages that lead to the given page.

isSingle TemplateTags.isSingle( post_id, screen )
Arguments :
  • post_id : int : Optional : WordPress post ID : pass an ID to check if you are displaying the sreen corresponding to the given post.
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to check a different screen than the current one
Returns :

Boolean : true if the current screen corresponds to the post with ID=post_id.

If no post_id is passed, it will return true if you are displaying a single.

Note : this will return false for a page : use TemplateTags.isPage( page_id ).

isPage TemplateTags.isPage( page_id, screen )
Arguments :
  • page_id : int : Optional : Wordpress page ID : pass an ID to check if you are displaying the sreen corresponding to the given page.
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to check a different screen than the current one
Returns :

Boolean : true if the current screen corresponds to the page with ID=page_id.

If no page_id is passed, it will return true if you are displaying a page screen.

Note : this will return false for a "single" screen : use TemplateTags.isSingle( post_id ).

isPostType TemplateTags.isPostType( post_type, post_id, screen )

Checks if the current screen is a single for a specific post type.

This can be used to check if you are displaying a certain type of your WordPress Custom Post Types.

Arguments :
  • post_type : string : the post type you want to check.
  • post_id : int : Optional : Wordpress post ID :  if you also want to check if this is a specific post.
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to know the post type of a different screen than the current one
Returns :

Boolean : true if the current screen corresponds to the given post_type and optionally post_id.

isTaxonomy TemplateTags.isTaxonomy( taxonomy, terms, screen )

Checks if a screen is a list of posts filtered by a given WordPress taxonomy. This can occur when you create an App having a “Post list” component filtered by a custom taxonomy in the WordPress Back Office.

For example, to check if you are displaying of list of posts filtered on any term of the WordPress taxonomy “my-taxonomy” : use TemplateTags.isTaxonomy( ‘my-taxonomy’ ), in the archive.html template or in functions.js.

To check if you are displaying the list of posts that have the “my-taxonomy” terms “my-term” and “my-other-term”, use : TemplateTags.isTaxonomy( ‘my-taxonomy’, [‘my-term’, ‘my-other-term’] ).

Arguments :
  • taxonomy : string : WordPress taxonomy slug to check
  • terms : string | array : Optional : Taxonomy terms slug(s) to check
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to check a different screen than the current one
Returns :

Boolean : true if the screen corresponds to the given taxonomy list (and specific terms if you passed some).

isCategory TemplateTags.isCategory( categories, screen )

Checks if a screen is a list of posts filtered by a given WordPress category. This can occur when you create an App having a “Post list” component filtered by a category in the WordPress Back Office.

For example, to check if you are displaying a list of posts filtered on any term of any WordPress category : use TemplateTags.isCategory(), in the archive.html template or in functions.js.

To check if you are displaying the list of posts that have the category terms “my-category” and “my-other-category”, use : TemplateTags.isCategory([‘my-category’, ‘my-other-category’]).

Note : TemplateTags.isCategory( [‘my-category’, ‘my-other-category’] ) is equivalent to TemplateTags.isTaxonomy( ‘category’, [‘my-category’, ‘my-other-category’] )

Arguments :
  • categories : string | array : Optional : Category terms slug(s) to check
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to check a different screen than the current one
Returns :

Boolean : true if the screen correponds to the given category(s)

isTag TemplateTags.isTag( tags, screen )

This is the same as TemplateTags.isCategory() but for WordPress Tags (“post_tag” taxonomy).

Note : TemplateTags.isTag( [‘my-tag’, ‘my-other-tag’] ) is equivalent to TemplateTags.isTaxonomy( ‘post_tag’, [‘my-tag’, ‘my-other-tag’] )

Arguments :
  • tags : string | array : Optional : Tag(s) (Wordpress "post_tag" taxonomy) slug(s) to check
  • screen : object (see TemplateTags.getCurrentScreen() ) : Optional : use only if you want to check a different screen than the current one
Returns :

Boolean : true if the screen correponds to the given tag(s)

isScreen TemplateTags.isScreen( screen_fragment, screen )

Checks if the current screen corresponds to the given screen fragment.

For example, to display a custom block only for the single corresponding to the post with WordPress ID=123 : in the single.html template :

<% if( TemplateTags.isScreen( 'single/posts/123' ) ) { %>
      <div>
            I will show up only for the post with ID=123
      </div>
<% } %>
Arguments :
  • screen_fragment : string : The url fragment to check (without the # chararcter)
  • screen : object : Optional : use only if you want to check a different screen than current one
isDefaultScreen TemplateTags.isDefaultScreen( screen_to_check )

Checks if the given or current screen is the default screen or not.

Arguments :

screen_to_check: optional: screen object: screen we want to test. If not given, the current screen will be used (see TemplateTags.getCurrentScreen() for screen object format details).

Returns :

Bool: True if the screen is the default one.

getAppStats TemplateTags.getAppStats(stat)

Retrieves stats infos about the app : app open count, last open date, app version.

Example, in any template :

<% var stats = TemplateTags.getAppStats() %>
<span>Current version is <%= stats.version %> and the last time you opened this app was on <%= stats.last_open_date %>.</span>
Arguments :
  • stat : can be empty to retrieve all stats in a JSON object, or use one of the following string to retrieve a specific stat : "count_open", "last_open_date", "version", "version_diff". 

For example, TemplateTags.getAppStats('version') will retrieve only the app version, as a string.

Returns :
  • count_open : int : number of times the app was open by the user
  • last_open_date : string (yyyy-mm-dd hh:mm:ss) : date of the last time the app was open by the user
  • version : string : current app version, as set in Wordpress Back Office in "Phonegap config.xml data" version field.
  • version_diff : JSON object containing "current_version", "last_version" (different of current_version if you just updated the app) and "diff" : equals 0 if current_version = last version, +1 if current_version > last version, -1 if current_version < last version.
getThemePath TemplateTags.getThemePath()

Retrieves the path to the current theme.

For example, to link a CSS file in the head.html template :

<link rel="stylesheet" href="<%= TemplateTags.getThemePath() %>/css/my_styles.css">
Returns :

String : Path to the current theme

getMenuItems TemplateTags.getMenuItems()

Retrieves menu items, in the same format as in the menu.html template.

Returns :

Array of JSON objects : Menu items array

getComponent TemplateTags.getComponent( component_slug )

Retrieves the given component data.

The way to go to retrieve component data for components that are not added to the app navigation.

See the components section for more details about this.

Arguments :
  • component_slug : string : component slug as defined when creating the component in the WordPress Back Office
Returns :

JSON Object containing component data :

  • data : JSON Object : contains all the data (content) coming from the WordPress side : this is where you want to look to retrieve your component data. In most cases you don't have to use the following other properties.
  • global : string : the internal global array ('posts', 'page', etc) where the possible components items are stored.
  • id : string : slug of the component as defined when creating the component on WP side
  • label : string : component label as defined when creating the component on WP side
  • type : string : internal type of the component 
  • view_data : the data prepared to be passed to the screen view, if the component is linked to a core view.
componentExists TemplateTags.componentExists( component_slug )

Check if the given component is included in the app.

Arguments :
  • component_slug: string: Slug of the component to retrieve, as set when creating the component in App edition on WordPress side.
Returns :

boolean: true if the component is found in the app, false otherwise.

isComponentInMenu TemplateTags.isComponentInMenu( component_slug )

Checks if the given component is present in app’s navigation.

Arguments :
  • component_slug: string: Slug of the component to retrieve, as set when creating the component in App edition on WordPress side.
Returns :

boolean: true if the component is found in app's navigation items, false otherwise.

Refreshing Content

refresh App.refresh ( cb_ok, cb_error )

Launches app refresh: gets updated content (components, posts, menu items) from the server and updates app’s local storage accordingly.

You’ll probably want to do some treatment in your theme when refresh starts and ends (like display/hide a loading spinner for example).
There are 2 ways to achieve that: using refresh callbacks (cb_ok, cb_error) or refresh events (refresh:start, refresh:end).
You can choose one of those ways depending on your implementation but you should not use them both at the same time (we would recommend using the events version for more flexibility).

For example, the 2 snippets below would be equivalent (in functions.js):

With callbacks:

$("#app-layout").on("touchend","#my-refresh-button", function(){
      //Call refresh with callbacks
      App.refresh( 
            function() { //Success callback (cb_ok)
                  //Hide loading spinner
                  //Display success message
            }, 
            function( error ) { //Error callback (cb_error)
                  //Hide loading spinner
                  //Display error message based on error.message
            }
      );
});

With events:

App.on( 'refresh:start', function() {
      //Display loading spinner
} );

App.on( 'refresh:end', function( result ) {
      //Hide loading spinner
      if ( result.ok ) {
            //Display success message
      } else {
            //Display error message based on result.message
      }
} );

$("#app-layout").on("touchend","#my-refresh-button", function(){
      //Call refresh without callbacks:
      App.refresh();
});
Arguments :
  • cb_ok : (Optional, not needed if using refresh:start and refresh:end events) : callback function : called when refresh process ends, if refresh went ok. 
  • cb_error : (Optional, not needed if using refresh:start and refresh:end events) : callback function : called if an error occured during refresh. Receives an error object as argument, containing error.message and error.data.
isRefreshing App.isRefreshing()

To know if there is an ongoing refresh process.

Returns :

True if the app is currently refreshing.

refresh-at-app-launch App.setParam('refresh-at-app-launch', false);

App param. Boolean (default true). Use in functions.js to choose if the app refreshes at app launch.

For example, if you display a custom page when your app version changes, you don’t want your app content to refresh immediately at app launch :

App.filter( 'launch-route', function( launch_route, stats ) {
		
    if( stats.version_diff.diff > 0 ){ //The app has been updated!
        //Display a custom page for the occasion :
        launch_route = TemplateTags.getPageLink(your_update_page_id,'new-version-page-component');
        //And avoid refreshing the app in this specific case :
        App.setParam('refresh-at-app-launch',false);
    }
		
    //Return the modified launch route :
    return launch_route;
} );
go-to-default-route-after-refresh App.setParam('go-to-default-route-after-refresh',false);

App param. Boolean (default true). Use in functions.js to choose if the app navigates automatically to the default route after a content refresh.

refresh:start App.on ( 'refresh:start', function() { ... } )

Event that is triggered when the app start refreshing its content : typically this happens at app launch and when the user clicks the “refresh” button of your app theme.

Example : add a class to your refresh button (to make it spin via CSS for example) :

App.on( 'refresh:start', function() {
      $( '#my-refresh-button' ).addClass( 'refreshing' );
} );
refresh:end App.on( 'refresh:end', function( result ) { ... } )

Event triggered when the app’s content refresh process is finished.

Example that removes a CSS class on the refresh button and display a success message when content refresh ends :

App.on( 'refresh:end', function( result ) {
      $( '#my-refresh-button' ).removeClass( 'refreshing' );
      if ( result.ok ) {
            $( '#my-feedback' ).html( 'Content updated successfully :)' ).show();
      }
} );
Arguments :
  • result : JSON Object : contains :
    • ok : boolean : true if no error occurred.
    • message : string : Error message if an error occurred during refresh (for example no network connection), empty if no error.
    • data : JSON Object : Error object if an error occurred, empty if no error.

Retrieve content

WP-AppKit app content is composed of posts and pages (and possibly other custom item structure of your own if you used custom components).

Those posts and pages are retrieved from the JSON webservice answer and stored locally (Local Storage) so that they’re fully available offline.

Internally, posts and pages are stored in a JSON Object named “globals”, property of the core App Object. By default this “globals” object contains 2 collections : globals.posts (contains all post types except pages) and globals.pages (contains only pages).

You don’t really have to care about this when you build your theme templates as posts and pages are served to templates in a transparent way. But maybe at some point you’ll need to retrieve posts on JS side (eg functions.js). This can be done using App.getItems() and App.getItem().

getItems App.getItems( items_ids, global_key, result_type )

Retrieves a list of items (posts or pages for example) from local storage.

Example of a function based on App.getItems() that can be used in a theme (functions.js) to retrieve the “nb_posts” last posts in local storage:

function getLastPosts( nb_posts ) {
        
        //Get all posts in local storage (Backbone collection)
        var all_post_models = App.getItems();

        //Sort collection by date
        all_post_models.comparator = 'date';
        all_post_models.sort();

        //Get the last 3 and reverse order to order by date desc
        var last_post_models = all_post_models.last( nb_posts ).reverse();

        //Retrieve JSON post objects out of Backbone models
        var last_posts = _.map( 
                last_post_models, 
                function( model ){ return model.toJSON(); }
         );

        return last_posts;
        
}
Arguments :
  • items_ids {array} WordPress IDs of the items (posts, pages) to retrieve
  • global_key {string} (Optional) global to retrieve the items from: 'posts' (default) or 'pages'.
  • result_type {string} 'slice' to retrieve a Backbone Collection (default), 'array' to retrieve an array of JSONified items.
Returns :

{Backbone Collection | Array} Items list corresponding to given IDs

getItem App.getItem( item_id, global_key )

Retrieves an item (post, page for example) from local storage.

Arguments :
  • item_id {int} Post ID of the post to retrieve
  • global_key {string} (Optional) global to retrieve the item from: 'posts' (default) or 'pages'.
Returns :

{JSON Object | null} item (post or page) object if found, null if no post found with the given item_id.

getComponents App.getComponents()

Retrieves all app components.

Useful to check if a specific component type is present in the app.

To retrieve only one component, use TemplateTags.getComponent( component_slug ).

Returns :

array: Array of all app components (each component as a JSON objects)

Routing

Each screen in a WP AppKit app corresponds to a specific url fragment identifier (url fragments are what’s after “#” in urls). When you navigate to a given fragment (let’s say #component-last-posts), the app checks if the fragment matches one of its internal routing rules, and if so, routes you to the corresponding screen (here, #component-last-posts will lead to the list of your last posts).

If the fragment is empty (as it is the case at app launch) or wrong (doesn’t match any internal route), the app follows its “default-route“, which is by default the fist element of your app navigation, that you defined in WordPress back office. The default route is also the one we come back to after a content refresh.

From WP AppKit themes you can hook into the app routing system to display a specific screen of your choice at app launch, after a refresh, and even more specifically when the app is launched for the first time or when the app has a version upgrade.

launch-route App.filter( 'launch-route', function( launch_route, stats ) { ... } );

Used in functions.js, this filter allows to go to a specific screen of your choosing at app launch.

Note : by default, apps automatically refresh their content at app launch. And, after a refresh, the app is redirected to the “default-route“.
So if you set a “launch-route” and feel like it is not working properly it is certainly due to the fact that when your app is launched :

  • first, your “launch-route” is triggered
  • then the app triggers a content refresh
  • when the refresh is finished the “default-route” is triggered! So you end up on the “default-route” screen instead of the “launch-route” screen…

So to be able to use a customized “launch-route” properly, you may want to :

For example, launch a specific page the first time the user opens the app, and another page when the user updates his/her app :

App.filter( 'launch-route', function( launch_route, stats ) {
		
    if( stats.count_open == 1 ){ //First app launch
        //Display a custom page :
        launch_route = TemplateTags.getPageLink(your_welcome_page_id,'your-welcome-page-component-slug');
    }
		
    if( stats.version_diff.diff > 0 ){ //The app has been updated!
        //Display a custom page for the occasion :
        launch_route = TemplateTags.getPageLink(your_update_page_id,'new-version-page-component');
    }
		
    //Return the modified launch route :
    return launch_route;
} );
Arguments :

The filter callback receives 2 arguments :

  • launch_route : string : the fragment the app is going to navigate to at app launch. Change this fragment and return it to modify the launch route.
  • stats : JSON object : contains the app open count, last open date and app version info (see getAppStats() )
Returns :

The modified launch_route

default-route App.filter( 'default-route', function( default_route, stats, is_app_launch ) { ... } );

Used in functions.js, this filter allows to modify the app “default-route”.

By default, the default route is the fist element of your app navigation, that you defined in WordPress back office.

The app navigates to the default route :

  • at app launch (by defaults, “launch-route” = “default-route”),
  • after app content refresh,
  • if one tries to navigate to a wrong url fragment.
App.filter( 'default-route', function( default_route, stats, is_app_launch ) {
		
    if( !is_app_launch ){ //App launch, as opposed to app refresh
        //Display a custom page :
        default_route= TemplateTags.getPageLink(your_custom_page_id,'your-custom-page-component-slug');
    }
		
    //Return the modified default route :
    return default_route;
} );
Arguments :

The filter callback receives 3 args :

  • default_route : string : the default route fragment that you can modify to change the app default route.
  • stats : JSON object : contains the app open count, last open date and app version info (see getAppStats() )
  • is_app_launch : boolean : true if the app is launching. Sometimes you'll want to change the default route only at app launch, or, on the contrary, anytime but not at app launch.
Returns :

The modified default_route.

pre-start-router App.action( 'pre-start-router', function( launch_route, stats, $deferred ) { ... } );

App action hook. Use in functions.js to do something before the app starts its routing logic.

Here is an example that uses ‘pre-start-router’ to check user authentication at app launch, before the routing engine starts:

//First, don't refresh content at app launch as we check user permissions before showing any content:
App.setParam( 'refresh-at-app-launch', false );

/**
* Check user authentication before launching app router, so that no content is displayed
* before authentication check
*/
App.action( 'pre-start-router', function ( launch_route, app_stats, $deferred ) {

	Auth.checkUserAuthenticationFromRemote(
		function () {
			//User is still logged in ok, with right membership level.
			$deferred.resolve();
		},
		function () {
			//User not logged in anymore, certainly because its membership level expired. 
			//Log out has already been triggered internally.
			$deferred.resolve();
		}
	);

} );

Note that ‘pre-start-router’ is a JS action hook. JS actions hooks are synchronous, so you have to call $deferred.resolve() when your treatment is finished to tell the core it can go on with app launch process.

Arguments :

The callback receives 2 arguments that you can use to decide what to do in the action hook:

  • launch_route : string : the fragment the app is going to navigate to at app launch.
  • stats : JSON object : contains the app open count, last open date and app version info (see getAppStats() )
  • $deferred: jQuery deferred object : must be resolved when the treatment is finished to tell the core it can resume its process and launch routing.
redirect App.filter( 'redirect', function( redirect, queried_screen, current_screen ) { ... } );

When nativating to a screen, allows to redirect to another screen instead.

Example that redirects the user to the login page when he/she tries to access a post and does not have the right capability :

App.filter( 'redirect', function( redirect, queried_screen ) {
      if ( queried_screen.screen_type == 'single' 
           && !Auth.currentUserCan( 'premium_capability' ) 
      ) {
            App.navigate( 'login-page' );
            redirect = true;
      }
      return redirect;
} );

 

Arguments :
  • redirect: boolean (default false): set to true if you want to redirect (after calling App.navigate('your-redirect-route') ).
  • queried_screen: screen object: the screen we are about to navigate to.
  • current_screen: screen object: the screen we are currently on (before starting navigation to an other screen).
Returns :

Return true to redirect (after calling App.navigate('your-redirect-route') )

info:app-ready App.on( 'info:app-ready', function( event ){ ... } );

App core event : triggers when the app is ready : app content is loaded and routing has started.

Example (in functions.js) to display a custom page when the user opens the app for the 10th time :

App.on( 'info:app-ready', function( event ) {
      if( event.core_data.stats.count_open == 10 ){ 
            App.showCustomPage( 'my-template-for-10th-opening', { my_custom_data_for_this_page } );
      }
} );
Arguments :
  • event : core event JSON object : event.core_data.stats contains app Stats data (App opening count, Last opening date, App version etc...) : see TemplateTags.getAppStats()
info:app-first-launch App.on( 'info:app-first-launch', function( event ) { ... } )

App core event : triggers when the app is launched for the first time.

Example (in functions.js) to display a custom page when the user opens the app for the fist time :

App.on( 'info:app-first-launch', function( event ) {
      App.showCustomPage( 'my-template-for-first-opening', { my_custom_data_for_this_page } );
} );
Arguments :
  • event : core event JSON object : event.data.stats contains app Stats data (App opening count, Last opening date, App version etc...) : see TemplateTags.getAppStats()
info:app-version-changed App.on( 'info:app-version-changed', function( event ){ ... } );

App core event : triggers when the app changed its version.

Example (in functions.js) to display a custom page when the user just updated the app :

App.on( 'info:app-version-changed', function( event ) {
      var stats = event.data.stats;
      if( stats.version_diff.diff > 0 ){ //The app has been updated!
            App.showCustomPage( 'my-template-for-version-change', { 
                  new_version: stats.version, 
                  old_version: stats.version_diff.last_version,
                  other_custom_data_for_this_page : 'other-custom-data'
            } );
      }
} );
Arguments :
  • event : core event JSON object : event.data.stats contains app Stats data (App opening count, Last opening date, App version etc...) : see TemplateTags.getAppStats()
addCustomRoute App.addCustomRoute( fragment, template, data )

Allows to create a custom route that will display a custom screen using the given custom template.

This is the way to go to create custom app screens that don’t correspond directly to WordPress pages or posts.

Example :

//In app's theme (functions.js)

/** 
  The following allows to create a custom screen on app side only 
  (meaning it does not correspond to an existing WordPress page or post).
  In this example, the page is accessed at the "url" #my-page-route and 
  uses the template 'my-page-template' to render. Last arguments allows to pass 
  custom data to the template.
*/
App.addCustomRoute( 'my-page-route', 'my-page-template', { some_data : 'for the template' } ); 

/**
  And if you want to pass dynamic data to the template, you can use the 
  'template_args' filter :
*/
App.filter( 'template-args', function( template_args, view_type, view_template ) { 
	if( view_template == 'my-page-template' ) {
		template_args.my_custom_arg = { my: custom_dynamic_value };
	}
	return template_args;
} );
Arguments :
  • fragment : string : url fragment for your custom screen
  • template : string : file name of the (custom) template you want to use (without the final ".html")
  • data : JSON object (Optional) : data passed to the template
showCustomPage App.showCustomPage( template, template_data )

Display a custom page that is not a WordPress page but a page created dynamically on app side.

When you call this function from your functions.js, it displays a page rendered with the template and the data you provided.

ShowCustomPage() is made for “one shot” app screens that you want to trigger dynamically on a specific occasion. To define a more permanent custom page associated to a given custom route, use App.addCustomRoute().

For example, to display a custom page when clicking a link :

In your template :

<a id="my-custom-page" href="#">My custom page</a>

In functions.js :

$( '#my-custom-page' ).click( function( e ) {
      e.preventDefault();
      App.showCustomPage( 'my-custom-page-template', {
            my_title: 'The custom page title', 
            my_content: 'My page content'
      } );
} );

In your custom template : my-custom-page-template.html :

<div id="my-custom-page">
      <h1><%= data.my_title %></h1>
      <div class="my-content">
            <%= data.my_content %>
      </div>
</div>
Arguments :
  • template : string : the template to be used to render the custom page : use any existing or custom template of your own.
  • template_data : JSON object : the data that will be passed to the template : all JSON data that you provide here is then accessible in your template under the "data" global var.

Navigation

Navigation in WP-AppKit apps is based on url fragment identifiers (url fragments are what’s after “#” in urls).

In single page apps, those fragment identifiers are also referred to as “routes” (See “Routing” for more detailed info about this).

To simplify things, reading this doc you can consider that “fragment identifier” = “route” = “link” = “(internal app) url”.

Here are the default fragment formats corresponding to the default WP-AppKit screen types:

  • List (component “Post list”) : #component-[slug-component]
  • Single (item of a “Post list”) : #single/posts/[post-ID]
  • Page (component “Page”) : #page/[slug-component]/[page-ID]
  • Comments : #comments/[post-ID]
  • Custom pages (created with App.addCustomRoute() ): #your-custom-fragment (in this case you may notice that internally the app core redirects in fact the browser to #custom-page, but you don’t have to worry about this, just use #your-custom-fragment to navigate to your custom page).

From templates it is better not to write those fragments manually but to retrieve them using the following template tags :  TemplateTags.getPostLink(), TemplateTags.getCommentsLink(), TemplateTags.getPreviousScreenLink(), TemplateTags.getPageLink().

For example :

//In a template : HTML link to a single post:
<a href="<%= TemplateTags.getPostLink(123) %>" >The post title</a>

//This would render: 
<a href="#single/posts/123">The post title</a>
//In functions.js:
App.navigate( TemplateTags.getPostLink( post_id ) );
App.navigate( "#single/posts/[post-ID]" );

Note : for now there’s no template tag that allows to retrieve a link for a list component screen : if you need to create a link to a component screen, you can do it manually with href=”#component-[slug-your-component]”.

navigate App.navigate( fragment )

Navigate (dynamically in Javascript) to the screen corresponding to the given url fragment.

Example :

//In functions.js :
App.navigate( TemplateTags.getPostLink( post_id ) );
Arguments :
  • fragment : string : url fragment (#my-fragment) you want to navigate to.
navigateToDefaultRoute App.navigateToDefaultRoute()

Allows to navigate to default route manually (from functions.js for example).

screen:showed App.on( 'screen:showed', function( current_screen, current_view ) { ... } );

Event that is triggered after a screen has finished rendering, meaning the screen’s DOM is all set (rendered from your theme’s templates).

This event is where you will :

  • make some internal theme’s processing when reaching a specific screen (like store some UI or User state to Local Storage)
  • possibly bind Javascript events on dynamic parts of the DOM that were just rendered, but a jQuery( “#app-layout” ).on( “your_event”, “.your_class”, function( e ) { … } ) pattern will be better in most cases (see notes below).

Note: 2 cases where screen:showed should not be used in most cases:

  • Dynamics parts of the screen are HTML defined in all templates except for layout.html : as explained in the Layout Areas section, the layout.html template defines the static part of the app’s DOM. So, to bind JS events on DOM elements defined in layout.html, you don’t need to wait for screen:showed and you should do it directly in function.js with a standard jQuery( ‘.your_class’ ).your_event( function( e ) { … } ).
  • To bind JS events on dynamic parts (coming from templates like archive.html, single.html etc), the best way is to use the jQuery.on() method on a static parent element (and not jQuery.live() that is deprecated !). The most convenient static parent DOM element that you can use to bind your events is div#app-layout because you can be sure it will always be there, not modified by the app core. This gives us patterns like :
//In functions.js :
jQuery( "#app-layout" ).on( "your_event", ".your_dynamic_element_class", function( e ) { 
      //Your treatment when your_event is triggered on .your_dynamic_element_class element
} ).

If you really need to bind events to DOM on screen:showed, they should be unbound in screen:leave.

Example :

screen:showed event example that allows to go back to the previous scroll position when coming back to a post list from a post detail (single) :

App.on( 'screen:showed', function( current_screen ) {
      if ( current_screen.screen_type == 'list' ) {
            //Retrieve previously stored scroll position (see screen:leave event)
            //(use current_screen.fragment as an id for the current screen) :
            var pos = Storage.get( 'scroll-pos', current_screen.fragment );
            if ( pos ) {
                  $( 'body' ).scrollTop( pos );
            } else {
                  scrollTop();
            }
      } else {
            scrollTop();
      }
} );
Arguments :
  • current_screen : JSON Object : contains data about the screen that has just been displayed. See TemplateTags.getCurrentScreen() for more details. 
  • current_view : WP-AppKit extended version of the Backbone View Object, contains info about the data used to render the current screen (template name, static screen or not, etc). Not needed in most cases, useful for debug.
screen:leave App.on( 'screen:leave', function( current_screen, queried_screen, current_view ) { ... })

Event that is triggered before leaving a screen.

This event is where you will :

  • make some internal theme’s processing before leaving a specific screen (like store some UI or User state to Local Storage)
  • possibly unbind Javascript events on dynamic parts of the DOM before app core deletes it (see the screen:showed event for more info about that)

Example that stores the current scroll position when leaving a “post list” screen so that we can come back to this position later using screen:showed :

App.on( 'screen:leave', function( current_screen, queried_screen ) {
      if ( current_screen.screen_type == 'list' ) {
            //Memorize scroll position before leaving the screen :
            //(use current_screen.fragment as an id for the current screen) :
            Storage.set( 'scroll-pos', current_screen.fragment, $( 'body' ).scrollTop() );
      }
} );
Arguments :
  • current_screen : JSON Object : contains data about the screen you're about to leave. See TemplateTags.getCurrentScreen() for more details. 
  • queried_screen : JSON Object : contains data about the screen that's about to be displayed (same format as current_screen).
  • current_view : WP-AppKit extended version of the Backbone View Object, contains info about the data used to render the current screen (template name, static screen or not, etc). Not needed in most cases, useful for debug.
navigateToPreviousScreen App.navigateToPreviousScreen()

Navigate to previous screen, according to app’s history.

Should be used along with getBackButtonDisplay() to setup your theme’s back button.

//Go to previous screen when clicking back button:
$back_button.click( function ( e ) {
        e.preventDefault();
        App.navigateToPreviousScreen();
} );

Back Button

getBackButtonDisplay App.getBackButtonDisplay()

Allows to check if a back button has to be displayed.

In the Android world, devices have a physical back button. That’s the main difference compared with iOS where back buttons are part of the app’s user interface. iOS back button is used when displaying a post detail. It allows to go back to the post list the post belongs.

App.getBackButtonDisplay() is used to detect when to display a back button in your theme. It returns true in the following cases.

Coming From Currently at
Archive (post list) Single (post)
Single (post) Comments
Page Subpage

Example in functions.js :

// iOS back button support
if ( App.getBackButtonDisplay() ) {
			
   // Display iOS back button
   $("#back-button").css("display","block");
   $("#menu-button").css("display","none");
		
} else {
			
    // Display the menu button as iOS back button is not supported
    $("#back-button").css("display","none");
    $("#menu-button").css("display","block");

}

In this case you would then handle click (or touch) events on your back button to navigate to the previous screen manually, for example, in functions.js :

$("#my-container").on("touchend","#my-back-button", function() {
    // Go back to the previous screen
    App.navigate( TemplateTags.getPreviousScreenLink() );
} );
displayBackButton TemplateTags.displayBackButton()

This is the template tag version of the previous App.getBackButtonDisplay() if you want to handle the back button display directly in a dynamic template like single.html or archive.html.

More posts can be displayed in lists when you have a total number of posts in your list that is greater than the number of posts per page (the number of posts per page can be defined in the WP AppKit Settings panel in WordPress back office).

For example, to display a “Get more posts” button in archive.html that will get the following :

<% if( TemplateTags.displayGetMoreLink() ) { %>
      <button class="my-get-more">Get more posts (<%= TemplateTags.getMoreLinkNbLeft() %> left)</button>
<% } %>

And then, in functions.js, you will get the following [number of posts per page] posts of your list by doing something like :

$( '#my-container' ).on( 'click', '.my-get-more', function( e ) {
      e.preventDefault();
      $( this ).attr( 'disabled', 'disabled' ).text( 'Loading...' );
      App.getMoreComponentItems( function() {
            //If something is needed once items are retrieved, do it here.
            $( this ).removeAttr( 'disabled' );
      } );
} );

Note : if the “get more” link is included in the archive.html template (which is recommended), it will be automatically refreshed  by App.getMorecomponentItems() (internally, the view is reloaded and the archive template re-computed) : you don’t have to show/hide the “get more” link manually according to the number of remaining posts to be displayed.

getMoreLinkNbLeft TemplateTags.getMoreLinkNbLeft()

Retrieves the number of remaining posts in the current list. Use this in the archive.html template.

For example, if you have a total of 24 posts in your list and you choose to display 10 posts per page in your WP AppKit Settings panel, TemplateTags.getMoreLinkNbLeft() will return :

  • 14 on the first list page
  • 4 once you have clicked the “Get more post” link for the first time
  • 0 if you re-click “Get more post” (but in this case the “Get more post” link should not appear if you used “if ( TemplateTags.displayGetMoreLink() ) ” to display your link.
<% if( TemplateTags.displayGetMoreLink() ) { %>
      <button class="my-get-more">Get more posts (<%= TemplateTags.getMoreLinkNbLeft() %> left)</button>
<% } %>

See the above “Get more posts in lists” for a complete example.

getMoreComponentItems App.getMoreComponentItems( cb_after, cb_error )

Use this in functions.js to retrieve the [number of posts per page] next posts of a list.

$( '#my-container' ).on( 'click', '.my-get-more', function( e ) {
      e.preventDefault();
      $( this ).attr( 'disabled', 'disabled' ).text( 'Loading...' );
      App.getMoreComponentItems( 
            function() {
                  //If something is needed once items are retrieved, do it here.
                  $( this ).removeAttr( 'disabled' );
            },
            function( error ) {
                  //If something is needed when an error occured, do it here.
                  $( this ).removeAttr( 'disabled' );
            }
      );
} );

Note that getMoreComponentItems() reloads the list view and re-computes the archive.html template when it’s finished, so you can let TemplateTags.displayGetMoreLink() and TemplateTags.getMoreLinkNbLeft() do their job to show/hide the “Get More” button after retrieving new posts for the list, don’t need to do it manually.

Arguments :

The cb_after callback is called if items were retrieved successfully. It receives 3 arguments :

  • is_last : boolean : true if we reached the last page of pagination
  • new_items : array : posts freshly retrieved
  • nb_left : int : number of remaining posts in the list (posts we haven't retrieved yet)

But you shouldn't have to use those arguments as TemplateTags.displayGetMoreLink() and TemplateTags.getMoreLinkNbLeft() allow to handle this automatically

The cb_error callback is called in case an error occured. It receives an error event object.

getGetMoreLinkDisplay App.getGetMoreLinkDisplay()

Retrieves data about the “Get more posts” link. Useful only if you need to implement your “Get more posts” link manually without using TemplateTags.displayGetMoreLink() and TemplateTags.getMoreLinkNbLeft().

Returns :

JSON object : "Get more posts" link data containing :

  • nb_left : int : number of posts remaining : same as TemplateTags.getMoreLinkNbLeft()
  • display : boolean : true if there are still some posts left to retrieve in the list : same as TemplateTags.displayGetMoreLink()
use-standard-pagination App.filter( 'use-standard-pagination', function( use_standard_pagination, current_component_id, current_screen ) { ... } );

Use this filter to set standard pagination type for the component instead of “infinite scroll” pagination. This is useful for search or custom query components that are not ordered by date desc.

WP-AppKit supports 2 kinds of pagination:

  • Infinite Scroll pagination“: retrieves posts before the last post in the list (by passing its id in “before_id” param).
    It avoids post display duplication when getting page>1 and a new post was created in the meantime.
    This is the default behaviour for the “Get More Posts” button in WP-AppKit’s post lists.
    It is nice but can conflict with some custom queries that are not ordered by date for example.
  • Standard pagination“: corresponds to the standard use of “paged” param in WP_Query. This is the post lists pagination logic used by default in WordPress themes.
    Return true as a result of this ‘use-standard-pagination’ filter to activate it.

Those 2 pagination types are exclusive per component: you can’t use both at the same time.
If standard pagination is set, infinite scroll pagination is ignored.

An example that sets standard pagination for a “my-custom-component” component:

App.filter( 'use-standard-pagination', function( use_standard_pagination, component_id ) {
    if ( component_id === 'my-custom-component' ) {
        use_standard_pagination = true; 
    }
    return use_standard_pagination;
});
Arguments :
  • use_standard_pagination: bool: set to true to use standard pagination, false to use "infinite scroll" pagination (default false).
  • current_component_id: string: the component we use pagination for.
  • current_screen: JSON Object: the screen we're currently on.
Returns :

Return modified "use_standard_pagination" (true/false) to set pagination type (standard or not).

Transitions

The app’s engine dynamically places main content (lists, singles, comments) in a div.app-screen inside the div#app-content-wrapper, using the corresponding templates (archive.html, single.html, comments.html).

During a screen change, the div#app-content-wrapper is the only one that is modified. The menu (div#app-menu) and any static HTML defined in layout.html remain unaltered. To make any modifications on those areas before or after a screen change using JavaScript, use the app’s events in the functions.js file.

content_wrapper_detail
When transitioning from a screen to another (let’s say from a list to a single), here is what happens:

  • The engine internally renders the new screen using the appropriate template (here single.html) and puts the result in a new div with .app-screen CSS class.
  • At this point, this new div is not attached to the DOM yet, it is just a JavaScript object. We can manipulate it, insert (and animate) it anywhere into the DOM.
  • The current screen (soon to be the previous screen) is still here, not changed, still having its .app-screen class and also available to JavaScript to be animated.
  • Here, the Theme API allows you to customize the way you make the transition between the current and the next screen by setting the app’s parameter custom-screen-rendering to true. Then you can get the current “transition direction” from ThemeApp.getTransitionDirection() and implement your own transitions (with CSS/Javascript) by hooking to the screen-transition app’s action.
  • If you don’t customize the screen transitions, a simple replacement is made by the core using something equivalent to $(‘#app-content-wrapper’).empty().html($next_screen) , after having cleanly closed the current screen view (unbind events, call close on Backbone views).
  • If you implement your own transitions, you are in charge of removing the old screen (the div.app-screen containing the ex current screen) from the DOM when the transition ends (and to handle the JavaScript events unbinding on this old screen if necessary).
custom-screen-rendering App.setParam( 'custom-screen-rendering', true );

Set the ‘custom-screen-rendering’ param to true if you want to define your own transitions (with CSS and Javascript) between app screens.

By default, if you don’t specifically set this ‘custom-screen-rendering’ param in your theme, it is set to false: no transitions between screens just a simple jQuery DOM replacement.

“screen-transition” action App.action( 'screen-transition', function( $wrapper, $current, $next, current_screen, next_screen, $deferred ) { ... $deferred.resolve() } );

Action hook that allows to define custom transitions between screens.

Example that defines custom transitions for basic screen navigation operations:

App.action( 'screen-transition', function(
    $wrapper,
    $current,
    $next,
    current_screen,
    next_screen,
    $deferred ) {

    // Get the direction keyword from current screen and previous screen:
    // By default transition directions can be 'next-screen', 'previous-screen' or 'default'.
    // And themes can define their own custom directions using the 'transition-direction' hook.
    var direction = App.getTransitionDirection( current_screen, next_screen );
    
    // Launch proper transition
    switch ( direction ) {
        case 'next-screen': // eg. "Archive to single" or "Single to comments"
            my_transition_to_next_screen($wrapper,$current,$next,current_screen,next_screen,$deferred);
            break;
        case 'previous-screen': // eg. "Single to archive" or "Comments to single"
            my_transition_to_previous_screen($wrapper,$current,$next,current_screen,next_screen,$deferred);
            break;
        default: // Unknown direction
            my_transition_default($wrapper,$current,$next,current_screen,next_screen,$deferred);
            break;
    }

});

In the above example, my_transition_to_next_screen(), my_transition_to_previous_screen() and my_transition_default() are functions that you implement yourself in the theme and that actually do the transition between $current and $next with CSS and/or Javascript. For example, in my_transition_to_next_screen() you will slide $next on top of $current, then remove $current from DOM.
Important: those transition functions must call $deferred.resolve() when finished to tell the core that the new screen is rendered.

Arguments :
  • $wrapper: jQuery Object corresponding to div#app-content-wrapper, which is the element wrapping $current and $next screens.
  • $current: jQuery Object corresponding to the screen (div.app-screen) that we're leaving, to display $next instead.
  • $next: jQuery Object corresponding to the new screen (div.app-screen) that we want to display (by replacing $current).
  • current_screen: JSON Object: screen object containing information (screen type, screen item id, etc) about the screen we're leaving (see getCurrentScreen() for details about screen objects).
  • next_screen: JSON Object: screen object containing information about the new screen we want to display.
  • $deferred: jQuery deferred object that must be resolved at the end of the transition animation to tell app core that the new screen has finished rendering.
getTransitionDirection App.getTransitionDirection( current_screen, next_screen );

Allows to retrieve the transition direction that correspond to the navigation from current_screen to next_screen.

By default there are 3 transition directions:

  • next-screen: when going from archive to single (ie. current_screen.screen_type == ‘single’ and next_screen.screen_type == ‘list’), or single to comments.
  • previous-screen: when going back to single from archive, or back to single from comments.
  • default: when none of the above. For example when displaying a page, when going from single to single, or going from comments directly to archive.

And you can add any custom transition directions that you need, using the ‘transition-direction‘ filter. See the following example that shows how to define a custom transition when displaying comments screens.

Arguments :
  • current_screen: JSON Object: screen object containing information (screen type, screen item id, etc) about the screen we're leaving (see getCurrentScreen() for details about screen objects).
  • next_screen: JSON Object: screen object containing information about the new screen we want to display .
Returns :

String: transition direction name: by default 'next-screen', 'previous-screen', 'default'

“transition-direction” filter App.filter( 'transition-direction', function( transition_direction, current_screen, next_screen ) { ... return transition_direction; }

Filter that allows to define your own transitions names, other than the default ones (‘next-screen’, ‘previous-screen’ and ‘default’).

For example if you want to define a custom animation when going from “single screen” to “comments screen” that is different than when going from “archive screen” to “single screen” you first have to declare those new kind of transitions using the “transition-direction” filter:

App.filter( 'transition-direction', function( transition_direction, current_screen, next_screen ) {
    
    // Single to comments transition
    if ( current_screen.screen_type == 'single' && next_screen.screen_type == 'comments' ) {
        transition_direction = 'single-to-comments';
    }

    // Comments to single transition
    if ( current_screen.screen_type == 'comments' && next_screen.screen_type == 'single' ) {
        transition_direction = 'comments-to-single';
    }
    
    return transition;
        
});

Then those new transition directions (‘single-to-comments’ and ‘comments-to-single’) become available as a result of App.getTransitionDirection( current_screen, next_screen ), that you’ll use in the ‘screen-transition’ action to implement the corresponding custom transitions:

App.action( 'screen-transition', function( $wrapper, $current, $next,
                                           current_screen, next_screen,
                                           $deferred ) {

    var direction = App.getTransitionDirection( current_screen, next_screen );
    
    switch ( direction ) {
        case 'single-to-comments': 
            my_transition_single_to_comments($wrapper,$current,$next,current_screen,next_screen,$deferred);
            break;
        case 'previous-screen':
            my_transition_comments_to_single($wrapper,$current,$next,current_screen,next_screen,$deferred);
            break;
    }

});

And my_transition_single_to_comments(), defined further in your theme (in functions.js, or a dedicated JS module) may look like:

function transition_single_to_comments ( $wrapper, $current, $next, 
                                         current_screen, next_screen,
                                         $deferred ) {
		
        // Add comments ($next) to a slideup panel
        $('#slideup-panel #panel-content').empty().append( $next );

	// Slide UP the comments panel
        $('#slideup-panel').velocity({
            top: '0px'
        },{
            duration: 300,
            easing: 'ease-out',
            complete: function () {
                $deferred.resolve(); // Transition has ended, tell the core
            }
        });
}
Arguments :
  • transition_direction: string: Transition direction name. Define your own directions by modifying this value according to current_screen and next_screen and return it!
  • current_screen: JSON Object: screen object containing information (screen type, screen item id, etc) about the screen we're leaving (see getCurrentScreen() for details about screen objects).
  • next_screen: JSON Object: screen object containing information about the new screen that is going to be displayed.

Network states (online/offline)

getNetworkState TemplateTags.getNetworkState(full_info)

Retrieves information about the current network connection.

Can be used in templates as a template tag( TemplateTags.getNetworkState(full_info) ) and in functions.js ( App.getNetworkState(full_info) ) :

Example that you can use in any template to display the current network state :

<% var network_state = TemplateTags.getNetworkState(); %>
<% var network_state_detailed = TemplateTags.getNetworkState(true); %>
<div class="network-info">
       Network connexion : <%= network_state %><br/>
       Detailed connexion info : <%= network_state_detailed %>
</div>

Internally, WP AppKit retrieves network information using the “Network Information” Phonegap plugin (which is included by default in WP AppKit PhoneGap exports).

If the plugin is not available, WP AppKit falls back on the HTML5 API using navigator.onLine .

Arguments :
  • full_info : Boolean : Optionnal (Default false) : If false, returns only "online", "offline" or "unknown". If true, returns more detailed information about the network connection.
Returns :

String : Network connection state.

If full_info is false (default)  : returns "online", "offline" or "unknown". Unknown is returned if the app could not retrieve network information from the device.

If full_info is true : returns detailed information about the network connection : return values can be :

  • 'Unknown connection'
  • 'Ethernet connection'
  • 'WiFi connection'
  • 'Cell 2G connection'
  • 'Cell 3G connection'
  • 'Cell 4G connection'
  • 'Cell generic connection'
  • 'No network connection'
network:online App.on( 'network:online', callback)

This event is fired when the device could connect to the network.

Example of how to use this in functions.js to display a message when internet is back :

App.on( 'network:online', function(event) {
      $( '#feedback' ).html( "Internet connexion ok :)" );
} );

Internally, WP AppKit uses the online event of the “Network Information” Phonegap plugin (which is included by default in WP AppKit PhoneGap exports).

If the plugin is not available, WP AppKit falls back on the HTML5 API using window.ononline.

Arguments :

Callback arguments :

  • event : JSON object : contains detailed information about the event.
network:offline App.on( 'network:offline', callback)

This event is fired when the device lost connection to the network.

Example of how to use this in functions.js to display a message when internet is lost :

App.on( 'network:offline', function(event) {
      $( '#feedback' ).html( "Internet connexion lost :(" );
} );

Internally, WP AppKit uses the offline event of the “Network Information” Phonegap plugin (which is included by default in WP AppKit PhoneGap exports).

If the plugin is not available, WP AppKit falls back on the HTML5 API using window.onoffline.

Arguments :

Callback arguments :

  • event : JSON object : contains detailed information about the event.

Storage

2 kinds of storage are available in WP AppKit themes :

  1. Temporary storage (non persistent)
  2. Persistent storage

Both non persistent and persistent storage modules use a “group / key / value” pattern to store data, as explained below :

Temporary Storage

The Temporary Storage module allows to memorize data for the current app session only. Stored in the current JavaScript context, Temporary Storage data survives app navigation but is lost when the app is closed.

This can be useful to store some UI state of your app that is only related to the current app session and that you don’t mind losing when the app is killed.

To use it in your theme, add the “core/modules/storage” dependency to your functions.js :

define( [ ..., 'core/modules/storage', ... ], function( ..., TempStorage, ... ) {

Here is an example using this Temporary Storage module to memorize scroll position when leaving a list so that we can get back to this scroll position  when coming back later from a single. We do this by binding to the screen:leave and screen:showed events (in functions.js for example) :

App.on( 'screen:leave', function( current_screen ) {
   if ( current_screen.screen_type == 'list' ) {
      //Memorize scroll position :
      var list_id = current_screen.fragment;
      TempStorage.set( 'scroll-pos', list_id, $('body').scrollTop() );
   }
});

App.on( 'screen:showed', function( current_screen ) {
   if ( current_screen.screen_type == 'list' ){
      //Retrieve scroll position and scroll to it :
      var list_id = current_screen.fragment;
      var pos = TempStorage.get( 'scroll-pos', list_id );
      if( pos !== null ) {
         $('body').scrollTop( pos );
      }
   }
});

Here, scroll-pos is the storage group. In this group we store a scroll position $(‘body’).scrollTop()  per list, using current_screen.fragment as storage key (which is a unique id for the list, see TemplateTags.getCurrentScreen()).

set TempStorage.set ( group, key, value )

Store a value in temporary storage.

Arguments :
  • group : string : the group (see this as a namespace) where the key / value pair will be stored
  • key : string : a string identifier for your data
  • value : mixed : data value that you want to memorize
get TempStorage.get ( group, key )

Retrieve a value from temporary storage.

Arguments :
  • group : string : the group (see this as a namespace) where the key / value pair has been stored
  • key (Optionnal) : string : the string identifier used to store the data. If not provided, will return the whole group.
Returns :

mixed : data that was stored at group:key

null if group:key doesn't exist.

clear TempStorage.clear ( group )

Delete data that are stored under the given group.

Arguments :
  • group : string : all key/values in this group will be deleted from temporary storage
clearAll TempStorage.clearAll()

Clear all data in temporary storage

Persistent Storage

The Persistent Storage module stores data in the app’s Local Storage, which makes the memorized data persistent even if the app is closed or updated.

As with  the temporary storage module, data is stored in a “group / key / value” format.

To use it in your theme, add the “core/modules/persistent-storage” dependency to your functions.js :

define( [ ..., 'core/modules/persistent-storage', ... ], function( ..., PersistentStorage, ... ) {

Here is an example that uses the Persistent Storage module to count the number of times a given page has been seen by the app’s user :

App.on( 'screen:showed', function( current_screen ) {

   if ( current_screen.screen_type == 'page' && current_screen.page_id == my_page_id ) {

      //Set a group and a key to store our counter value :
      var storage_group = 'page-open';
      var storage_key = 'page-'+ my_page_id;

      //Get the counter value from Local Storage :
      var count_page_open = PersistentStorage.get( storage_group, storage_key, 0 ); //default count value is 0

      //Increment counter :
      count_page_open += 1;

      //Memorize counter new value :
      PersistentStorage.set( storage_group, storage_key, count_page_open );

   }

});
set PersistentStorage.set ( group, key, value )

Store a value in persistent storage.

Arguments :
  • group : string : the group (see this as a namespace) where the key / value pair will be stored
  • key : string : a string identifier for your data
  • value : mixed : data value that you want to memorize
get PersistentStorage.get ( group, key, default_value )

Retrieve a value from persistent storage.

Arguments :
  • group : string : the group (see this as a namespace) where the key / value pair has been stored
  • key (optionnal) : string : the string identifier used to store the data. If not provided, will return the whole group.
  • default_value (optionnal) : mixed : value that will be returned if no data is found in storage for group:key. If none provided, null is returned in that case.
clear PersistentStorage.clear ( group, key )

Delete data that are stored under the given group (and optionally the given key).

Arguments :
  • group : string : group you want to delete keys from. 
  • key (optionnal) : string : specific key to delete. If none, all key/values in the given group will be deleted from persistent storage
clearAll PersistentStorage.clearAll()

Clear all data in persistent storage (use with caution!).

User Authentication

In a nutshell, here is how user authentication is handled from the app point of view:

  • The app internally maintains a CurrentUser object
  • this user can be “not authenticated” (not logged in) or “authenticated” (logged in)
  • a user authenticates with his/her login and passwords directly from an HTML form defined in the app’s theme (all sensitive data are encrypted using RSA public key encryption before being sent to server)
  • when a user is authenticated, you can access his/her “user permissions” that are made of his/her WordPress roles and capabilities
  • the authentication is persistent : memorized in local storage, the user will stay authenticated even if he/she kills and restarts the app
  • the user can log out manually, from a logout button somewhere in the theme for example
  • or, the app theme can choose to make remote checks to server to see if the user authentication is still valid, and if not, log out will trigger automatically

This section details the JS API that allows to handle user authentication from your app theme.

You can load the authentication module in your theme by requiring it like so (in functions.js or any theme’s js module of your own) :

define( [ 'core/modules/authentication', 'other-dependency', ... ], function( Auth, OtherDependency, ... ) {
      //Your code using Auth : 
      //for example Auth.logUserIn( user, pass )
} )

To see an example of a theme implementing the user authentication, you can take a look at the User Login version of the Bootstrap theme.

See also the User Login feature section to learn how to setup your app for authentication by generating a RSA private key.

logUserIn Auth.logUserIn( login, pass, cb_ok, cb_error )

Logs the given user in from given login/password.
Use this to log a user in from your theme.

Note : all sensible data (password) is encrypted with RSA public key encryption in the process.

Example that logs a user in when we click the login button (#go-login) of a login form containing login and password inputs :

$( '#login-wrapper' ).on( 'click', '#go-login', function( e ) {
      e.preventDefault();
      Auth.logUserIn( 
            $('#userlogin').val(), //from form text input#userlogin 
            $('#userpass').val() //from form password input#userpass
      );
} );
Arguments :
  • login {string} User login
  • pass {string} User password
  • cb_ok {function} What to do if login went ok (or you can also bind to authentication info events with App.on( 'info' ) to react to login success)
  • cb_error {function} What to do if login went wrong (or you can also bind to authentication error events with App.on( 'error' ) to react to login errors)
logUserOut Auth.logUserOut()

Logs the user out.

Example that logs the user out when clicking a logout button (#logout) :

$( '#login-wrapper' ).on( 'click', '#logout', function( e ) {
      e.preventDefault();
      Auth.logUserOut();
} );
getCurrentUser Auth.getCurrentUser( field )

Get info about the currently logged in user.

Example that uses the “template-args” filter to make logged in user data available in a custom user page template :

App.filter( 'template-args', function( template_args, view_type, view_template ) {
      if ( view_template == 'user-page' ) { //we are displaying the user page
            var current_user = Auth.getCurrentUser();
            if ( current_user ) {
                  //Make user info available in the user page template :
                  template_args.user = {
                        login: current_user.login,
                        role: current_user.permissions.roles.pop(),
                        capabilities: current_user.permissions.capabilities
                  };
            }
      }
      return template_args;
} );
Arguments :
  • field  {String} (Optional) to get a specific user data field (can be 'login', 'permissions')
Returns :

If no field is provided, returns a JSON Object containing :

  • login {String}
  • permissions {JSON Object}

If field is provided, returns the asked field

If no user is logged in, returns null.

userIsLoggedIn Auth.userIsLoggedIn()

Check if a user is currently logged in.

Note : this only checks if a user is locally logged in into the app : it does not make a remote check to see if his/her connection is still valid on server side :
use Auth.checkUserAuthenticationFromRemote() for that.

Returns :

{Boolean} Returns true if a user is logged in

checkUserAuthenticationFromRemote Auth.checkUserAuthenticationFromRemote( cb_auth_ok, cb_auth_error )

If a user is logged in, does a remote server check to see if his/her connection is still valid by verifying public key and user secret from server.

If we reached the server and it answered authentication is not ok, Auth.logUserOut() is automatically called internally to trigger logout events.

Example that checks if the user authentication is still valid at each app launch :

App.on( 'info:app-ready', function() {
      Auth.checkUserAuthenticationFromRemote(
            function( current_user ){
                  //The user is still connected ok
            },
            function( error ){
                  //The user has been disconnected, or was not connected.
                  //Logout events are triggered and can be intercepted with App.on( 'info' );
            }
      );
} );
Arguments :
  • cb_auth_ok {function} Called if the user is connected ok
  • cb_auth_error  {function} Called if the user is not connected
currentUserCan Auth.currentUserCan( capability )

Checks if the current user has the given capability.

Can be customized using the “current-user-can” filter (and “wpak_auth_user_permissions” filter on server side).

Example that redirects a user to the login page when he/she tries to access a post and does not have the right capability :

App.filter( 'redirect', function( redirect, queried_screen ) {
      if ( queried_screen.screen_type == 'single' 
           && !Auth.currentUserCan( 'premium_capability' ) 
      ) {
            App.navigate( 'login-page' );
            redirect = true;
      }
      return redirect;
} );
Arguments :
  • capability    {string}   Capability we want to check
Returns :

{Boolean}  True if the user has the given capability in his/her permissions

currentUserRoleIs Auth.currentUserRoleIs( role )

Checks if the current user has the given role.

Can be customized using the “current-user-role” filter (and “wpak_auth_user_permissions” filter on server side)

Arguments :
  • role   {string}   Role we want to check
Returns :

{Boolean}  True if the user has the given role in its permissions

getActionAuthData Auth.getActionAuthData( action, control_data_keys, control_data )

Generates authentication control data for any custom webservice action.

This can be used from addons or modules that need to authenticate their webservice calls (used for the Comments module for example).

It generates a control hash based on control_data/user/timestamp/user_secret_key that allows to check on server side that the query comes from the right user and has not been modified.

Arguments :
  • action {string} Webservice query action name
  • control_data_keys {array} Ordered keys of the data you want to control (order is important for the hash control!)
  • control_data {JSON Object} Data you want to control.
Returns :

{JSON Object} Object containing the authentication data, that can be checked directly with WpakRsaPublicPrivateAuth::check_authenticated_action() on server side

Set custom user data

By default the user object on app side retrieved with Auth.getCurrentUser() contains 2 fields: login and permissions.

To attach more data to the user object you can use the “wpak_auth_user_info” filter on PHP side. Here’s an example that adds the user email to the user data sent to the app:

//Put this code in a PHP file inside the "php" folder of your theme
add_filter( 'wpak_auth_user_info', 'add_custom_user_info', 10, 3 );
function add_custom_user_info( $user_info, $user_id, $app_id ) {
	
	//Add user's display_name and email to the user info sent to the app:
	$user_wp = get_user_by( 'id', $user_id );
	if ( $user_wp ) {
		$user_info['display_name'] = $user_wp->display_name;
		$user_info['email'] = $user_wp->user_email;
		//(We could also retrieve some other user meta data here using WordPress's  get_user_meta() function)
	}
	
	return $user_info;
}

Then, in your app theme you can access display_name and email under the “info” field of the user object:

//In your app theme's functions.js:
var current_user = Auth.getCurrentUser();
console.log( current_user.info.display_name, current_user.info.email );

And you’ll certainly want to pass your user object to your templates, here’s how to do so:

//In your app theme's functions.js:
App.filter( 'template-args', function( template_args, view_type, view_template ) {
	//Here we suppose that you have a custom template 'user-page.html'
	//but it could be any template 'single', 'archive' etc.
	if ( view_template === 'user-page' ) {
		var current_user = Auth.getCurrentUser();
		if ( current_user ) {
			template_args.user = {
				login: current_user.login,
				display_name: current_user.info.display_name,
				email: current_user.info.email
			};
		}
	}
	return template_args;
} );

 

Comments

By default, post comments are not embedded in WP-AppKit post data.

Comments are retrieved separately by calling ThemeApp.displayPostComments( post_id ), that calls the WP-AppKit comments endpoint to retrieve comments from the server.

As for v0.4 and User Authentication, comments can also be posted from apps (beta feature).

displayPostComments ThemeApp.displayPostComments

Displays the comments screen for a given post.

Retrieves the post comments from server or from memory if already cached, then navigate to #comments-[post_id].

Using this function allows to use success and error callbacks (cb_ok/cb_error), which you can’t do if you navigates directly to #comments-[post_id] in your theme.

Example:

$( "#container" ).on( "click", ".comments", function( e ) {
	e.preventDefault();
		
	$('#waiting').show();
		
	App.displayPostComments( 
		$(this).attr( 'data-post-id' ),
		function( comments, post, item_global ) {
			//Do something when comments display is ok
			//We hide the waiting panel in 'screen:showed' to avoid flickering, because 
			//at this point, comments are retrieved but not rendered
		},
		function( error ){
			//Do something when comments display fail 
			//(note that an app error is triggered automatically)
			$('#waiting').hide();
		}
	);
} );

Note that the cb_ok() callback is called after comments are retrieved, and not after the comments view is rendered (as view rendering must be done later, in router).
If you need to do something after the comments screen is showed, you can use the ‘screen:showed’ event where you’ll test if ( current_screen.screen_type === ‘comments’ ) ).

Arguments :
  • post_id {int} Post we want to retrieve the comments for.
  • cb_ok {function} What to do if comments are retrieved ok. Receives 3 arguments : comments, post, global (the internal global collection the post belongs to)
  • cb_error {function} What to do if an error occurs while retrieving comments. Receives an error event object.
Comments module

The Comments module works along with User Authentication to allow to post comments from the app.

You can load the comments module in your theme by requiring it in functions.js or any theme’s js module of your own:

define( [ 'core/modules/comments', 'other-dependency', ... ], function( Comments, OtherDependency, ... ) {
      //Your code using Comments: 
      //for example Comments.postComment( ... ) 
} )
postComment Comments.postComment( comment, cb_ok, cb_error )

(beta) Post a comment to server. Use this to submit a comment from your theme.

Note :

  • a user must be logged in to comment, this function will fail if no user is logged in, calling the error callback.
  • if the server answers that the given user’s connection is not valid (expired for example), logout events are automatically triggered.

Complete example of comment posting :

/**
* On comment form submit, we retrieve comment content and post ID from the
* form and use Comments.postComment() to submit it to the server.
* 
* Internally, if the comment query is successful the new comment is automatically added
* to the post comment list, so here we just have to rerender the comment screen,
* to make the new comment appear in the comment list.
*/
$( '#app-content-wrapper' ).on( 'submit', '#comment-form', function( e ) {
    e.preventDefault();
		
    var $submit_button = $( '#comment-form [type="submit"]' );
    $submit_button.attr( 'disabled', 'disabled' ).text( 'Sending...' );
		
    var comment = {
        content : $( '#comment-form [name="content"]' ).val(),
        post : $( '#comment-form [name="post"]' ).val()
    };
		
    Comments.postComment( 
        comment,
        function( comment_data ) {
            //Comment created OK!
				
            //Reset submit button :
            $submit_button.removeAttr( 'disabled' );
				
            //Empty comment edition :
            $( '#comment-form [name="content"]' ).val('');
				
            //Re-display current view (comments view) 
            //to display the new comment in the list :
            App.rerenderCurrentScreen();
				
            //Scroll top so that we can see the following feedback message: 
            window.scrollTo( 0, 0 );
				
            //Display a happiness message :
            var message = !comment_data.waiting_approval ? 
                          'Comment added successfully :)' : 'Your comment is awaiting moderation';

            $( '#feedback' ).removeClass( 'error' ).html( message ).slideDown();

        },
        function( error ) {
            //Reset submit button :
            $submit_button.removeAttr( 'disabled' ).text( 'Submit comment' );
				
            //Scroll top so that we can see the feedback message 
            //that comes up through theme error handling. 
            window.scrollTo( 0, 0 );
				
            //Error messages display can be handled by 
            //App.on( 'error' ) or App.filter( 'theme-event-message' )
        }
    );

} );
Arguments :
  • comment {JSON Object} Comment object : must contain at least the following fields :
    • content {string} The comment content
    • post {int} ID of the post we're commenting on
  • cb_ok {function} What to do if comment was posted ok.
  • cb_error {function} What to do if comment posting failed.

Events

When the app core reaches some key endpoints in its process (app launch, content refresh, network connection etc), it triggers events that can be intercepted from themes to react accordingly.

Events families are grouped using the “group_prefix:event” format (error:*, info:*, network:*, screen:* etc) and you bind to them from themes using the App.on() method.

Events are asynchronous : the callbacks you bind to them don’t stop the app’s execution, and you can’t return any value from them to be interpreted by the app core. Synchronous/sequential interactions are handled in WP-AppKit using Javascript Hooks and App Parameters logic.

on App.on ( app_event, callback )

Attach an event handler function for the given app event.

App.on() is used intensively in functions.js : this is the main way for themes to intercept app core processes and react to them .

An example that reacts to the ‘refresh:start’ event :

//In functions.js :
App.on('refresh:start',function(){
      $('#my-refresh-button').addClass('refreshing');
});
Arguments :
  • app_event : String : app event (like 'refresh:start', 'screen:showed' ...)
  • callback : Function : function to call when the event is triggered. See each event documentation detail to know the arguments passed to this callback.
Error and info events

Error and info events (error:* and info:*) can be used in a specific way in themes:

You can either bind to them one by one like any other event:

App.on( 'error:synchro:ajax', function( error ) {
      $( '#my-feedback' ).addClass( 'error' ).html( error.message ).show();
} );

But as there are many different error events, you certainly don’t want to bind to all of them manually. To avoid that you can use the generic ‘error’ event:

App.on( 'error', function( error ) {

      //And if you want to target a specific error :
      if ( error.event == 'synchro:ajax' ) {
            //Show something special when app synchronization fails
      }

      $( '#my-feedback' ).addClass( 'error' ).html( error.message ).show();
} );

And the same applies to info events:

App.on( 'info:app-ready', function( info ) {
      //My action when app is ready
} );

is equivalent to:

App.on( 'info', function( info ) {
      if ( info.event == 'app-ready' ) {
            //My action when the app is ready
      }
} );

error and info argument passed to events callbacks have the same format: a JSON Object containing:

  • event: String: event name with no group prefix: ‘synchro-ajax’, ‘app-ready’ …
  • type: String: ‘error’ or ‘info’
  • subtype: String: specific error type (alias of core_data.type). Not used for infos.
  • message: String: error or info message. See “theme-event-message” filter to learn how to customize those event messages.
  • core_data: JSON Object:
    • for errors: error object (see below)
    • for infos: JSON data depending on the info event

Error objects passed through error.core_data contain:

  • type: String: error type (‘ajax’, ‘web-service’, ‘not-found’, ‘wrong-data’, etc)
  • where: String: function or code location where the error occured
  • message: String: error message (from core)
  • data: JSON Object: data depending on the error
“theme-event-message” filter App.filter( 'theme-event-message', function( message, event_data, event ) { ... return message; }

This filter allows to customize event messages.

By default, WP-AppKit defines only 2 error messages:

  • “Remote connection to website failed” for any unsuccessful ajax query (ie event.subtype == ‘ajax’)
  • “Oops, an error occured…” for any other error event

And 1 info message:

  • “The application couldn’t retrieve any content, please check your internet connection!” (info:no-content)

You can change those default messages and add other messages for any other event by using the “theme-event-message” filter.

Here is an example where we customize the message displayed when an AJAX query fails (for example when trying to refresh app content while being offline):

App.filter( 'theme-event-message', function( message, event_data, event ) {
		
	if ( event_data.type == 'error' && event_data.subtype == 'ajax' ) {
		message = 'My custom message in case a remote AJAX call failed.';
	}
		
	return message;
} );
Arguments :
  • message: string: Message to customize and return
  • event_data: JSON Object containing (See Error and Info events for details): 
    • type ("error"/"info" )
    • subtype ("ajax", "web-service", "not-found" ... )
    • message
    • core_data
  • event: string: event name ("synchro:ajax" ... )
“stop-theme-event” filter App.filter( 'stop-theme-event', function( stop, theme_event_data, event ) { ... return stop; } );

Use this filter to avoid an event from triggering in the theme.

Useful to deactivate some error events display in your theme for exemple.

Arguments :
  • stop: boolean: Whether to stop the event or not. Default false.
  • theme_event_data: JSON Object: Theme event data object (contains "event", "type", "subtype", "message", "core_data")
  • event: String: Original (internal) event name
Error events reference

All error events have error.type = ‘error’.
Error events subtypes (error.subtype) are referenced in the following table.

Event name Event Subtype Description Data passed to event
(error.core_data.data)
Synchronization web service
synchro:ajax ajax Ajax query failed jQuery ajax error
synchro:wrong-format web-service Wrong web service answer format Web service answer
synchro:wrong-status web-service Wrong web service answer status Web service answer
synchro:ws-return-error web-service Web service returned an error Web service answer (error detail in data.result)
synchro:wrong-answer web-service Expected web service data not found Web service answer
synchro:no-component web-service No component found for the app Web service answer
Fetch post comments
comments:ajax ajax Ajax query failed jQuery ajax error
comments:post-not-found not-found Asked comments for a non existing post none
Get more component items
getmore:ajax ajax Ajax query failed jQuery ajax error
getmore:ws-return-error web-service Web service “component” returned an error none
getmore:wrong-component-id not-found Wrong component id none
getmore:global-not-found not-found Web service returned data for a non existent global none
“Live Query” web service
live-query:ajax ajax Ajax query failed jQuery ajax error
live-query:ws-return-error web-service Web service returned an error none
live-query:no-auto-interpret-action-found not-found Could not auto interpret Live Query web service answer none
live-query:update-global-items-error mixed Error while updating local component items from Live Query’s answer result object
live-query:update-component-error mixed Error while updating local component from Live Query’s answer result object
User authentication
auth:ajax-failed:* authentication-error Ajax query failed jQuery ajax error
auth:no-result authentication-error Wrong authentication web service answer none
auth:web-service-error authentication-error Authentication web service returned an error none
auth:no-auth-error authentication-error Authentication web service returned an unknown error none
auth:empty-user
auth:wrong-user
auth:wrong-pass
auth:user-banned
auth:wrong-data (*)
auth:wrong-hmac (*)
auth:wrong-query-time (*)
auth:php-openssl-not-found (*)
auth:empty-public-key (*)
auth:wrong-public-key
auth:wrong-auth-data (*)
auth:wrong-decryption (*)
auth:wrong-secret (*)
auth:no-hash
auth:user-not-authenticated
auth:user-connection-expired
(*) only if debug mode is on, otherwise = ‘auth:auth-error’
authentication-error Authentication failed none
Info events reference

All info events have info.type = ‘info’.
Info events have no subtype (info.subtype is an empty string).

Event name Description Data passed to event
(info.core_data)
App launch
app-ready App core and app theme are loaded. App router is launched. App stat object: count_open, last_open_date, last_sync, version, version_diff
app-first-launch First time the app is launched! App stat object: count_open, last_open_date, last_sync, version, version_diff
app-version-changed First app launch after an app version change App stat object: count_open, last_open_date, last_sync, version, version_diff
no-content The app could not load any content from remote server and has none in Local Storage yet. none
Get more component items
component:get-more “Get more” action was successful new_items, is_last, nb_left, new_ids, global, component
User Authentication
auth:user-login A user logged in successfully User and permissions data
auth:user-logout A user logged out successfully User, permissions and logout type data
Debug panel
debug-panel:render The debug panel has finished rendering Debug panel view object
Other core events reference

Those are general core events that are not triggered as info or error, so they don’t have corresponding type / subtype.
They may be merged into the info events in a future version (in a transparent way for theme users).

Event name Description Data passed to event
Refresh
refresh:start App refresh started none
refresh:end App refresh ended Result Object: ok, message (if error), data (if error: error object formatted as error event data)
Screen
screen:showed An app screen just finished to render current_screen, current_view
screen:leave App refresh ended current_screen (the screen we leave), queried_screen (the screen we go to), current_view
Menu
menu:rendered The menu just finished rendering (using menu.html) current_screen, menu view object
Network
network:online App just found network none
network:offline App just lost network connexion none

Parameters

Misc.

Obsolete

While in beta stage, we authorize ourselves to make some changes that can break backward compatibility.

Here we keep track of some functions that are now obsolete, meaning they don’t exist anymore and should not be used.

setAutoBackButton App.setAutoBackButton( $go_back_btn, do_before_auto_action ) Obsolete function. Removed in version 0.5, along with App.updateBackButtonEvents() to let themes decide how they handle back button, calling App.navigateToPreviousScreen() directly

If you don’t feel like setting up a back button manually, you can use App.setAutoBackButton() : it will automatically handle showing and hiding your back button according to current screen (list, single, page, comments, etc…).

Typically, you will define a back button (for example an HTML link with id=”my-back-button”) in the static layout.html template and define it as a back button in functions.js with :

App.setAutoBackButton( $('#my-back-button"), function( show ){
    if( show ){
        //Do something when the back button is showed
    }else{
        //Do something when the back button is hidden
    }
} );

Internally, “click” events are automatically set on your $go_back_btn to navigate to the previous screen. Touch events are not handled here, to use them you can set your back button manually :

  • Show/Hide manually using App.getBackButtonDisplay()
  • and navigate manually to previous screen with App.navigate( TempatelTags.getPreviousScreenLink() ).
Arguments :
  • $go_back_btn : jQuery Object corresponding to your back button : $('#my-back-button') for example.
  • do_before_auto_action : callback that is called before showing/hiding the back button. This callback receives 1 argument : "show" which is a boolean = true if the back button is shown and false if it is hidden.
updateBackButtonEvents App.updateBackButtonEvents( $go_back_btn ) Obsolete function. Removed in version 0.5, along with App.setAutoBackButton() to let themes decide how they handle back button, calling App.navigateToPreviousScreen() directly

Sets back buton click event that handle the navigation to the previous screen.

For example if you have a back button #my-back-button that you want to show/hide manually using your own CSS/JS (according to App.getBackButtonDisplay()) instead of using the full automated App.setAutoBackButton(), you don’t have to also handle navigation to the previous screen manually, you can use App.updateBackButtonEvents( $(‘#my-back-button’) ) and your back button becomes active.

Note : this sets “click” events, not touch events. For now, to handle touch events for your back button, you will have to do it manually :

  • Show/Hide manually using App.getBackButtonDisplay()
  • and navigate manually to previous screen with App.navigate( TemplateTags.getPreviousScreenLink() ).
Arguments :
  • $go_back_btn : jQuery Object corresponding to your back button : $('#my-back-button') for example.

Having questions?

FAQ | Tutorials | Documentation

Or

Contact Us