Статьи

Создание WordPress-интерфейса: посты, категории и пользовательские контроллеры

В предыдущей части серии мы создали специальную директиву для публикации сообщений в интерфейсе. Эта директива принимает аргументы непосредственно в атрибуте HTML, а также в URL для получения сообщений с сервера. Построение директивы позволило нам показать функцию листинга постов в любом месте нашего приложения, повторно используя бизнес-логику и логику рендеринга, предоставляемую директивой.

В этой заключительной части серии мы будем работать с оставшейся частью нашего приложения и сборками контроллеров для листинга постов, отдельного поста, автора и страницы категории. Мы также будем работать с шаблонами этих контроллеров и отображать на них данные, предоставленные контроллерами.

Чтобы быть конкретным, в текущей части серии мы будем:

  • познакомимся с контроллерами AngularJS
  • строить контроллеры для постов, категорий и пользователей
  • связать шаблоны с данными, предоставленными контроллером

Итак, начнем с представления о контроллерах AngularJS.

Контроллеры в AngularJS являются одним из основных строительных блоков приложения. Они содержат бизнес-логику, которая решает, какие данные отображать пользователю. Они управляют большей частью функциональности приложения, связанной с пользовательским интерфейсом, а также обеспечивают поддержку взаимодействия с пользователем.

Контроллеры тесно связаны с DOM и склеивают модель приложения, в котором находятся данные, с представлением приложения.

В нашем случае, когда мы создаем приложение на основе WP REST API, контроллеры — это то место, где мы показываем данные, полученные через API и различные сервисы, для конечного пользователя.

Контроллеры в AngularJS определены в модуле, и мы будем использовать те же обозначения безопасного стиля внедрения зависимостей, что и для объявления пользовательской директивы. Рассмотрим следующий код, в котором мы объявляем контроллер для страницы списка записей:

1
2
3
4
5
6
/**
 * Controller for Post Listing
 */
quiescentApp.controller( ‘PostListing’, [function() {
    var self = this;
}] );

Контроллеры определяются в модуле с помощью .controller() который доступен в модуле. Имя контроллера, которое мы определили выше, это PostListing .

Любые данные, которые нам нужно представить внешнему миру, должны быть установлены в ключевом слове this внутри функции конструктора контроллера. Следовательно, мы кешируем ключевое слово this , создавая переменную self .

Контроллер для пост-листинга является самым простым из всех контроллеров, которые мы создадим, в том смысле, что ему не нужно иметь никаких данных. Для этого просто нужно связать шаблон, и мы <post-listing></post-listing> директиву <post-listing></post-listing> в этот шаблон, чтобы начать публикацию сообщений. Директива будет извлекать сообщения самостоятельно, используя службу Posts и перечислять их, используя собственную логику рендеринга.

Итак, в качестве первого шага, мы свяжем шаблон views / list.html с контроллером PostListing , и мы сделаем это в разделе .config() нашего приложения. В разделе .config() мы настроили маршруты для приложения, и нам нужно изменить маршрут /wp/v2/posts следующим образом:

1
2
3
4
5
$route.when( ‘/posts’, {
    templateUrl: ‘views/listing.html’,
    controller: ‘PostListing’,
    controllerAs: ‘postListing’
} )

В приведенном выше коде мы поместили два дополнительных свойства в определение маршрута, и эти свойства:

  1. controller : имя контроллера, которое нам нужно связать с этим маршрутом и его шаблоном.
  2. controllerAs : ключевое слово, по которому мы ссылаемся на контроллер в нашем шаблоне.

Следовательно, мы передали PostListing качестве имени контроллера, и мы будем ссылаться на него в шаблоне, используя ключевое слово postListing .

Связав контроллер с маршрутом и шаблоном, теперь нам нужно изменить шаблон для правильного отображения списка сообщений. Поэтому откройте файл шаблона views / list.html и замените его содержимое следующим кодом:

1
<post-listing></post-listing>

Ниже приведен скриншот готового шаблона:

Просмотр списка сообщений

Вот и все! Приведенная выше строка кода демонстрирует силу директив AngularJS. С помощью всего одной строки кода мы смогли имитировать функциональность для публикации записей, которая включает в себя бизнес-логику и логику рендеринга. Далее мы увидим, насколько гибкой может быть эта директива AngularJS при создании контроллеров для представлений категорий и списков пользователей в следующих разделах.

Ознакомившись с синтаксисом объявления контроллеров и построив очень простой контроллер для листинга постов, мы готовы начать работу над более продвинутым контроллером для представления категорий.

Контроллер представления категорий, который мы создаем, будет использовать службу $routeParam для доступа к идентификатору категории в URL-адресе, и с помощью этого идентификатора контроллер будет использовать службу категорий для получения информации о категории и списка связанных сообщений. Однако контроллер не будет напрямую извлекать сообщения, используя службу Posts , а скорее будет использовать директиву postListing и передавать ей идентификатор категории, чтобы получить список сообщений, связанных с этой категорией.

Ниже приведен код для контроллера CategoryListing :

01
02
03
04
05
06
07
08
09
10
11
/**
 * Controller for Categories
 */
quiescentApp.controller( ‘CategoryListing’, [‘$routeParams’, ‘Categories’, function( $routeParams, Categories ) {
    var self = this;
    self.categoryInfo = {};
     
    Categories.get( {‘id’: $routeParams.id}, function( data, headers ) {
        self.categoryInfo = data;
    });
}] );

Контроллер CategoryListing выше имеет две зависимости для службы $routeParams и настраиваемой службы Categories . Используя службу $routeParams , он получает идентификатор категории из URL-адреса, а затем запрашивает этот идентификатор для получения информации о категории через службу Categories .

Контроллер имеет переменную, определенную в объекте $scope именем categoryInfo . Эта переменная содержит объект категории, возвращаемый сервером, и его значение устанавливается после успешного выполнения запроса.

Следующее, что нам нужно сделать, это связать шаблон с этим контроллером, который будет отображать данные для пользователя. И мы делаем это в разделе приложения .config , так же, как мы делали для контроллера PostListing в предыдущем разделе.

Поэтому измените маршрут /categories/:id чтобы он содержал следующий код:

1
2
3
4
5
6
// category profile route
.when( ‘/categories/:id’, {
    templateUrl: ‘views/category.html’,
    controller: ‘CategoryListing’,
    controllerAs: ‘categoryListing’
} )

В приведенном выше коде мы связываем маршрут с контроллером CategoryListing а также определяем ключевое слово categoryListing через которое мы ссылаемся на него в шаблоне.

Теперь пришло время изменить шаблон views / category.html, чтобы он отображал данные динамически, а не статический HTML-код.

1
2
3
<h2>Category: {{categoryListing.categoryInfo.name}}</h2>
 
<post-listing post-args=»{‘filter[cat]’: categoryListing.categoryId}»></post-listing>

В приведенном выше коде мы заменили жестко закодированное имя категории на {{categoryListing.categoryInfo.name}} , где categoryListing является экземпляром контроллера CategoryListing . Переменная categoryInfo содержит объект категории, возвращаемый сервером, и этот объект содержит свойство name для имени категории.

Для функции публикации postListing мы используем директиву postListing и передаем ей идентификатор категории через атрибут post-args . Для этой цели мы используем синтаксис filter[] поддерживаемый маршрутом /wp/v2/posts API REST WP. Мы уже знакомы с синтаксисом filter[] из четвертой части вводной серии об API-интерфейсе WP REST.

Ниже приведен скриншот завершенного представления категории:

Просмотр категории

Давайте теперь разработаем контроллер для пользователей, который очень похож на контроллер категорий.

Контроллер для пользовательского представления очень похож на контроллер категорий. Мы начнем с изменения конфигурации маршрутизации, чтобы связать контроллер с шаблоном:

1
2
3
4
5
6
// author profile route
.when( ‘/users/:id’, {
    templateUrl: ‘views/author.html’,
    controller: ‘UserListing’,
    controllerAs: ‘userListing’
} )

Здесь мы связываем контроллер UserListing с маршрутом и его шаблоном. userListing словом, по которому мы ссылаемся на экземпляр контроллера, является userListing .

Ниже приведен код для контроллера UserListing :

01
02
03
04
05
06
07
08
09
10
11
12
/**
 * Controller for Users
 */
quiescentApp.controller( ‘UserListing’, [‘$routeParams’, ‘Users’, function( $routeParams, Users ) {
    var self = this;
    self.userInfo = {};
    self.userId = $routeParams.id;
     
    Users.get( {‘id’: self.userId}, function( data, headers ) {
        self.userInfo = data;
    });
}] );

Контроллер UserListing принимает $routeParams и Users качестве зависимостей. Используя сервис $routeParams , он получает доступ к идентификатору пользователя в URL. Служба Users затем используется для извлечения объекта пользователя с использованием идентификатора пользователя. Переменная userInfo содержит объект пользователя, возвращаемый сервером.

Давайте теперь изменим шаблон views / author.html, чтобы отобразить эти данные для пользователя. Замените все содержимое файла author.html следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<!— author box starts —>
<div class=»author-box row»>
    <figure class=»author-gravatar columns medium-4″>
        <img ng-src=»{{userListing.userInfo.quiescent_avatar_url}}» alt=»{{userListing.userInfo.name}}»>
    </figure>
    <div class=»author-info columns»>
        <h2 class=»author-title»>About {{userListing.userInfo.name}}</h2>
        <p>{{userListing.userInfo.description}}</p>
    </div>
</div>
<!— author box ends —>
 
<h2>Posts by {{userListing.userInfo.name}}</h2>
 
<post-listing post-args=»{author: userListing.userId}»></post-listing>

В приведенном выше коде мы получаем доступ к переменной userInfo определенной в области видимости контроллера, которая содержит объект информации о пользователе. Используя различные свойства этого пользовательского объекта, мы заменяем жестко запрограммированное имя пользователя, граватару пользователя и описание пользователя.

Для postListing сообщений, созданных пользователем, мы используем директиву postListing и передаем ей идентификатор пользователя в качестве значения параметра author . Затем директива извлекает сообщения, используя службу Posts .

Вот как должен выглядеть завершенный вид:

Вид пользователя

Четвертый и последний контроллер, над которым нужно поработать сейчас, предназначен для просмотра одного поста, и мы сделаем это в следующем разделе.

Представление для одного сообщения немного отличается от других, поскольку оно не будет использовать директиву postListing потому что директива использует шаблон, который больше подходит для страницы публикации поста. Кроме того, мы добавим поддержку для отображения комментариев для одного сообщения в будущем, поэтому нам нужно иметь отдельный шаблон для одного сообщения, а не использовать тот же шаблон, что и для публикации сообщений.

По указанным выше причинам мы будем использовать службу Posts вручную в контроллере для одного сообщения, чтобы получить сообщение, основываясь на его слаге.

Давайте сначала сделаем быструю модификацию в маршруте одного сообщения, чтобы связать контроллер и шаблон:

1
2
3
4
5
6
// single post route
.when( ‘/posts/:slug’, {
    templateUrl: ‘views/single.html’,
    controller: ‘SinglePost’,
    controllerAs: ‘singlePost’
} )

Таким образом, имя контроллера для одного поста будет SinglePost . Мы будем использовать ключевое слово singlePost для ссылки на него в своем шаблоне.

Ниже приведен код для объявления контроллера:

01
02
03
04
05
06
07
08
09
10
11
12
/**
 * Controller for Single Post
 */
quiescentApp.controller( ‘SinglePost’, [‘$routeParams’, ‘Posts’, function( $routeParams, Posts ) {
    var self = this;
    self.postSlug = $routeParams.slug;
    self.post = {};
     
    Posts.query( {‘slug’: self.postSlug}, function( data, headers ) {
        self.post = data[0];
    });
}] );

В приведенном выше коде мы сначала извлекаем почтовый слаг с $routeParams службы $routeParams и сохраняем его в свойстве self.postSlug в области видимости контроллера. Затем мы запрашиваем базу данных, используя сервис Posts , предоставляя post-slug в качестве аргумента запроса. self.post данные — это массив, содержащий один объект, и мы устанавливаем свойство self.post в области действия, используя эти возвращаемые данные. Просто!

Теперь для шаблона ниже приведено содержимое файла views / single.html :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<!— post listing starts —>
<article class=»post-entry»>
    <h2 class=»post-title»><a ng-href=»#/posts/{{singlePost.post.slug}}»>{{singlePost.post.title.rendered}}</a></h2>
    <figure class=»post-thumbnail» ng-show=»singlePost.post.quiescent_featured_image»>
        <img ng-src=»{{singlePost.post.quiescent_featured_image}}» alt=»Featured Image»>
    </figure>
    <p class=»post-meta»>
        By <a ng-href=»#/users/{{singlePost.post.author}}»>{{singlePost.post.quiescent_author_name}}</a>
        in <a ng-href=»#/categories/{{category.term_id}}» ng-repeat=»category in singlePost.post.quiescent_categories»>{{category.name}}{{$last ?
    </p>
    <div class=»post-content» ng-bind-html=»singlePost.post.content.rendered»></div>
    <p class=»back-to-listing»>
        <button class=»button» onclick=»window.history.back()»>Back to posts listing</button>
    </p>
</article>
<!— post listing ends —>

Приведенный выше код довольно прост, поскольку мы привязываем различные свойства объекта post к различным элементам, как мы делали в последних нескольких разделах.

Ниже приведен скриншот завершенного просмотра одного сообщения:

Один пост просмотр

Приложение завершено (еще не совсем!) И предоставляет просмотры для списка сообщений, отдельного сообщения, страницы пользователя и категории.

На этом мы завершаем серию из четырех частей, в которой мы создали интерфейс, работающий на WP REST API и AngularJS. Мы начали с анализа требований и анализа каркасов. Затем мы создали сопутствующий плагин, который предоставляет некоторые дополнительные поля в стандартных ответах, которые будут необходимы в нашем интерфейсе.

В следующих частях мы загрузили наше приложение AngularJS, проанализировали шаблоны для различных представлений и настроили маршрутизацию приложения. Мы также создали специальную директиву AngularJS для функции публикации сообщений, которая абстрагирует функциональность для публикации сообщений и предоставляет гибкий способ получения набора сообщений для различных требований.

В заключительной части серии мы создали контроллеры для списка публикаций, отдельных сообщений, категорий и пользовательских представлений и связали их с соответствующими шаблонами через раздел .config() нашего приложения.

Приложение не является полным и может быть улучшено многими способами. Некоторые идеи перечислены ниже:

  • ветка комментариев на просмотр одного сообщения
  • Нет сообщений автора сообщения, когда на странице профиля автора нет сообщения пользователя.
  • нумерованная нумерация страниц на страницах листинга
  • лучший SEO с AngularJS одностраничных приложений

Мы постараемся использовать эти функции в следующих уроках. Но сейчас я оставляю вам возможность поиграть с приложением и дополнить его некоторыми потрясающими функциями. Не забудьте предоставить онлайн-демо для приложения в комментариях, так как я очень хочу учиться у моих читателей.