Build your WP-AppKit app with Cordova

Since October 2020, Adobe has discontinued PhoneGap Build and ended investment in PhoneGap, so PhoneGap Build cannot be used to build WP-AppKit apps anymore. To address this issue, since version 1.6.0 WP-AppKit allows to build apps directly with Cordova tools, or to use the Voltbuilder online service.

Here we will see how to configure Cordova and how to use it to build WP-AppKit Android apps. Cordova first install is not really straight forward and what you are about to read is obviously not exactly a 5 minutes tutorial but the great advantage of building apps with Cordova is that you can do it directly on your local computer without depending on an external online service.

The goal of this tutorial is to build a WP-AppKit app with Cordova, but it can help anyone who wants to build an hybrid app (HTML/CSS/Javascript based) with Cordova as most of the steps described will be the same.

All installation instructions in this tutorial have been tested on linux platform (Ubuntu 18.04). You can find more general information about Cordova installation on the Cordova website : “Get started” and “Android Platform specific configuration“.

Setup Cordova on your local computer

Nodejs and npm

The first requirement to run Cordova is to install nodejs and npm:

sudo apt update
sudo apt install nodejs
sudo apt install npm

Cordova requires that you run last version of nodejs. Some linux distributions (like Ubuntu) install quite old nodejs versions by default. You can check the installed node version by running:

node -v

If the version is inferior to the last LTS version of node (that you can check here, currently v12.19.0 when writing this tutorial), you must update your node version so that Cordova works. The easiest way to do so is to use the “Node Version Manager” nvm:

Install nvm:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.36.0/install.sh | bash

Then update node to lastest LTS version

nvm install --lts

Now run “node -v” again and check that the version correspond to the last current LTS node version (currently v12.19.0).

Android SDK

Before installing Cordova itself, install the Android SDK which is required by Cordova to build Android apps.

To do so, first install the last JAVA JDK (find last version install info here):

sudo apt install openjdk-8-jdk-headless

Here we use the “headless” (lighter) version of the jdk because we don’t need graphical interface, but you can install “opendjk-8-jdk” instead if you need a more general SDK version.

Then install Gradle using SDKMAN!:

Install SDKMAN!:

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

Install Gradle:

sdk install gradle 6.7

Finally install the Android SDK itself: here we use the “Command line tools only” version, which is lighter and sufficient to build WP-AppKit apps as we will only use the Cordova command line tools, not the Android Studio graphical interface.

  • Download “Command line tools only” version of Android SDK here: https://developer.android.com/studio#command-tools
  • Create the following directory on your computer: /home/[your-user]/android-sdk/cmdline-tools/tools/
  • Unzip the downloaded SDK in a temporary folder. Go to this temporary folder and copy what is inside the [temporary folder]/cmdline-tools directory into the /home/[your-user]/android-sdk/cmdline-tools/tools/ directory created above.
  • Check that you now have the exact following path : /home/[your-user]/android-sdk/cmdline-tools/tools/bin/, with sdkmanager binary in it.

Edit your /home/[your-user]/.bash_profile file and add the Android SDK environment variables like so:

# Android 
export ANDROID_HOME=/home/[your-user]/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/tools

then load this config with:

 source "$HOME/.bash_profile"

We can now use the sdkmanager command to install the required Android packages: “Android Platforms SDK” and “Android SDK build-tools”, like so:

sdkmanager "platform-tools" "platforms;android-28"
sdkmanager "build-tools;30.0.0" 

You can choose Android API-Levels (here we use 28) here and Build tools versions here (here we use 30.0.0).

And this is it, the Android SDK is installed and configured, we can now install Cordova.

Install Cordova

Run the following to finally install Cordova:

sudo npm install -g cordova

If you’re still there, well done, you’ve done the hardest part! Now let’s use Cordova to build apps!

Build Apps

Cordova test app

Before trying to build a WP-AppKit app, try to build the default Cordova test app to see if Cordova is installed correctly.

Create a new directory where you will create your Cordova projects. Here we will call it [my-cordova-projects-dir].

cd [my-cordova-projects-dir]
cordova create MyTestApp

(If you encounter a parsing error at this point, it is probably because you need to update your nodejs version: see first step of this tutorial to do so).

cd MyTestApp
cordova platform add android
cordova build

The first build can be a bit long as new libs are downloaded and installed but if everything went well, that’s so cool, you just built your first Android app on your own computer 🙂

You can find the app’s .apk in the directory that’s indicated at the end of the Cordova build log, send it to your phone and install it. This should run the default Cordova “Hello World” app.

Now let’s see how to build WP-AppKit apps.

Build a WP-AppKit app with Cordova

Export your app as a “Cordova template”

On WordPress side, in your WP-AppKit app edition panel, choose the platform “Android – Native – Cordova export”, and configure your app theme and app components as for any WP-AppKit app (see Getting Started).

Cordova specific config must be set up in the “Cordova” box (App name, App ID, etc), as detailed in our “Getting Stated – Build native app” section.

Then click the “Cordova app template – Export” button:Export WP-AppKit app as Cordova template

This exports the WP-AppKit app sources as a Cordova app template. Cordova app templates are pre-built Cordova projects that you can use to jumpstart another Cordova project.

We are now going to use this Cordova template (zip file “cordova-template-export-[app-slug]-[app-version].zip“) that you just downloaded to create and build our WP-AppKit app’s Cordova project.

 Create Cordova project from WP-AppKit Cordova app template

Let’s say that you downloaded the WP-AppKit app Cordova template zip file in the directory [my-downloads]: [my-downloads]/cordova-template-export-[app-slug]-[app-version].zip.

Unzip the Cordova template zip file, with your favorite zip archive manager or with command line (here we unzip into a directory [my-downloads]/template-[app-slug]-[app-version]):

cd [my-downloads]
unzip cordova-template-export-[app-slug]-[app-version].zip -d template-[app-slug]-[app-version]

Then go to the directory where you want to create your WP-AppKit app Cordova project (here we will use the same directory as in the previous section: [my-cordova-projects-dir]) and create the Cordova project that correspond to the WP-AppKit app Cordova template:

cd [my-cordova-projects-dir]
cordova create [app-slug]-[app-version] --template [my-downloads]/template-[app-slug]-[app-version]

This creates the directory [app-slug]-[app-version] containing our WP-AppKit app Cordova project.

Build Cordova app

Go to the newly created Cordova project directory [app-slug]-[app-version] and add Android platform. This will parse the config.xml and import the  Cordova plugins required by the WP-AppKit app:

cd [app-slug]-[app-version]
cordova platform add android

At his point if you see some (yellow) warnings in logs, run the following until you don’t have any more warnings:

rm -rfd platforms && rm -rfd plugins && rm package*
cordova platform add android

Then build your app with:

cordova clean && cordova build

Get the resulting .apk from the last line of logs, send it to your phone (via email or your preferred online file storage service for example), install it and enjoy your fully manually built app!

Build your WP-AppKit app with VoltBuilder

Since October 2020, Adobe has discontinued PhoneGap Build and ended investment in PhoneGap, so PhoneGap Build cannot be used to build WP-AppKit apps anymore. To address this issue, since version 1.6.0 WP-AppKit allows to build apps directly with Cordova tools, or to use the Voltbuilder online service.

Here we will see how to build your WP-AppKit app with VoltBuilder.

Configure your WP-AppKit app

On WordPress side, in your WP-AppKit app edition panel, select the “Android – Native – VoltBuilder” platform, and configure your app theme and app components as for any WP-AppKit app (see Getting Started).

Then setup VoltBuilder config in the “VoltBuilder” box (App name, App ID, etc), as detailed in our “Getting Stated – Build native app” section.

Then click the “VoltBuilder – Export” button:

Dowload the exported zip file on your computer.

Build with VoltBuilder

Connect to VoltBuilder, go to “Upload” section and directly upload the previously download zip export:

VoltBuilder then builds the app and, when finished, gives you a QR code that you can scan to install your app.

Enjoy building your WP-AppKit apps with VoltBuilder!

WP-AppKit now supports Cordova and VoltBuilder exports

Following PhoneGap announcement about stopping PhoneGap development and discontinuing PhoneGap Build service on October 2020, we released a new version of WP-AppKit (1.6.0) that allows to export your app in 2 new formats:

  • export app in Cordova template format so that it can be built with raw Cordova tools on your local computer. See how to build your app with Cordova in this tutorial.
  • export app in VoltBuilder format so that it can be built with VoltBuilder online service. See how to build your app with VoltBuilder in this tutorial.

All 3 WP-AppKit addons have also new versions released to make them compatible with the new Cordova and Voltbuilder exports. To update your addons, connect to your account and go to “Purchase History” > “View Details and Downloads”, or if you’re using addons’ github repositories, simply download or pull last version of addons’ master branches.

 

PhoneGap discontinued on October 1, 2020

PhoneGap has announced that they will stop PhoneGap development and discontinue the PhoneGap Build service on October 1, 2020.

We are currently reviewing existing alternatives to PhoneGap Build so that WP-AppKit users can build their native Android Apps with other services.
A WP-AppKit update will be made in the coming weeks so that WP-AppKit apps can be exported in other formats than only PhoneGap Build format. One of the new WP-AppKit exports will be the native Cordova tools, so that apps can be built manually without any external service.

Progressive Web Apps are not impacted and you can still build PWAs with WP-AppKit as usual.

Send push notifications to WordPress users

In this tutorial we will see how to send OneSignal push notifications to WP-AppKit apps (and PWAs) targeting specific, chosen, WordPress users.

Here’s the idea:

  • The user subscribes to OneSignal notifications in the app,
  • Then, still in the app, the user logs in with his WordPress login (using native WP-AppKit login feature). When he/she does, we send his/her WordPress ID to OneSignal, which allows to map the WordPress user to the corresponding OneSignal user.
  • From WordPress Back Office we select some users and send push notifications only to the apps of those chosen users.

What we will do technically:

  • Use WP-AppKit OneSignal addon to handle push notifications in the app,
  • Use WP-AppKit login feature so that WordPress users can log into the app,
  • See how to map WordPress users to OneSignal users,
  • Finally send push notifications from WordPress Back Office to chosen WordPress users’ devices only.

OneSignal configuration

You can download WP-AppKit OneSignal addon here on our website or directly on github.

You will find all OneSignal installation and configuration instructions on both OneSignal and WordPress sides here.

In a nutshell:

  • Install the addon like any other WordPress plugin and activate it. Then, in your WP-AppKit app edition panel, activate the addon for the app.

  • On OneSignal side, create a new app and get its “App ID”.

  • Copy this OneSignal App ID into WP-AppKit app config. Don’t forget to re-save your app.

Once OneSignal is configured for your app, you can export/install it and run a first test to check that OneSignal subscription from the app works well and that your app receives push notifications that you send from OneSignal interface.

In OneSignal you can also check that your subscription tests appear in “Audiences” > “All users”. Those OneSignal users are not mapped to WordPress users yet, they only have a “Player ID” that is not related to WordPress user IDs. That’s what we are going to work on now.

Allow WordPress users to log into your app

You can find all instructions about how to setup WordPress login in a WP-AppKit app in the corresponding documentation.

Here are the main steps to follow:

  • Create a RSA private key that you copy to your WP-AppKit app “Authentication Settings” section to create a secure communication between your app and WordPress:

Once user authentication is configured for your app (private key and authentication demo theme installed), you can test it by trying to log in in the app (you will see a login form at the top of the app) with your WordPress login/password.

Map WordPress users to OneSignal users

This is where we really start to implement new features that are not in WP-AppKit by default 🙂

The goal of this tutorial is to be able to send push notifications to specific WordPress users. So the first thing we need to add is a way to map WordPress user IDs to OneSignal “player IDs”. Fortunately OneSignal provides a user field that is designed for this kind of mapping: external_user_id.

So what we need to do is send the WordPress user ID of the user logged in in the app to OneSignal as an external_user_id.

Here’s how to implement this:

  • First, we have to add the WordPress user ID to the user information that is sent from WordPress to the app (by default WP-AppKit only send user login to the app, not user ID). To do so, create a wordpress-user-id.php file in wp-content/themes-wp-appkit/[your-app-theme]/php with the following code in it:
<?php

//Add WordPress user ID to the authentication user info sent to the app
//when a user logs in:
add_filter('wpak_auth_user_info', function($user_info, $user_id, $app_id) {
        $user_info['id'] = $user_id; //This allows to retrieve "current_user.info.id" on app side
        return $user_info;
}, 10, 3);

Note: If this is the first time that you add a PHP file into a WP-AppKit theme, you may wonder what is happening: WP-AppKit apps are Javascript based webapps, why are we including a PHP file in it? The answer is that WP-AppKit themes can add server side customization to modify what is returned by WP-AppKit content or authentication web services. Any PHP file found in [your-wp-appkit-theme]/php folder will be included in WP-AppKit webservice context (but not in the exported app sources, which is pure Javascript). That’s what we use here to add our user ID info to the default authentication webservice answer. You can find other useful information about this php folder in this article.

  • Create a Javascript file named onesignal-external-user-id.js in wp-content/themes-wp-appkit/[your-app-theme]/js and put the following code in it:
define([
        'core/theme-app',
        'core/modules/authentication',
        ], function(App,Auth) {

        //When WordPress user logs in, set OneSignal's external user ID:
        App.on( 'info:auth:user-login', function( info ) {
                var current_user = Auth.getCurrentUser();
                OneSignal.setExternalUserId(current_user.info.id);
        } );

        //When WordPress user logs out, unset external user id
        App.on( 'info:auth:user-logout', function( info ) {
                OneSignal.removeExternalUserId();
        } );
} );
  • Require this new “onesignal-external-user-id” Javascript module in the js/functions.js file of your theme (which is the main entry point for any custom Javascript added to a WP-AppKit app) by adding “theme/js/onesignal-external-user-id” as a dependency:
//In [your-wp-appkit-theme]/js/functions.js
define([
     'theme/authentication/js/top-login-form',
     'theme/authentication/js/premium-posts',
     'theme/authentication/js/pages',
     'theme/js/jquery.fitvids',
     'theme/js/onesignal-external-user-id'
     ], function($,App,Storage,TemplateTags,Config,Moment,Velocity) {

Now if you save and re-export/install your app, then log a WordPress user in on app side, you can check in OneSignal (Audience > All users) that your WordPress user ID is set as external ID:

Now if you log your user out in the app, you should see that the external user ID on OneSignal side is removed.

And that’s it concerning mapping WordPress users with OneSignal users. Now it is possible to send push notifications on a “per WordPress user” basis, by sending OneSignal notifications filtered by “external user IDs”. Let’s see how to do this.

Send push notifications to selected WordPress users

You can find here a micro WordPress plugin “OneSignal push to WP users” that was made for this tutorial and that implements:

  • a WordPress admin page where you can select WordPress users and send a notification only to those selected users
  • a basic example of how to create and send OneSignal notifications from WordPress using the OneSignal API along with the external_user_id targeting.

You will find explanations about how to setup this plugin in its readme file.

Here are the key concepts implemented:

  • Create an admin page under tools menu that displays a form listing all the WordPress users with a checkbox to select them.
  • When the form is submitted we send a notification that only the selected users will receive, if they are logged in in their app.
  • The notification is sent by calling the OneSignal API’s notifications endpoint (https://onesignal.com/api/v1/notifications) and providing our selected WordPress user IDs in the “include_external_user_ids” request field.

Once you’ve followed indications from the plugin’s readme file and configured it with your own OneSignal App Id and Auth key (which you can find in OneSignal under Settings > Keys & Ids), you can go to the “Tools > OneSignal push to WP Users” WordPress admin page and finally test sending notifications to the selected users that are currently logged in in the instances of your WP-AppKit app!

We hope that this tutorial will help you build cool notification based applications linked to WordPress. Don’t hesitate to post your questions or feedback in the comments!

Handle internal links

Let’s say that you have an internal link in one of your post content:

<a href="#my-internal-element">Go to internal element</a>

That points to the div with id=”my-internal-element”:

<div id="my-internal-element">Here's the internal element we want to go to</div>

The thing is that internal links (beginning with “#”, also called “fragments) are considered internal routes by BackboneJs app engine, so this will result in triggering an app route that does not exist (which leads to going back to app home screen) instead of going to the “Internal element”.

To solve that, here’s what can be done:

First, add the “q-theme-prevent-navigation” class to the link to prevent the app engine from handling it as a navigation link:

<a href="#my-internal-element" class="q-theme-prevent-navigation">Go to internal element</a>

Then add the following code to your [app-theme]/js/functions.js file (or in a custom js module of your own included in your theme):

$("#app-layout").on("click", ".q-theme-prevent-navigation", function(e){
    var href = $(e.target).attr('href');
    if ( href.charAt(0) == '#' ) { //Link's href is a fragment
        var $anchor_target = $(href); //Get link's target element
        if ( $anchor_target.length ) { //Scroll to target element if exists
            var $app_screen = $(e.target).closest(".app-screen");
            $app_screen.animate({
                scrollTop: $anchor_target.position().top
            }, 500);
        }
    }
});

This makes the app screen scrolling to your target internal element when clicking on an internal link.

Favorites for WP-AppKit: New Toy in Town

What if you wanted to let users bookmark posts they want to read later? What if they could read these bookmarked articles even when they’re offline? That’s exactly what our new add-on Favorites for WP-AppKit is done for.

As soon as you activate Favorites for WP-AppKit, it will add the possibility:

  • to bookmark a post from post list

  • to bookmark a post from post detail

  • to access the list of bookmaked posts from the Favorites special screen

Of course users will be able to unbookmark posts and even empty the whole bookmark list. Even more powerful, bookmarked posts are available offline.

In the latest release of WP-AppKit (version 1.5.3), the Q for Android theme is already compatible with the Favorites for WP-AppKit add-on. (This is where screen captures come from.) You will be able to add the favorites feature to your apps thanks to the add-on’s API, fully documented here.

The Favorites add-on for WP-AppKit is available here

 

Add a contact form to your App

In this tutorial we’ll see how to add forms to your app. Here we’ll implement a contact form but any other custom form sending data from the app to the server can be implemented following the same steps.

There are many form plugins for WordPress out there but unfortunately we did not find one yet that is designed to send forms from somewhere else than the website itself. If some of you know a WordPress form plugin that would allow to submit its forms from an external Javascript based web application, don’t hesitate to share it in the comments!

So for now we have to implement the app form feature “by hand” in the app. To do so, here are the main steps that we will follow in this tutorial:

  • create a custom app screen where we will display the contact form
  • handle the form submission in Javascript
  • retrieve sent form data on server side and process it (send an email to site admin)

This tutorial is based on Q for Android WP-AppKit default theme. A working example including all the code used here can be found here on github. More specifically, the files used in this tutorial are: : contact.html, forms.css, forms.js, forms.php, funtions.js, menu.html.

Create a custom app screen for our contact form

Note: the contact form screen that we are going to create here is specific to the app. It is not related to a WordPress post or page. You don’t have to add any component to your app to make it work, everything happens directly in your app theme (wp-content/themes-wp-appkit/[your-app-theme]).

Form template

First let’s add a new “contact.html” template to the app theme, where we define the HTML for the contact form:

<!--
    (in [your-app-theme]/contact.html)
    Contact Form screen template
-->

<div id="content" class="content single-template">

    <div class="post-title">
        <h1>
            Contact
        </h1>
    </div>

    <div id="single-content" class="single-content">

        <!--
            Contact form
            The id must be the same as the one defined in js/forms.js
            The class must be "app-form" so that the form can be handled by js/forms.js
        -->
        <form id="contact" class="app-form">

            <label for="firstname">First name</label>
            <input name="firstname" id="firstname">

            <label for="lastname">Last name</label>
            <input name="lastname" id="lastname">

            <label for="email">Email</label>
            <input name="email" id="email" type="email">

            <label for="message">Message</label>
            <textarea name="message" id="message"></textarea>

            <input type="submit" value="Send">

            <div class="feedback"></div> <!-- Where we will display form submission results -->

        </form>

	</div>

</div>

This contact form has firstname, lastname, email and message fields. Of course you can remove or add fields according to your needs. If you do so, simply don’t forget to reflect those changes in the forms Javascript variable that we will define in js/forms.js later in this tutorial.

Note the id (contact) and the class (app-form) attributes of the form element. They must be named this way to be recognized in the Javascript processing that’s coming later.

Some styles for the form

While we’re at it, add some CSS so that the form displays properly. Create a css/forms.css file with the following rules:

/**
 * (in [your-app-theme]/css/forms.css)
 * Styles for contact form
 */

.app-form input {
    display: block;
    width: 100%;
    margin-bottom:1em;
    padding:5px;
}
.app-form textarea {
    display: block;
    width: 100%;
    height: 6em;
    margin-bottom:1em;
    padding:5px;
}
.app-form .feedback {
    display: none;
    border-left: 4px solid #fff;
    padding: 3px 12px;
}
.app-form .feedback.success {
    border-left-color: #46b450; //green
}
.app-form .feedback.error {
    border-left-color: #dc3232; //red
}

And reference this new stylesheet forms.css in the head.html template:

<!-- head.html template -->
<meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1">
<link rel="stylesheet" href="<%= TemplateTags.getThemeAssetUrl('css/common.css') %>">
<link rel="stylesheet" href="<%= TemplateTags.getThemeAssetUrl('css/post-list.css') %>">
<link rel="stylesheet" href="<%= TemplateTags.getThemeAssetUrl('css/post-detail.css') %>">
<link rel="stylesheet" href="<%= TemplateTags.getThemeAssetUrl('css/forms.css') %>">

Add this new contact screen to the App

Create a js/forms.js file where we will handle the Javascript logic four our forms.

First, tell the App that we have a new “contact” screen:

/**
 * (in [your-app-theme]/js/forms.js)
 * Add forms to App engine
 */
define([
    'jquery',
    'core/theme-app',
    ], function($,App) {

    //Create a custom app screen called "contact" associated to template "contact.html", where the contact form is implemented.
    //We also add a link to this contact screen in app menu (see menu.html template).
    App.addCustomRoute( 'contact', 'contact' );

});

Then plug this new Javascript file into the App engine by requiring it in js/functions.js (see highlighted line):

/* [your-app-theme]/js/functions.js */
define([
    'jquery',
    'core/theme-app',
    'core/modules/storage',
    'core/theme-tpl-tags',
    'root/config',
    'theme/js/moment.min',
    'theme/js/velocity.min',
    'theme/js/jquery.fitvids',
    'theme/js/forms'
    ], function($,App,Storage,TemplateTags,Config,Moment,Velocity) {

And finally add our new contact screen to the App’s menu so that we can access it easily: add the following highlighted line to the menu.html template:

<ul id="menu-items" class="menu-items" style="display:none;">

    <% if(menu_items.length){ %>

        <% _.each( menu_items, function( menu_item ){ %>

            <li class="has-ripple-feedback"><a href="<%= menu_item.link %>"><%= menu_item.label %></a></li>

        <% }) %>

        <li class="has-ripple-feedback"><a href="#contact">Contact</a></li>

    <% } %>

</ul>

Test it!

If everything went well, if you preview your app now you should see a “Contact” entry in your app menu and when clicking on it, your contact form should display.

Of course the form itself is not working yet, let’s bring it to life now!

Handle form submission

Now we’ll see how to submit our form data to the server.

App side (Javascript)

In the previously created js/forms.js file, add the definition of the app forms:

/**
 * In [your-app-theme]/js/forms.js, after App.addCustomRoute(...)
/*

    //Define forms that will be used in the app, along with their corresponding field names.
    //Forms (HTML) must also be defined in app templates with class="app-form",
    //and are handled on server side in php/forms.php.
    var forms = {
        contact: { //Form id
            fields: [
                'firstname', //Field name
                'lastname',
                'email',
                'message',
            ],
            messages: {
                submitting: "Sending message...",
                success: "Message sent successfully! Thank you for contacting us.",
                error: "An error occurred"
            }
        }
    };

If you removed or added other fields in your HTML form (in contact.html template), don’t forget to adjust the fields part.

Here we only have a contact form (the contact entry in the forms Json Object) but any other forms could be added here. The form field names defined here (firstname, lastname, etc) must correspond to the ones defined in the contact.html template. Feel free to customize your contact form’s messages.

Then we add the form submission Javascript logic: get the form data and send it to the server. You should not have to modify those lines, this is an automated logic based on the forms variable defined above. Still in js/forms.js, add:

/**
 * (in [your-app-theme/js/forms.js], after the forms variable definition
 */
   
    //Handle app forms submission
    $('#app-layout').on('submit','.app-form', function(e) {

        e.preventDefault();

        var form_id = $(this).attr('id');

        if( forms.hasOwnProperty(form_id) ) {
            var form = forms[form_id];

            //Retrieve form data
            var form_data = {};
            $.each(form.fields, function(index, field_name){
                form_data[field_name] = $('[name='+ field_name +']').val();
            });

            //Get feeback wrapper:
            var $feedback = $('.feedback', this);
            $feedback.text('').removeClass('success error').hide();

            //Get submit button and set the "submitting" message:
            var $submitButton = $('input[type=submit]', this);
            var original_submit_button_message = $submitButton.val().length ? $submitButton.val() : 'Submit';
            $submitButton.val(form.messages.submitting).prop('disabled', true);

            //Configure WP-AppKit liveQuery web service to submit the form to the server:

            //Define our custom query that we will handle on server side using the 'wpak_live_query' hook in php/forms.php
            var query_args = {
                form_action: 'submit',
                form_id: form_id,
                form_data: form_data
            };

            //Define query options:
            var options = {
                success: function( answer ) { //The liveQuery webservice call went ok

                    if ( answer.form_result.ok === 1 ) {
                        //Form submitted ok.
                        //Display some success feedback to the user.
                        $feedback.text(form.messages.success).addClass('success').show();
                        //Remove submit button so that we don't submit again
                        $submitButton.remove();
                    } else {
                        //An error occurred.
                        //Display an error feedback to the user.
                        $feedback.text(form.messages.error +': '+ answer.form_result.error).addClass('error').show();
                        $submitButton.val(original_submit_button_message);
                        $submitButton.prop('disabled', false);
                    }

                },
                error: function( error ) {

                    //This is if the liveQuery web service ajax call failed (no network)
                    //Display an error feedback to the user.

                    $feedback.text(form.messages.error +': network error.').addClass('error').show();

                    $submitButton.val(original_submit_button_message);
                    $submitButton.prop('disabled', false);

                },
                auto_interpret_result: false, //This is to tell WP-AppKit that we're doing our own custom query
            };

            //Finally submit our form data to the server using liveQuery webservice:
            App.liveQuery( query_args, options );
        }
    });

Server side (PHP)

Finally let’s retrieve on server side the data sent from the app, and send an email to the site admin, containing data from the form.

Create a php/forms.php file in your app theme and put the following code in it (of course if you added or removed form fields in your contact.html template, don’t forget to reflect the changes here too):

<?php
/**
 * (in [your-app-theme]/php/forms.php)
 *
 * Handle form submission on PHP side.
 * App form submission is made using the WP-AppKit "liveQuery" webservice.
 * Here we handle this webservice call, check which form was sent, sanitize posted data,
 * then send an email to the website admin.
 */

//Hook into liveQuery webservice to handle form submit
add_filter( 'wpak_live_query', 'wpak_handle_forms_submit', 10, 2 );
function wpak_handle_forms_submit( $service_answer, $query_params ) {
    //$query_params contains what was passed in liveQuery's "query_args"

    //Check that the 'form_action' action (set on app side) is 'submit':
    if ( isset( $query_params['form_action'] ) && $query_params['form_action'] === 'submit' ) {

        //Prepare our answer:
        $result = array( 'ok' => 0, 'error' => '' );

        //Check passed form data:
        if ( !empty( $query_params['form_id'] ) && !empty( $query_params['form_data'] ) ) {

            $form_data = $query_params['form_data'];
            $form_id = $query_params['form_id'];

            //This handles the form with id "contact" as defined on app side.
            //Any other form submission can be handled here by adding an "if" case following this one.
            if ( $form_id === 'contact' ) {

                //Sanitize inputs
                $firstname = sanitize_text_field( $form_data['firstname'] );
                $lastname = sanitize_text_field( $form_data['lastname'] );
                $email = sanitize_text_field( $form_data['email'] ); //email is validated hereunder
                $message = sanitize_textarea_field( $form_data['message'] );
                //For more sanitize functions see:
                //https://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data

                //Check sent data
                //Check not empty:
                if ( empty( $firstname ) || empty( $lastname ) || empty( $email ) || empty( $message ) ) {
                    $result['error'] = 'Please provide all fields';
                    $service_answer['form_result'] = $result;
                    return $service_answer;
                }
                //Check email validity:
                if ( !filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
                    $result['error'] = 'Please provide a valid email';
                    $service_answer['form_result'] = $result;
                    return $service_answer;
                }

                //Data check went ok. Now send email to website admin with contact form data:
                $mail_to = get_bloginfo( 'admin_email' );
                $subject = "Contact form submission from app ". wpak_get_current_app_slug();
                $body = "First name: ". $firstname ."\n".
                        "Last name:  ". $lastname ."\n".
                        "Email: ". $email ."\n\n".
                        "Message: \n". $message ."\n";

                wp_mail( $mail_to, $subject, $body );

                //If you need to do other treatments (save form data in database, etc)
                //you can do it here.

                //Tell the app that everything went ok
                $result['ok'] = 1;

            } else {

                $result['error'] = 'Form ['. $form_id .'] not found';

            }

            $form_data = $query_params['form_data'];

        } else {

            $result['error'] = 'Wrong form';

        }

        //Add our result to the web service answer:
        $service_answer['form_result'] = $result;
    }

    return $service_answer;
    //This webservice answer is then handled on app side in the "success" callback in forms.js
}

Here we simply send an email to the site admin including the data submitted from the form, but feel free to add any other PHP treatment that you would see fit when the form is submitted following (or in place of) the wp_mail() function.

And that’s it, you should now be able to submit your contact form in the app and see that you receive and email on the site admin’s mailbox when you do so 🙂

Again, all the code of this tutorial can be found directly here on github: contact.html, forms.css, forms.js, forms.php, funtions.js, menu.html.

You can now go create cool forms in your apps, and don’t hesitate to post any feedbacks in the comments!

Add a Cordova plugin to your app

To add a Cordova plugin to your app, add the plugin in the PhoneGap > Plugins box. For example:

<plugin name="cordova-plugin-google-analytics" spec="1.8.3" source="npm"/>
<plugin name="cordova-build-architecture" spec="https://github.com/MBuchalik/cordova-build-architecture.git#v1.0.1" source="git"/>

Add Cordova plugin

Then you can use the plugin’s functions (in this example the cordova-plugin-google-analytics plugin’s object is available as window.ga) in your theme’s functions.js file :

//In functions.js or in a JS module included in functions.js:
window.ga.trackEvent( category, action, label, value );

Then save, export and build the app.

Dropping iOS Support 😱

Supporting iOS has always been a challenge for an open source project such as WP-AppKit. For several months, we have discussed this issue among the team as difficulties have increased. This article explains why we came to the conclusion that coming versions of WP-AppKit won’t support iOS hybrids apps anymore.

Cost Constraint

First, supporting iOS requires specific hardware and software. Apple’s devices costs are skyrocketing (remember we have to use laptops, ipads and iphones). At the beginning of the project, we acquired needed devices but this year, it became obvious that we had to replace them. It was also obvious that the required budget is out of range.

Time Constraint

Another thing to consider is the time devoted to work on iOS as sometimes just compiling and testing an iOS app is ridiculously complicated. We are not the only ones to feel that building hybrid apps for iOS is a pain in the ass. Freetime to work on WP-AppKit is precious and we’d like to use it as purposefully as possible.

PWA Support

At the end of 2017, we invested a lot in PWA. PWA aim to create an app like user experience using web technologies. This is something which is deeply in the core of WP-AppKit’s mission. PWA are well supported on Android and now expand on Mobile Firefox, Desktop Chrome and Edge. Reading the list of platforms supporting this technology, you can see that Apple is missing. This is not enterily true, iOS Safari offers some support for PWA but it is lagging behind other vendors.

Dropping iOS Support 😱

We are fully aware that iOS is a huge part of the mobile world but we came to the conclusion that our project can’t fit Apple’s schemes anymore. It is a difficult and scary decision, believe me. We also make the choice of web technologies as we did before since the beginning of the project. WP-AppKit has always been about strong choices and we understand that decision may anger some of our users.

What does that mean exactly?

It means that we won’t test anymore on latest iOS devices and we will deprecate the iOS platform in future versions of WP-AppKit.

If you have any questions or remarks about this new direction for WP-AppKit, please share in the comments. (However be aware, we won’t publish or respond agressive comments.)

 

Having questions?

FAQ | Tutorials | Documentation

Or

Contact Us