Dynamic Title and Description with AngularJS and WordPress

Table of Contents:

  1. Introduction
  2. Meta Service
  3. Set Title and Description
  4. Bind to Our View
  5. Summary
  6. Other Posts in this Series

Introduction

When you serve your application that we’ve been making over the past 6 instalments, you’ll notice that the title and meta description tags are empty. We could set them to a static default, but they’d be the same on every page. This wouldn’t be terribly useful to your visitors, nor would it help when it came to SEO (search engine optimization) and how we appear on the SERP’s (search engine results page) would be less than desirable.

In part 7 of this series we will make a meta service that will set the title and meta description tags dynamically, determined by the title and content of the page that is currently being served.

The Meta Service

We’ll start by making a setter-getter service that will be available anywhere in our application, making it easy to set our title and description within one scope, and get it in another. This will be the case when we fetch data in our page controllers, but want to use that data in the head on our index.html

  1. In the terminal, use the command:
    yo angular:factory metaService
    

    This will create an angular factory at app/scripts/services/metaservice.js.

  2. Open the app/scripts/services/metaservice.js and replace the boilerplate filler inside of the factory callback with some variable expressions to start.

    .factory('metaService', function () {
         var title = 'My awesome app',
            description = 'Apps are awesome, but this one is the awesomest.',
            service = {
                title: getTitle,
                setTitle: setTitle,
                description: getDescription,
                setDescription: setDescription
            };
    
    return service;
    ...
    

    This sets us up with default values for title and description and defines our service dictionary with the methods that will be available to metaService. Finally, we return service.

  3. Next we want to declare our functions that get used in our service dictionary. Both the setters and getters are really straight forward. The getters return the title or description variables while the setters mutate their value with a passed in argument.

    ...
    return service;
    
    //=> NEW CODE
    function getTitle() {
        return title;
    }
    function setTitle(newTitle) {
        title = newTitle;
    }
    function getDescription() {
        return description;
    }
    function setDescription(newDescription) {
        description = newDescription;
    }
    
  4. The whole factory should look like this:
    'use strict';
    
    /**
     * @ngdoc service
     * @name myappApp.metaService
     * @description
     * # metaService
     * Factory in the myappApp.
     */
    angular.module('myappApp')
    .factory('metaService', function () {
        var title = 'My awesome app',
            description = 'Apps are awesome.',
            service = {
                title: getTitle,
                setTitle: setTitle,
                description: getDescription,
                setDescription: setDescription
            };
    
            return service;
    
            function getTitle() {
                return title;
            }
            function setTitle(newTitle) {
                title = newTitle;
            }
            function getDescription() {
                return description;
            }
            function setDescription(newDescription) {
                description = newDescription;
            }
    });
    

Set Title and Description

We have a service for setting and getting the title and description, now we can use that service in our dynamic.js controller to dynamically set these values based on the data that gets returned from WordPress.

  1. Open app/scripts/controllers/dynamic.js and inject the metaService, right after pageContent:
    .controller('DynamicCtrl', function (pageContent, metaService) {
    
  2. We’re going to use the WordPress excerpt to drive the content in our meta description. However, the WordPress excerpt contains html and could be longer than 160 characters, so we need to do a couple of operations first. Lets start by declaring a variable called description at the top of the scope:
    .controller('DynamicCtrl', function (pageContent, metaService) {
        var dynamic = this,
            description = pageContent.excerpt.rendered;
    
    ...
    
  3. Next we’ll strip out tags and shorten the excerpt accordingly:
    var dynamic = this,
        description = pageContent.excerpt.rendered;
    
    dynamic.title = pageContent.title.rendered;
    dynamic.content = pageContent.content.rendered;
    
    //=> New Code Here
    description = description.replace(/<[^>]+>/ig, '');
    description = description.substring(0, 157) + '...';
    
  4. Finally, set the title and meta description with the metaService:
    description = description.replace(/<[^>]+>/ig, '');
    description = description.substring(0, 157) + '...';
    
    //=> New Code Here
    metaService.setTitle(dynamic.title);
    metaService.setDescription(description);
    

Bind to Our View

Now that title and description are set dynamically with each page that gets loaded, we can get these values and bind them to our title and meta description tags.

  1. What we don’t have is a controller to help us bind our service values to our view. We could reuse the main.js controller here, but let’s make a new controller specifically for the head tag, just for practice. In the command line:
    yo angular:controller head
    

    This will create the file app/scripts/controller/head.js.

  2. Open app/scripts/controller/head.js and inject our metaService:

    .controller('HeadCtrl', function (metaService) {
    ...
    
  3. Replacing the boilerplate code, bind this to vm and assign metaService to vm.meta:
    var vm = this;
    
    vm.meta = metaService;
    
  4. We are ready to bind these values to our view, but first we need to make a slight modification to our app. Open app/index.html and move the ng-app attribute from the body tag to the html tag. While we’re at it, we need to call our head controller:
    <!doctype html>
    <html ng-app="myappApp">
        <head ng-controller="HeadCtrl as head">
    
    ...
    
    <body>
    
    ...
    
  5. Now we can call our metaService getter methods on the title and meta description tags, like so:
    <title ng-bind="head.meta.title()">My Awesome App</title>
    <meta name="description" content="{{ head.meta.description() }}">
    

    You’ll notice that on the home page you get the default values set in metaService. This is because the home page still uses the MainCtrl which is triggered on the / route in app/app.js. But if you were to navigate to any other page you will see that the title and description are set according to the values of resolved WordPress data.

    Why not see if you can take what you’ve learned here and try to set the title and description in the MainCtrl yourself.

yo-angular-title-description

Summary

In this post we created a new service to set and get title and description values based on returned WordPress data. We then bound those values to our title and meta description tags.

Other Posts in this Series

 

Adam Merrifield

 

2 thoughts on “Dynamic Title and Description with AngularJS and WordPress

  1. Great tutorial. I had a question about where the title and the descriptions for each individual page needs to be set. Currently I have AngularJS and WordPress site setup using $stateProvider rather than $routeProvider. Each of my pages, Home, About, Etc. are within their respective HTML pages and I am using this tutorial to dynamically set the title and the descriptions. Where can I set the Title and Description for each page?
    I do not see this on the tutorial. Also does the DynamicCtrl need to be set within the head tag somewhere?

    Thank you in advance.

    1. This post is one in a series. If you haven’t followed the full series then this post likely wouldn’t make complete sense. The links to the other posts in the series are at the bottom of this post.

Leave a Reply