Content is added to your app using Components.
Let’s see what those components are, and how to hook into WP-AppKit webservices to customize content sent to apps.
Components
WP AppKit components are the content blocks that you use to build your app in the WordPress Back Office.
The main native WP AppKit components are :
- Posts list : allows to add lists of posts (filtered by post type and taxonomies) to your app
- Pages : allows to add single page or page tree to your app
And, as explained in the following section, you can define your own custom components.
The main thing to understand about components is that :
- their content is added to the main app web service (the web service called “Synchronization”)
- which implies that their content is fetched from WordPress (and memorized locally in the app for Offline browsing) at each app refresh.
Components are THE way to define and handle the dynamic content of your app, content that will always be synchronized with your WordPress instance.
Typically when building your app you add your components to the app navigation, and components data are accessed in your app theme templates without you really knowing it, through template variables and template tags.
But you can also add a component to your app without adding it to the app navigation. In this case, you will retrieve its data manually from your theme using the TemplateTags.getComponent(component_slug) template tag. This way you can send nearly any data from your WordPress to your app and be sure it is updated each time the app content is refreshed.
Out of the box, WP AppKit provides some generic components that allow to add WordPress content to your apps :
- post lists filtered by post type and taxonomies
- pages (single page or page tree)
But you can also define your own custom WP AppKit components.
That allows you to ship nearly any content, coming from WordPress or not, to your app.
Your custom component data is added to the WP AppKit synchronization web service and is handled the same way as other native components.
Just be aware that WP AppKit components (custom or not) only deal with content, they don’t add new features to the app. To add new features to WP AppKit apps, you will use the addons logic (and an addon, among all the things it can do, can add new components). The documentation about how to create WP AppKit addons is not ready yet, but we’re working on it!
To implement a custom component :
- Create a new component in your App choosing “Custom component, using hooks” in the “Component type” dropdown.
- In the “Hook name” text field, write the name of the hook that you will implement in your code. For this example, let’s say “my-component”
- In a plugin of yours (or in the functions.php of your WordPress theme but we wouldn’t recommend that to keep concerns separated) implement the custom component filter : “wpak_custom_component-[your-hook-name]” as follows :
function wpak_my_custom_component( $component_data ) { //... Here you add your data to $component_data ... return $component_data; } add_filter('wpak_custom_component-my-component', 'wpak_my_custom_component');
Where “my-component” is the “Hook name” that you defined at step 2.
Then, on the app side you can retrieve your custom component data and define specific templates to render those custom data, as explained in the following steps.
Custom components creation can be approached in 2 ways :
- The “non-collection” type : components that just define a set of custom data that don’t belong to a collection : for example if you have a WordPress Widget that defines some Front content and you want to use this Widget content in your app.
- The “collection” type : typically a component that will handle a list of items : for example a database of products that you want to display in your app with the same logic as for post lists : archive <=> single. (Here we suppose that those products are not WordPress content but imported from an external database, otherwise we would simply handle it using the native “Post list” component filtered on the right post type).
Let’s say that we have a WordPress Widget “Our favorite restaurant of the month” where we can set the 3 following fields :
- restaurant_name : string
- what_you_will_eat : array of dishes
- where : string : restaurant address
And you want to display this block in your app on the “Food” category archive screen.
Provided you created a custom component with slug “restaurant-widget” and “Hook name” = “favorite-restaurant-widget” :
function wpak_favorite_restaurant_widget( $component_data ) { $data = array( 'restaurant_name' => 'Name retrieved from WP Widget' 'what_you_will_eat' => $array_retrieved_from_wp_Widget 'where' => 'Address retrieved from WP Widget' ); $component_data['favorite_restaurant'] = $data; return $component_data; } add_filter('wpak_custom_component-favorite-restaurant-widget', 'wpak_favorite_restaurant_widget');
Then in your archive.html template you would display the “Our favorite restaurant of the month” block only if the category slug is “food” :
<% if( TemplateTags.isCategory('food') %> <% //Retrieve our component : var restaurant_widget_component = TemplateTags.getComponent('retaurant-widget'); //Here, "restaurant-widget" is the component slug as defined when creating the component, //and NOT the "hook name" (which is "favorite-restaurant-widget"). //Retrieve the widget data, corresponding to the //$component_data['favorite_restaurant'] set earlier on PHP side : var widget_data = restaurant_widget_component.data.favorite_restaurant; //and then display the widget HTML : %> <div class="my-restaurant-widget"> <h2><%= widget_data.restaurant_name %></h2> Menu : <ul> <% _.each( widget_data.what_you_will_eat, function( dish ){ %> <li><%= dish %></li> <% }); %> </ul> <p>Address : <%= widget_data.where %></p> </div> <% } %> And then display your posts list as usual in archive.html : <% if( posts.length ) { %> <ul> <% _.each( posts, function( post ){ %> <li> ... </li> <% }); %> </ul> <% } %>
Now let’s imagine you have a database of products that comes from an external web service and is not available as a WordPress post type.
This collection of products is not related to WordPress native content in any way : products have their own IDs that can conflict with WordPress ones.
But still, you want to display those products in your WP AppKit app and benefit from the automated “archive” <=> “single” navigation and history logic to browse the products in the app.
Custom component allow to do that, provided that you set the right parameters to $component_data in the “wpak_custom_component-[your-hook-name]” filter.
The key $component_data params you’ll have to set are :
- “global-items” : an array of your products. Each product row must contain a column named ‘id’ that is the unique identifier of the product.
- “global-items-ids” : an array of the ids of the products (must correspond to the ‘id’ column that you provided in the “global-items” array).
- “total” : total number of products
- “template” : defines the custom WP AppKit theme template that will be called on app side to render the custom component screen. You have to implement this template in your app theme.
Which gives us, if you created a custom component with “slug” = “hook name” = “products” (yes the component slug and the hook name can be the same) :
function wpak_custom_component_products( $component_data ) { //Products that don't come from WordPress : $products = array( array( 'id' => 1, 'title' => 'My first product', 'price' => '10€' ), array( 'id' => 2, 'title' => 'My second product', 'price' => '20€' ), array( 'id' => 3, 'title' => 'My third product', 'price' => '30€' ), ); $component_data['global-items'] = $products; $component_data['global-items-ids'] = array_column( $products,'id' ); //Note : array_column() requires PHP 5.5. With older PHP versions you would use array_map() : //$component_data['global-items-ids'] = array_map( function( $product ){ return $product['id']; }, $products ); $component_data['total'] = count( $products ); $component_data['template'] = 'products'; //So that the app uses the products.html template to display this component return $component_data; } add_filter('wpak_custom_component-products', 'wpak_custom_component_products');
Then you can create the “products.html” template in your app theme.
In this template, the following variables will be automatically available :
- items : an array of your products (each product is a JSON object)
- component : a JSON object containing all you need to know about the custom component. (component.data contains all the params you set earlier to $component_data).
For example to display the list of our products :
<% if(items.length){ %> <ul> <% _.each( items, function( item ){ %> <li> <h4> <a href="<%= TemplateTags.getPostLink(item.id, component.global) %>" > <%= item.title %> </a> </h4> <p><br/><%= item.price %></p> </li> <% }); %> </ul> <% }else{ %> <p>No product found!</p> <% } %>
Note that the TemplateTags.getPostLink() can be used here to retrieve the link to the product detail (single), but you have to provide the specific component “global” as second parameter : TemplateTags.getPostLink(item.id, component.global).
The last thing to do is to implement the “product single” template that will display the product details : create the products-single.html template (you can name it whatever you want).
In this template you can access the product data via the “item” variable :
<h1><%= item.title %></h1> <p><%= item.price %></p>
And last but not least you have to tell the app that it has to use this “products-single.html” template to render products singles, using the “template” filter in your functions.js :
App.filter( 'template', function( template, current_screen ) { if( TemplateTags.isSingle(0,current_screen,'custom-global-products') ){ // The 3rd argument is "custom-global-[your-component-slug]" template = 'products-single'; } return template; } );
Shortcodes
[hide_from_apps notify='yes|no' container='p|span|div|none']content[/hide_from_apps]
Use this shortcode for content that you want to hide in apps but still display on website front-end.
By default the shortcode content will be removed from post content, in apps only.
You can also use the “notify” attribute to set a placeholder that will be displayed in place of the removed content.
For example the following code:
[hide_from_apps notify="yes"]Hide me in app[/hide_from_apps]
will replace the “Hide me in app” content (on app side only) by the following placeholder:
<div class="wpak-content-not-available"></div>
that you can then style using CSS in your app theme.
This placeholder is fully customizable using the wpak-shortcode-hide-from-apps-placeholder filter :
//In a php file inside theme's php folder: add_filter( 'wpak-shortcode-hide-from-apps-placeholder', 'my_custom_placeholder', 10, 3 ); /** * Define your own placeholder for content hidden in app * @param string $new_content Placeholder content to display in app: customize this. * @param string $content Content originally inside of the shortcode (maybe you'll want * to wrap this in a custom div of yours). * @param array $settings Shortcode settings set by the user (notify: 'yes'/'no') */ function my_custom_placeholder( $new_content, $content, $settings ) { return $new_content; }
When not in app the content of the shortcode will be displayed in a <p> tag by default. You can customize this using the container attribute. For example to use a <span> instead of <p>:
[hide_from_apps container="span"]Hide me in app[/hide_from_apps]
- notify : String : 'yes' or 'no' : (Optional, default 'no') If the notify shortcode attribute is set to 'yes', the shortcode content is replaced by a notification div (see example above)
- container: When not in app, shortcode content is displayed wrapped in a <p> tag by default, but this can be changed to any other html tag using this container attribute. Pass "none" to use no wrapper.
[show_only_in_apps container='p|span|div|none']content[/show_only_in_apps]
Use this shortcode for post content that you want to display in apps but hide from website front-end.
In the following example
[show_only_in_apps]Show me only in app[/show_only_in_apps]
“Show me only in app” will display in apps but be removed from font-end post single display.
When your in the app the content of the shortcode will be displayed in a <p> tag by default. You can customize this using the container attribute. For example to use a <span> instead of <p>:
[show_only_in_apps container="span"]Show me only in app[/show_only_in_apps]
Content Hooks
Filter pages list displayed into a “Page” component select field.
- $pages The default pages list to display
- $current_post_type_object->name The name of the post type being displayed
An array of page objects.
Filter taxonomies list displayed into a “Posts list” component select field.
- $taxonomies The default pages list to display
An array of taxonomy slugs.
Filter data from a custom component, identified thanks to (hook-name).
- $component_default_data An array of default data
- $component The component object
- $options An array of options
- $args An array of complementary arguments
An array of data for the component:
$component_default_data = array( 'query' => array( 'type' => 'custom-component' ), 'total' => 0, 'global' => 'custom-global-' . $component->slug, 'global-items' => array(), 'global-items-ids' => array() );
Filter the number of words included into an excerpt.
- 30 The default value overriden by this plugin
- $default_wp_excerpt_length The default value provided by WordPress
An int containing the number of words to include into an excerpt.
Filter the string showed when a content is troncated to make an excerpt.
- ' ...' The default value overriden by this plugin
- $default_wp_excerpt_more The default value provided by WordPress
A string containing the value to show at the end of an excerpt.
Filter a page content. Use this to format app pages content your own way.
To apply the default App Kit formating to the content and add only minor modifications to it, use the “wpak_post_content_format” filter instead, applied in WpakComponentsUtils::get_formated_content() .
- '' The page content: an empty string by default
- $post The page object
- $component The component object
A string containing the formatted page content.
Filter page data sent to the app from a page component. Use this for example to add a page meta to the default page data.
- $post_data The default page data sent to an app
- $post The page object
- $component The component object
An array of page data.
Filter a single post content.
- $content The post content
- $post The WP_Post object
A string containing the formatted post content. To override (replace) the default WP-AppKit formatting completely, use "wpak_post_content" filter. To handle post lists posts content or page content independently, use "wpak_posts_list_post_content" and "wpak_page_content" filters.
Filter post data sent to the app from a posts list component. Use this for example to add a post meta to the default post data.
Example that adds a post meta to all posts sent trough the web services :
add_filter( 'wpak_post_data', 'add_meta_to_my_app_posts', 10, 3 ); function add_meta_to_my_app_posts ( $post_data, $post, $component ) { //Add our meta to the application post data : $post_data['my_meta'] = get_post_meta( $post->ID, 'my_meta', true); return $post_data; //Return the modified $post_data }
Then, in the single.html or archive.html template, you can display your meta like this :
<p class="my-meta-box" ><%= post.my_meta %></p>
- $post_data The default post data sent to an app
- $post The post object
- $component The component object
An array of post data.
Filter a single post excerpt.
- $post_excerpt The post excerpt
- $post The WP_Post object
A string containing the post excerpt.
Filter data from a posts list component, identified thanks to (hook-name).
- $posts_list_data An array of default data
- $component The component object
- $options An array of options
- $args An array of complementary arguments
- $before_post_date The publication of the last displayed post
An array of data for the component:
$posts_list_data = array( 'posts' => array(), 'total' => 0, 'query' => array( 'type' => 'custom-posts-list', 'taxonomy' => '', 'terms' => array(), 'is_last_page' => true, 'before_item' => 0 ) );
Filter post content into a posts list component. Use this to format app posts content your own way.
To apply the default App Kit formating to the content and add only minor modifications to it, use the “wpak_post_content_format” filter instead, applied in WpakComponentsUtils::get_formated_content() .
- '' The post content: an empty string by default
- $post The post object
- $component The component object
A string containing the formatted post content.
Filter the number of posts displayed into a posts list component.
- Default number of posts
- $component The component object
- $options An array of options
- $args An array of complementary arguments
An integer containing the number of posts to display.
Filter args used for the query made into a posts list component.
You can see a usage example in this gist.
- $query_args An array of default args
- $component The component object
- $options An array of options
- $args An array of complementary arguments
- $query Data about the query to retrieve on the app side
An array of arguments to use for the posts list query.