Создаем веб-приложение с помощью WordPress

Дата публикации:Март 4, 2013

Презентация Мэтта Мулленвега «State Of The Word» предсказала основные тенденции развития WordPress в 2012 году. Основной акцент в этой презентации был сделан на веб-приложениях, создаваемых с помощью WordPress. Однако стоит сразу отметить, что информации по данной теме в интернете не так уж и много. Мы решили восполнить данный пробел. В указанном руководстве мы рассмотрим создание простого приложения, позволяющего составлять список основных задач. Данное приложение будет работать на всех платформах – включая мобильные устройства, планшеты и настольные компьютеры.

preview theme

По ссылке представлена демонстрационная страница (логин: user, пароль: notes), на которой вы можете увидеть полностью реализованное приложение в WordPress. Это наш итоговый результат, к которому мы будем идти в данном руководстве. Также вы можете скачать уже готовый архив с исходной темой.

Немного теории

Сегодня многочисленные фреймворки для создания веб-приложений используют структуру MVC или MVVM. В WordPress реализована своя собственная, уникальная структура обработки данных, без знания которой мы не сможем создавать полноценные приложения. Я имею в виду разделение логики, событийных функций и представления.

data-flow-340x263

WordPress – идеальный фундамент для создания приложений, поскольку он обладает обширным API-функционалом. У нас есть аутентификация, пользовательские роли, санитизация, типы контента и т.д. Нам не нужно заботиться об экране администратора. Если вы создаете комплексное приложение, то вам не нужно будет беспокоиться о мета-полях, таксономиях, загрузке изображений. Все это уже реализовано в WP.

Подход, который мы будем использовать, достаточно прост. Я создал стартовую тему (обладающую CSS-стилями и базовой WP/JS функциональностью), с которой мы и будем работать. Код, который нам понадобится писать в указанном руководстве, будет разбит на Javascript- (main.js) и WordPress-логику (ajax-actions.php). Такое разделение кода позволит нам создать гибкое, структурированное приложение.

Увеличиваем скорость

Основное внимание в данном руководстве будет уделяться не дизайну приложения, а его разработке на базе AJAX. Я покажу вам, как идентифицировать отдельные события, как работать с ними, как получить от них данные, как внести их в базу данных WordPress и как обработать полученный ответ. Все это мы будем делать вне панели администратора.

Стартовая тема, которую я создал для вас, является простым каркасом без какой-либо функциональности. Весь интерфейс уже реализован мною (кнопки, стиль, выпадающие меню, модальные окна) – вам нужно будет провести тяжелый труд, основанный на получении и сохранении данных, а также обновлении пользовательского интерфейса в зависимости от полученного ответа.  Я добавил Mustache.js, шаблоны, которые мы будем использовать (в footer.php), а также необходимый код, который понадобится нам для отображения списка всех записей и пользователей, находящихся в базе данных во время первой загрузки.

Поток данных в одностраничном веб-приложении

data-flow

Давайте исследуем диаграмму, представленную выше.

Здесь вы можете видеть, что наши данные передаются из пользовательского интерфейса, когда пользователь отправляет их. Javascript интерпретирует ввод данных от пользователя и передает эти данные PHP. PHP выполняет добавление данных в БД WordPress. Когда WP получит данные, PHP передает Javascript’у, что данные были сохранены. Затем Javascript обновляет пользовательский интерфейс, чтобы человек мог понять, что он все сделал правильно.

Если смотреть на данный процесс с позиций Javascript, то нам необходимо создать четыре важные функции, отсутствующие в стартовой теме.

  1. UI для взаимодействия с пользователем.
  2. UI для запросов (когда пользователь отправляет данные).
  3. AJAX-запросы (передача данных в WP).
  4. AJAX-ответ (обработка ответа, полученного от WP).

Если смотреть на данный процесс с позиций WordPress и PHP, у нас нет в стартовой теме действий для обработки AJAX-запросов от клиента. Очень скоро я идентифицирую их для вас, однако сначала давайте запустим WordPress и установим стартовую тему.

Базовая тема

Ваш WP сайт должен выглядеть на данный момент следующим образом

Ваш WP сайт должен выглядеть на данный момент следующим образом

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

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

actions-circled

  1. Очистить все записи.
  2. Добавить пользователя (или удалить пользователя)
  3. Удалить запись.
  4. Добавить запись.

Еще одно действие – Обновить запись – будет видимым при взаимодействии с UI.

update-action

Мы будем использовать мощный механизм событий jQuery для отлова всех видов взаимодействий и получения необходимых данных, которые затем будут передаваться в БД. Если вы откроете файл footer.php и взглянете на строку 26, то вы заметите, что у каждой ссылки (кнопки) есть три набора данных: data-modal, data-action, and data-id.

<a ... data-modal="" data-action="update-post", data-id="{{id}}">update</a>

С помощью jQuery мы можем получить эту информацию очень легко, поскольку мы знаем (в данном случае), какое модальное окно открыто (если такие есть), какое действие вызвано и каков ID пункта, с которым ведется работа. Давайте быстро взглянем на структуру данных из пользователей и заметок.

Структура данных для пользователей и заметок

Структура данных для пользователей и заметок

Чтобы ничего не усложнять, пользователь будет просто добавляться по email-адресу. Это означает, что пользователь состоит из:

  • ID (integer);
  • Email-адреса (string).

Под записями в данном случае подразумеваются заголовки записей в WP. Они состоят из:

  • ID (integer)
  • Заметки (string)

Как вы можете видеть, объекты данных практически идентичны, что немного упрощает нашу работу. JSON-данные, передаваемые на сервер, будут выглядеть следующим образом:

{
  action: "action-to-be-called",
  id: 1,
  text: "Email Address or Note"
}

Остановимся на AJAX-запросах

Теперь, когда мы получили представление о структуре данных, нам необходимы некоторые Javascript-функции, чтобы обрабатывать запросы. Откройте файл functions.php и перейдите к строке 63. Вы увидите комментарий:

//WP LOCALIZE SCRIPT

Говоря кратко, в WordPress есть функция wp_localize_script(), которая используется при создании многоязычных сайтов. Ее основная задача – передавать идентификатор языка скриптам через переменную, прикрепленную к окну.

Мы можем использовать эту переменную, чтобы сделать доступным расположение wp-ajax файла для наших скриптов. Таким образом, у нас есть корректный URL для отправления запросов AJAX. Идем дальше и заменяем комментарий следующим кодом:

wp_localize_script(
  'main',
  'WP_AJAX',
  array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) )
);

Сохраняем и закрываем файл functions.php. Если вы откроете сайт WP и посмотрите его исходник, вы увидите что-то похожее на это (рядом с закрывающим тегом body):

/* <![CDATA[ */
var WP_AJAX = {"ajaxurl":"http://articl.es/notes-app/wp-admin/admin-ajax.php"};
/* ]]> */

В Javascript это доступно для нас в переменной:

WP_AJAX.ajaxurl

Теперь у нас есть AJAX URL для публикации.

Обработка запросов AJAX

Мы собираемся создать нашу первую функцию Javascript, обрабатывающую запросы AJAX. Поскольку я подключил jQuery в стартовой теме, мы будем использовать функцию $.post, позволяющую отправлять запросы серверу. Как только мы научимся обнаруживать пользовательские действия (в следующем разделе), мы будем использовать эту функцию для отправки данных, полученных от пользователя.

В файле js/main.js заменим 64 строку

//create processRequest function

следующим кодом:

processRequest: function(data){
  console.log(data);
  $.post(
    WP_AJAX.ajaxurl,
    data,
    Notes.succcessfulRequest
  );
},

Мы расширяем объект Notes в main.js для подключения другой функции processRequest. Если вы не разбираетесь в Javascript, просто выполняйте все шаги и вставляйте код.

Как и в PHP, Javascript функции получают некоторые аргументы. В нашем случае processRequest получает переменную, которую мы назвали data.

console.log(data) регистрирует данные, переданные в консоль вашего браузера. Мы рассмотрим это позже.

$.post отправляет POST запрос и получает три аргумента (в порядке следования):

  1. AJAX URL для отправки данных.
  2. Данные, передаваемые в URL (в формате объекта).
  3. Функция успеха для обработки ответа от AJAX-запроса.

Если вы разбираетесь в происходящем, то вы сделаете вывод, что теперь нам нужна функция successfulRequest, поскольку ее до сих пор не существует.

Отлично. В том же самом файле main.js заменяем

//create successfulRequest function

на

succcessfulRequest: function(jsonResponse){
  alert('Request sent!');
 
  //change UI based on response from WordPress
},

successfulRequest() получает переменную jsonResponse, которая является ответом от сервера. Когда мы дойдем до PHP, мы просто выведем все, что мы хотели возвратить в этой переменной, и функция это использует.

На данный момент функция просто выдаст предупреждение в браузере, показывающее, что запрос AJAX был успешно отправлен.

Чем же все это полезно?

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

Обработка действий с UI

На 55 строке файла main.js вы можете увидеть функцию actions. В настоящее время она неактивна, и только скрывает модальные окна в нижней части страницы используемой темы. Перейдем на строку 7, где находится комментарий:

//actions call

Заменим его на:

Notes.actions();

Поскольку код находится в функции init (которая вызывается в самом низу файла main.js при полной загрузке страницы), если вы обновите страницу, то модальные окна будут скрыты.

Обнаружение пользовательских действий

Функция actions, которую нам нужно написать, должна обнаруживать щелчок пользователя по кнопкам. Она получит все необходимые данные, после чего проверит, требуется ли модальное окно. Если нет, то она произведет AJAX-запрос. Если да, то в таком случае будет открыто модальное окно, связанное с действием (определяется атрибутом data-modal, который мы видели ранее).

В строке 58 заменим комментарий следующим кодом:

$('.action').on('click', function(e){
 
  e.preventDefault();
 
  var action = 'notes-' + $(this).data('action');
  var modal  = $(this).data('modal');
  var id     = $(this).data('id');
  var text   = $(this).parent('li').find('input').val();
 
  var data = {
    action: action,
    id: id,
    text: text
  };
 
  if( modal === "" ){
    Notes.processRequest(data)
  } else { //if a modal is required }
});

Если вы знакомы с jQuery, то вы знаете, что делает данный код. Функция .on() сообщает jQuery, что необходимо вызывать следующую функцию всякий раз, когда выбран класс .action (т.е. при щелчке по кнопке).

e.preventDefault() предохраняет от изменения URL.

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

Переменная action будет выполняться на сервере как notes-action-called. Переменная Modal будет или пустой (если не требуется дополнительный ввод данных), или yn – если требуется подтверждение yes/no, или invite – в случае добавления нового пользователя в приложение. Затем все данные преобразуются в JSON-объект.

Условное выражение проверяет, требуется ли модальное окно. Если нет, то все данные передаются в функцию, которую мы создали ранее для обработки запросов.

Обновите свой сайт WordPress и щелкните по иконкам добавления и удаления. Вы получите уведомление, что ваш запрос был отправлен. Отлично!

first-request-sent

Теперь нам необходимо обработать оператор else – условие, когда требуется модальное окно. Заменим условие

} else { //if a modal is required }

на следующее:

} else if ( modal != "" ){
  Notes.openNotice(modal, data);
}

Оно проверяет, присутствует ли атрибут data-modal, и если да, то передает модальный тип и объект данных в функцию openNotice.

Теперь функция actions должна иметь следующий вид:

actions: function(){
  $('.notice').addClass('hidden');
 
  $('.action').on('click', function(e){
 
    e.preventDefault();
 
    var action = 'notes-' + $(this).data('action');
    var modal  = $(this).data('modal');
    var id     = $(this).data('id');
    var text   = $(this).parent('li').find('input').val();
 
    var data = {
      action: action,
      id: id,
      text: text
    };
 
    if( modal === "" ){
      Notes.processRequest(data)
    } else if ( modal != "" ){
      Notes.openNotice(modal, data);
    }
  });
},

Функция openNotice уже создана – она находится над функцией actions в строке 35.

Чтобы получить передаваемые аргументы, нам понадобится немного модифицировать эту функцию. Изменим функцию openNotice, чтобы она могла принимать аргументы:

openNotice: function(noticeClass, data){
  $('.notice:visible').toggleClass('hidden').data('info', '');
  Notes.centreNotice();
  $('.'+noticeClass).toggleClass('hidden').data('info', data);
},

Она скрывает все видимые модальные окна и уничтожает все данные, прикрепленные к ним. Также она центрирует модальные окна, что также является встроенным действием. Наконец, функция находит модальное окно с некоторым классом (атрибутом data-modal кнопки), и затем прикрепляет наши данные к этому окну. Последнее действие очень важно, поскольку нет никакого другого способа для передачи данных следующему событию (подтверждению или вводу email-адреса для приглашения или отмены).

Сохраните файл main.js и обновите сайт. Щелкните по действию, которое вызывает модальное окно – «добавить пользователя» или «очистить заметки». Вы получите небольшое модальное окно, предварительно созданное вашим покорным слугой, то бишь, мной.

yes-no-modal

invite-modal

Отправка запросов при взаимодействии с пользователем

Последняя сложность – передача запросов в функцию processRequest() в зависимости от пользовательского ввода в модальное окно. Пользователь вводит email-адрес в модальное окно ввода адреса или щелкает yes в окне подтверждения.

Все это передается через функцию UISendRequest(), которая считывает ответ пользователя в модальном окне, получает данные, которые мы ранее прикрепили к модальному окну, и затем отправляет их в processRequest().

На 8 строке main.js стоит еще один закомментированный вызов:

//UISendRequest call

Отредактируем данную строку, выполнив вызов функции UISendRequest внутри init():

Notes.UISendRequest();

Теперь мы должны написать саму функцию. Строка 80 – еще один комментарий, который нам необходимо заменить функцией:

UISendRequest: function(){
  $('.go').click(function(){
    var data = $(this).parents('.notice').data('info');
 
    Notes.processRequest(data);
    $('.notice:visible').toggleClass('hidden').data('info', '');
  });
 
  $('.cancel').click(function(){
    $(this).parents('.notice').toggleClass('hidden').data('info', '');
  });
},

Данная функция привязывает событие щелчка к кнопкам .go и .cancel. Они расположены в наших модальных окнах файла footer.php, в строках 5, 6 и 12. Функция получает данные, прикрепленные к модальному окну, в котором было инициировано действие, обрабатывает запрос, после чего закрывает модальное окно и уничтожает прикрепленные данные. Отмена закрывает модальное окно и уничтожает прикрепленные данные.

Сохраните файл и вернитесь к сайту. Обновите его. Помните, как мы помещали console.log()в функцию processRequest()? Вот здесь это и пригодится нам. Если вы не знаете, как открыть консоль браузера, можете почитать следующую страницу.

chrome-instructions-for-console-470x177

В консоли в основном выводятся ошибки, связанные с Javacript, а также разные ошибки, вызванные в процессе передачи запросов. Функция console.log() выводит в консоли все то, что стоит между скобками. Поскольку мы поместили в нее переменную data, вызов processRequest() отобразит в консоли данные, переданные в эту функцию.

logged-actions

Через консоль вы можете отследить все действия, которые я совершил в UI.

Первое, что я сделал – это подтвердил, что хочу очистить все заметки. Для этого нам нужна только функция action, выполняющая полное удаление.

Следующий шаг – я попытался обновить запись «Hello World!». Вы видите data-action, data-id и текст для обновления, который был передан в processRequest().

email-invite

Последний шаг – я попытался пригласить пользователя в приложение. Вы можете видеть это в консоли, однако самого адреса в ней нет. Очень важно передать его в функцию processRequest, поскольку мы будем использовать его в коде WordPress для регистрации нового пользователя.

Исправить данный недостаток можно двумя строчками кода. Прежде, чем отправить запрос, мы должны проверить, является ли модальное окно приглашением и выбран ли адрес электронной почты, который будет добавлен к переменной data. Поместите данный фрагмент кода сразу перед строкой Notes.processRequest() в функции UISendRequest().

if($(this).parents('.notice').hasClass('invite'))
  data.text = $('.invite-email').val();

Если вы попытаетесь пригласить человека, то вы теперь увидите в консоли его электронный адрес.

email-being-logged

Наконец, мы хотим видеть ответ сервера. В функции successfulRequest() измените предупреждение, чтобы получить переменную jsonResponse вместо сообщения “Request sent!”.

succcessfulRequest: function(jsonResponse){
  console.log(jsonResponse);
 
  //change UI based on response from WordPress
},

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

Взаимодействие с WordPress

На данный момент сценарий передает в WordPress данные, которые мы собрали, однако сам WP не знает, что с этими данными делать.

Помните, как мы передавали data-action через AJAX-запрос? Сейчас это нам пригодится. Как оказалось, действие (action) – это единственный параметр, который необходим WordPress для обработки AJAX-запроса. Мы будем использовать действие в качестве хука для присоединения PHP-функций. Таким образом, хук

add_action( 'wp_ajax_notes-add-user', 'notes_add_user' );

будет реагировать на AJAX-запрос notes-add-user. Круто, правда? Это, безусловно, означает, что PHP-функция notes_add_user() должна существовать.

Перед тем, как погрузиться в это, нам необходимо получить предварительно созданный, непротиворечивый ответ для передачи обратно в Javascript. Переменная $fail – простой ответ с неудачным действием (т.е. что-то пошло не так в коде WP). generate_response() принимает три аргумента, которые передаются обратно в Javascript.

Откроем файл ajax-actions.php и заменим строки 7-9 на следующее:

$fail = json_encode(array('message' => 'fail'), JSON_FORCE_OBJECT);
 
function generate_response($message, $id = null, $text = null){
  $response = array(
    'message' => $message,
    'id'      => $id,
    'text'    => $text
  );
 
  echo json_encode($response, JSON_FORCE_OBJECT);
}

Здесь представлены две полезные функции, которые служат важной цели. Возьмем, к примеру, функцию json_encode(). Передавая массив в качестве первого аргумента и JSON_FORCE_OBJECT в качестве второго, наш PHP ответ передается обратно в JSON, чтобы интерпретироваться Javascript.

Есть ли здесь что-то знакомое нам? Структура нашего ответа идентична структуре нашего запроса: действие становится сообщением, идентификатор и текст остаются теми же. Конечно, не всегда требуется имитировать существующую структуру, однако это помогает сохранить простоту и понятность кода. Особенно при работе с ответом от WP и переводе его в изменения UI (чтобы пользователь видел, что его действия к чему-то привели).

Аутентификация и ответы в случае неудачи

Для начала мы должны разрешить выполнение некоторых действий для пользователей. К примеру, если один пользователь пытается добавить другого, у них должна быть возможность использования wp_insert_user(). Функция current_user_can() позволяет нам проверять это. Я опишу все совершаемые нами действия вместе с AJAX хуками. Добавим следующий код сразу после функции generate_response():

function notes_add_user(){
 
  if(current_user_can( 'add_users' )){
 
    extract($_POST);
 
    //create user code here
 
  } else { echo $fail; }
  exit;
}
 
function notes_delete_user(){
  if(current_user_can( 'remove_users' )){
 
    extract($_POST);
 
    //delete user code here
 
  } else { echo $fail; }
  exit;
}
 
function notes_clear_all(){
  if(current_user_can( 'delete_posts' )){
 
    //do delete all posts here
 
  } else { echo $fail; }
  exit;
}
 
function notes_new_post(){
  if(current_user_can( 'publish_posts' )){
    extract($_POST);
 
    //do create new post code here
 
  } else { echo $fail; }
  exit;
}
 
function notes_update_post(){
  if(current_user_can( 'edit_posts' )){
    extract($_POST);
 
    //update post code here
 
  } else { echo $fail; }
  exit;
}
 
function notes_delete_post(){
  if(current_user_can( 'delete_posts' )){
    extract($_POST);
 
      //delete post code here
 
  } else { echo $fail; }
  exit;
}
 
add_action( 'wp_ajax_notes-add-user', 'notes_add_user' );
add_action( 'wp_ajax_notes-delete-user', 'notes_delete_user' );
add_action( 'wp_ajax_notes-clear-all', 'notes_clear_all' );
add_action( 'wp_ajax_notes-new-post', 'notes_new_post' );
add_action( 'wp_ajax_notes-update-post', 'notes_update_post' );
add_action( 'wp_ajax_notes-delete-post', 'notes_delete_post' );

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

Примечание: функция the extract($_POST) очень важна. Она распределяет наш блок данных по переменным, таким как $action, $id и $text.

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

Самая популярная ошибка пользователей вызвана неверным добавлением этих функций в тему. Откройте functions.php и перейдите к его нижней части. Замените комментарий INCLUDE AJAX ACTIONS вызовом функции include_once(). Не забудьте это сделать! Иначе вы всегда будете получать пустые ответы.

include_once(ajax-actions.php);

Добавление пользователя

Довольно странно, но наше действие add-user является самым сложным из всех. На то есть своя причина – нам необходимо выполнить последовательность действий:

  1. Создать имя пользователя на основе электронной почты.
  2. Проверить, существует ли уже такой пользователь.
  3. Сгенерировать случайный пароль.
  4. Создать нового пользователя.
  5. Установить для пользователя роль Редактора, чтобы у него были полномочия по добавления и удалению записей.
  6. Уведомить пользователя, что он был добавлен.
  7. Отправить ответ назад в javascript.

Код является следующим:

function notes_add_user(){
 
  if(current_user_can( 'add_users' )){
 
    extract($_POST);
    $user_name = substr($text, 0, strpos($text, "@"));
 
    $user_id = username_exists( $user_name );
 
    if ( !$user_id and email_exists($text) == false ) {
 
      $random_password = wp_generate_password( $length=12, $include_standard_special_chars=false );
      $user_id = wp_create_user( $user_name, $random_password, $text );
 
      $user = new WP_User($user_id);
      $user->set_role( 'editor' );
 
      wp_new_user_notification( $user_id, $random_password );
 
      generate_response('user-added', $user_id, $text);
 
    } else { echo $fail; }
 
  } else { echo $fail; }
  exit;
}

Его объяснение занимает долгое время.

Очень важно отметить функцию generate_response(). В ней мы передаем сообщение успеха ‘user-added’, ID нового пользователя, и адрес электронной почты. Это отобразится в вашей консоли после получения ответа в WP.

Сохраните это и пригласите пользователя. Как вы можете видеть на следующем скриншоте, я отправляю запрос на добавление пользователя, и затем получаю ответ, что пользователь был добавлен вместе с его адресом электронной почты и присвоенным ему ID. Неплохо!

request-and-response

Такой тип запроса и ответа представляет собой последнюю сложность — перевод ответа из JSON-объекта, полученного от WP, в изменения UI, которые может заметить человек.

Если вы обновите страницу, то недавно добавленный пользователь появится в меню пользователей панели администратора. Но нам нужно, чтобы это происходило без обновления страницы!

new-user-in-list

Обработка ответа

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

Поскольку данные возвращаются в функцию successfulRequest(), в ней мы и обработаем ответ.

Если вы знаете PHP, то вы быстро поймете цикл switch/case. В Javascript тоже есть функция, аналогичная switch, поэтому мы можем перейти к сообщению, полученному от сервера, для выполнения различных задач.

Вернемся к файлу main.js и перейдем к строке 103, где находится функция successfulRequest(). Изменим ее:

succcessfulRequest: function(jsonResponse){
  //action's effect on UI
 
  response = jQuery.parseJSON(jsonResponse);
 
  console.log(response.message);
 
  switch (response.message){
 
    case "fail" : alert('Something went wrong.'); break;
 
    case "user-added" :
 
      console.log('user with email address ' + response.text + ' has been added to WordNotes');
 
      var user_tmpl = $('#tmpl-user').html();
      var user_data = {
        id: response.id,
        email: response.text
      }
 
      if($('.all-users .empty').length > 0) $('.all-users .empty').remove();
 
      $('.all-users').append(Mustache.render(user_tmpl, user_data));
 
    break;
 
    //OTHER CASES GO IN HERE
 
  }
 
},

Мы переводим возвращенный ответ JSON в читаемый для jQuery вид JSON с помощью parseJSON().

Затем мы возвращаем сообщение console.log() для нашего удобства.

Теперь идет довольно увесистая часть. Мы используем switch для переключения между сообщениями, и применяем Javascript. Естественно, мы тестируем на случай «user-added» и затем выводим console.log(), если действие было выполнено успешно.

Следующие пять строк – настройка шаблона Mustache, готового для вставки в меню (помните, что я настроил все шаблоны, чтобы вы могли сфокусироваться на JS и PHP. Они находятся в footer.php, если вам интересно).

Следующая строка проверяет наличие строки-заполнителя ‘No users! Add some!’. Если эта строка есть, удаляем ее.

Наконец, мы добавляем нового пользователя к списку пользователей с помощью Mustache функции render, которая выдает шаблон вместе со всеми переданными данными.

Сохраните все это, перейдите к своему сайту и обновите его. Щелкните по списку Пользователи, затем щелкните «Добавить нового пользователя». Введите адрес электронной почты, и нажмите Invite. Вы увидите, что пользователь добавлен в список!

request-response-reaction

Если вы посетите секцию администратора и зайдете в раздел Пользователей, то увидите там всех добавленных вами пользователей. И это без использования панели администратора!

Этот пример демонстрирует мощь AJAX запросов, объединенных в файле wp-ajax.php.

users-in-database

Что по поводу оставшихся действий?

Да, действительно, остались еще пять действий. Вместо полноценного описания я просто приведу код каждого из них, разбитый на код для WP и код для main.js. Просто добавьте их и все.

Если что-то пошло не так, убедитесь, что функция switch/case в файле main.js форматирована должным образом. Иначе ищите ошибку в чем-то другом!

Удаление пользователей

Ajax-actions.php

function notes_delete_user(){
  if(current_user_can( 'remove_users' )){
 
    extract($_POST);
 
    if(wp_delete_user($id))
      generate_response('user-deleted', $id);
 
  } else { echo $fail; }
  exit;
}

Просто получите ID и используйте wp_delete_user() для удаления пользователя. Ответ должен содержать ID удаляемого пользователя, чтобы он был также удален из UI.

main.js

case "user-deleted" :
  $('#user-' + response.id).remove();
  if($('.all-users li').length == 0) $('.all-users').append('<li class="empty">No users yet! add some.</li>');
break;

Удаляем из UI пользователя с возвращенным ID. Убеждаемся в том, что список не является пустым, иначе добавляем заполнитель.

Удаление всех заметок

ajax-actions.php

function notes_clear_all(){
  if(current_user_can( 'delete_posts' )){
    $posts = get_posts(array('posts_per_page' => 9999));
    foreach($posts as $post) wp_delete_post( $post->ID );
 
    generate_response('all-deleted');
 
  } else { echo $fail; }
  exit;
}

Используем get_posts() для получения 9999 самых свежих записей и в цикле используем wp_delete_post() для их удаления. Высылаем ответ all-deleted, чтобы UI был очищен от примечаний.

main.js

case "all-deleted" :
  $('.note').remove();
  alert('All notes have been deleted.');
break;

Просто удаляем все элементы списка с классом note, и предупреждаем пользователя, что они были удалены.

Добавление заметок

ajax-actions.php

function notes_new_post(){
  if(current_user_can( 'publish_posts' )){
    extract($_POST);
 
    $p = array(
      'post_title'    => $text,
      'post_author'   => get_current_user_id(),
      'post_content'  => ' ',
      'post_status'   => 'publish'
    );
 
    $post_id = wp_insert_post($p);
 
    if($post_id != 0){
 
      generate_response( 'post-added', $post_id, $text );
 
    } else { echo $fail; }
 
  } else { echo $fail; }
  exit;
}

Создаем массив записей, используя wp_insert_post() для создания нового сообщения. Высылаем ответ с сообщением post-added, ID новой записи и заголовков записи для вставки в UI.

main.js

case "post-added" :
 
  console.log('Note added!');
 
  var post_tmpl = $('#tmpl-post').html();
  var post_data = {
    id: response.id,
    post_title: response.text
  };
 
  $(Mustache.render(post_tmpl, post_data))
    .insertBefore('.notes ul .new-post');
 
  $('.new-post input').blur().val('New note...');
 
break;

Отмечаем, что заметка была добавлена, создаем шаблон Mustache для добавления к странице. Вставляем его сразу перед полем ввода new-post, после чего размываем поле и возвращаем значение по умолчанию.

Вот то, чего вы так долго ждали! Вы можете теперь добавлять заметки в свой блокнот без обновления страницы. Ниже представлен снимок моего запроса, ответа и реакции. Щелчок по «+» отправляет запрос.

new-note

Новое сообщение появляется в базе данных даже без обращения к панели администратора.

note-in-admin

Редактирование заметок

ajax-actions.php

function notes_update_post(){
  if(current_user_can( 'edit_posts' )){
    extract($_POST);
 
    $p = array(
      'ID'            => $id,
      'post_title'    => $text,
      'post_author'   => get_current_user_id(),
      'post_content'  => ' ',
      'post_status'   => 'publish'
    );
 
    $post_id = wp_update_post($p);
 
    if($post_id) generate_response('post-updated', $id, $text);
 
  } else { echo $fail; }
  exit;
}

Функция вызывается при щелчке по галочке рядом с существующей заметкой. Мы используем wp_update_post() вместо wp_insert_post().

main.js

case "post-updated" :
 
  $('#post-' + response.id + ' input').blur();
 
break;

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

Удаление заметок

ajax-actions.php

function notes_delete_post(){
  if(current_user_can( 'delete_posts' )){
    extract($_POST);
 
    $result = wp_delete_post( $id );
 
    if(!false) generate_response('post-deleted', $id);
 
  } else { echo $fail; }
  exit;
}

Получаем ID, используем wp_delete_post() для удаления заметки. Если все прошло успешно, передаем ответ обратно вместе с ID удаляемой записи.

main.js

case "post-deleted" :
 
  $('#post-' + response.id).remove();
 
break;

Получаем ответ и удаляем соответствующий элемент на базе ID.

Готово!

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

complete-app

Это достаточно простое приложение. Вы можете себе представить, что было бы, если бы мы использовали более сложные структуры данных, произвольные типы записей и т.д.

Принудительная аутентификация

Единственное, что отсутствует в нашем приложении – принудительная аутентификация. Конечно, люди способны публично изучить ваше приложение, если вы не запретите им это делать. Если вы хотите ввести вынужденную регистрацию для просмотра и редактирования заметок, то в таком случае вам понадобится добавить несколько дополнительных строк кода, которые надо будет разместить в functions.php.

Аутентификация состоит из трех частей. Для начала, принудительный вход в систему. Затем редирект к главной странице вместо wp-admin. И, наконец, изменение стилей страницы входа, чтобы не было никаких связей с WP.

Принудительный вход

Вот действительно полезный фрагмент для вас. Его надо расположить в основании functions.php вашей темы:

// Require login for site
get_currentuserinfo();
global $user_ID;
if ($user_ID == '' && $_SERVER['PHP_SELF'] != '/wp-login.php') {
  header('Location: '.get_bloginfo('url').'/wp-login.php'); exit();
}

Этот фрагмент получает информацию, связанную с текущей сессией. Если ID пользователя не возвращен (т.е. вы не вошли в панель), и вы не находитесь на странице входа в панель, то вас перебрасывает на страницу входа. Попробуйте получить доступ к какой-либо странице при выходе из системы – у вас это не получится.

Редирект при входе

Как только пользователь входит в систему, мы хотим переместить его на главную страницу сайта вместо панели администратора. Следующий фрагмент позволяет сделать это:

//change login redirect to home url
function redirect_to_home(){
  return home_url();}
add_filter('login_redirect', 'redirect_to_home');

Изменение стилей страницы входа

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

function custom_login_style() {
  wp_enqueue_style( 'custom-login', TEMPL_PATH.'/css/custom-login.css' ); }
add_action( 'login_enqueue_scripts', 'custom_login_style' );

custom-login-page

Дополнение

Есть много других вещей, которые мы могли бы добавить к своему приложению, но у меня нет на это времени:

  • Использование WP Nonces для безопасности
  • Автоматическое обновление заметок
  • Уведомление о выходе в онлайн пользователя
  • Валидация

Мощь WordPress для создания приложений

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

Ресурсы

Источник: wpmu.org

Поделиться

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.