sviluppiamo comunicazione con weLaika Advertising

Single page application with AngularJs and WordPress

Tags: WordPress, AngularJS
Alessandra Cannata' -
Alessandracannata

When we work with WordPress we aim for a fluid frontend, something that responds and looks well. That’s why for our projects we exploited the synergy between WordPress and AngularJs; and result was really good.

Note

In this example we used Angular 1.x because the project was realized before Angular 2 release.

WordLess

We develop WordPress sites using WordLess, an open source tool we’ve created to make WordPress themes’ code more readble and maintanable.

So consider our theme’s folder (wp-content/themes/theme_name) tree something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
├── assets
│   ├── fonts
│   ├── images
│   │   └── icons
│   ├── javascripts
│   └── stylesheets
├── config
│   ├── initializers
│   └── locales
├── theme
│   ├── assets
│   │   ├── javascripts
│   │   └── stylesheets
│   ├── helpers
│   │   ├── components
│   │   └── repl
│   └── views
│       ├── components
│       ├── inline_svg
│       ├── layouts
│       └── posts
└── tmp

Setting up AngularJS

First of all you will have to download a copy of AngularJS inside assets/javascript folder. You can easily find it at the official website.

To include it, you have to modify the default_hooks.php file situated in the config/initializers folder (or the functions.php file if you are not using WordLess), so that you can register and enqueue the script in WordPress.

1
2
3
4
5
6
7
8
function enqueue_javascripts() {
    [...]
    wp_register_script("angular.min", javascript_url("angular.min"), '', false, true);
    wp_enqueue_script("angular.min");
    [...]
}

add_action('wp_enqueue_scripts', 'enqueue_javascripts');

Start Coding

Once you have done, you have successfully included Angular in your WordPress site.

Now you can start writing Controllers and Directives in your javascripts folder, and use them in your theme.

To better analyze it, I wrote a very basic example. In this example we just have a post_type players and some posts of this type, each one composed of title and id: the name of the player and his jersey number.

The focus is on how to communicate from Angular frontend to WordPress backend in order to retrieve data from the database.

Make an Api

To get data from the backend and make it collectable for Angular we have to create a custom API. In my example I have a simple php function that retrieve all the informations. I placed the function in a php file I created under the folder theme/helpers:

1
2
3
4
5
6
7
├── assets
├── config
├── theme
    ├── assets
    ├── helpers
    |   ├── json_create.php
    ├── views

The content of the file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

function json_create(){
    $json = array();
    $json = players_for($json);
    return json_encode($json);
}

function players_for() {
    $results = array();

    $args = array('posts_per_page' => -1, 'post_type' => 'player');
    $players = get_posts($args);

    if ($players) {
        foreach ($players as $player) {
            $results[] = array(
                'jersey_number' => $player->ID,
                'name' => $player->post_title
            );
        }
    }

return $results;
}

api folder and visualization of data

In the theme/views folder we have a serie of subfolders, for example:

1
2
3
4
5
6
7
8
9
├── assets
├── config
├── theme
    ├── assets
    ├── helpers
    ├── views
        ├── layouts
        ├── pages
        ├── posts

Add a subfolder named api, and place an html template in it. In this template, we simply call the function json_create() we mentioned above. theme/views/api/v1.html.haml:

1
  =json_create()

to use it via API, we have to register a route. In WordLess is a very simple operation: just modify index.php in the wp-content/themes/theme_name folder and use the render_view() helper, as described in the documentation.

1
2
3
4
5
6
<?php

...
if (is_page('api')) {
  render_view("api/v1", "api");
}

Now in http://localhost:8080/api/ you should have the data retrieved from the backend, in the form you gave it in json_create() (in this case, an array of objects):

[{“jerseynumber”:18,“name”:“Bobby”},{“jerseynumber”:17,“name”:“Igua”},{“jerseynumber”:10,“name”:“Maxi”},{“jerseynumber”:16,“name”:“Pobba”},{“jerseynumber”:14,“name”:“Romeo”},{“jerseynumber”:15,“name”:“Valla”}]

API and AngularJs

To retrieve data from the API we use an Angular service to make an http request. So in my example there I created a file called angular-app.js.coffee containing a module called myApp and a service getInfos which will be called from the controller MainController.

The file lies under the folder theme/assets/javascripts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
angular
  .module('myApp', [])
  .service 'getInfos', [ '$http', ($http) ->
    ->
      $http
        method: 'GET'
        url: 'api/'
  ]
  // [...]
  .controller 'MainController', ['$scope', '$log', 'getInfos', ($scope, $log, getInfos) ->
    $scope.data = {}

    // [...]

    init = ->
      getInfos()
        .then (response)->
          $scope.data = response.data
          $log.log response
        .catch (error)->
          $log.log error

    init()
    return
  ]

The response object, obtained after calling the getInfos() service, has many properties. The one that we consider is the data property, which is the body of the response, and contains the data we seek. All the data contained in response.data is saved in the scope of our Angular application, to be manipulated.

Also this file, angular-app.js.coffee, needs to be registered and enqueued.

Now We Are Ready!

Ok, we have everything we need, so it is time to use it! We can use the module and the controller we just created in a view, for example single_page.html.haml in the folder theme/views/pages:

1
2
.wrap(ng-app="myApp")
%div(ng-controller="MainController as MainCtrl")

and then play with the data collected:

1
2
    .square(ng-repeat="player in data" ng-click="playerSelect(player.name, player.jersey_number)" ng-class="isPlayerSelected(player.jersey_number)")
      %p= "{{player.name}} {{player.jersey_number}}"