Статьи

API Rewrite: основы

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


WordPress, как и все системы управления контентом, решает, какой контент отображать, основываясь на переменных (обычно называемых переменными запроса), передаваемых ему. Например: http://example.com/index.php?category=3 сообщает WordPress, что мы ищем записи в категории с идентификатором 3, а http://example.com/index.php?feed=rss сообщает WordPress. Мы хотим, чтобы канал сайта в формате RSS.

К сожалению, это может оставить нас с довольно уродливыми URL:

1
http://example.com/index.php?post_type=portfolio&taxonomy=wordpress&portfolio=my-fancy-plugin

Вот где начинается переписывание WordPress. Это позволяет нам заменить вышеперечисленное на:

1
http://example.com/portoflio/wordpress/my-fancy-plugin

Который теперь не только намного более удобочитаем (и запоминаем), но и более оптимизирован для SEO. Это, в двух словах, что переписывает делать.


Теперь http://example.com/portoflio/wordpress/my-fancy-plugin не существует в виде каталога или файла. Так как же WordPress подает правильный контент? Когда WordPress получает «довольно постоянную ссылку», подобную приведенной выше, ему необходимо преобразовать это во что-то, что он понимает, а именно в объект запроса . Проще говоря, он должен взять симпатичный URL и сопоставить соответствующие части с правильной переменной запроса. Итак, для нашего примера:

1
http://example.com/portoflio/wordpress/my-fancy-plugin
  • post_type установлен в «портфолио»
  • portfolio-taxonomy установлена ​​на «WordPress»
  • portfolio установлено как «my-fancy-plugin» (название сообщения)

Тогда WordPress знает, что мы находимся после постов типа « portfolio » в терминологии таксономии « wordpress » « portfolio-taxonomy » с именем « my-fancy-plugin ». (Как вы уже догадались, первые два на самом деле излишни). WordPress затем выполняет этот запрос, выбирает соответствующий шаблон для отображения результатов и затем передает его зрителю. Но ясно, что WordPress не просто догадывается, как интерпретировать URL-адреса, это нужно сказать …

Предполагая, что вы можете включить и включить красивые постоянные ссылки на своей странице Настройки -> Постоянные ссылки ( минимальные требования см. В Кодексе — для WordPress на серверах Nginx есть этот подключаемый модуль ) — тогда все начинается с файла .htaccess . Это играет простую и все же значительную роль. WordPress включает в этот файл что-то похожее на следующее:

01
02
03
04
05
06
07
08
09
10
# BEGIN WordPress
   <IfModule mod_rewrite.c>
       RewriteEngine On
       RewriteBase /
       RewriteRule ^index\.php$ — [L]
       RewriteCond %{REQUEST_FILENAME} !-f
       RewriteCond %{REQUEST_FILENAME} !-d
       RewriteRule .
   </IfModule>
   # END WordPress

Это просто проверяет, существует ли файл или каталог на самом деле — и если это так, вы просто попадаете туда. Например:

1
http://example.com/blog/wp-content/uploads/2012/04/my-picture.png

Просто взял бы PNG-приложение my-picture.png . Но, как и в случае:

1
http://example.com/blog/portoflio/wordpress/my-fancy-plugin

Там, где каталог не существует — вы попадаете в файл WordPress index.php . Именно этот файл загружает WordPress.

На данный момент WordPress еще не знает, что вы ищете. После некоторой начальной загрузки WordPress и его настроек он запускает метод parse_request класса WP ( находится в файле class-wp.php ). Именно этот метод берет /portoflio/wordpress/my-fancy-plugin и преобразует его в понятный WordPress объект запроса ( почти он фактически устанавливает массив query_vars а затем $wp->query_posts превращает его в запрос).

Вкратце, эта функция сравнивает полученный URL ( /portoflio/wordpress/my-fancy-plugin ) с массивом «регулярных выражений». Это массив перезаписи — и он будет выглядеть примерно так:

1
2
3
4
5
6
category/(.+?)/page/?([0-9]{1,})/?$ => index.php?category_name=$matches[1]&paged=$matches[2]
   category/(.+?)/?$ => index.php?category_name=$matches[1]
   tag/([^/]+)/page/?([0-9]{1,})/?$=> index.php?tag=$matches[1]&paged=$matches[2]
   tag/([^/]+)/?$ => index.php?tag=$matches[1]
   ([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$ => index.php?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]
   (.+?)(/[0-9]+)?/?$ => index.php?pagename=$matches[1]&page=$matches[2]

Ключи этого массива являются регулярными выражениями, и полученный URL сравнивается с каждым по очереди, пока не будет найдено соответствие с шаблоном полученного URL. Соответствующее значение — то, как тогда интерпретируется URL. Массив $matches содержит захваченные значения (проиндексированные от 1) из сопоставления.

Например, посетив www.example.com/blog/tag/my-tag , WordPress будет искать первый шаблон, который соответствует « tag/my-tag ». С указанным выше массивом он соответствует третьему шаблону: tag/([^/]+)/?$ . Это говорит WordPress, что он должен интерпретировать URL как www.example.com/blog/index.php?tag=my-tag и, соответственно, архив my-tag обслуживается.

Конечно, WordPress позволяет вам настраивать этот массив, и остальная часть этого урока посвящена тому, как показать.


Ваш первый порт захода должен быть на странице настроек «Постоянная ссылка». На этой странице можно изменить правила для стандартного типа post «post» и таксономий « category » и « tags ». Параметр «по умолчанию» отключил довольно постоянные ссылки, но вы можете выбрать из списка предустановленных структур или создать пользовательскую структуру. Обратите внимание, что пользовательские структуры не должны содержать URL вашего сайта . WordPress позволяет изменять структуру постоянных %postname% добавляя в предоставленные теги, такие как %postname% (название сообщения), %year% (год публикации сообщения) и %author% (автор сообщения). Структура постоянной ссылки, такая как:

1
/%year%/%author%/%postname%/

Будет производить ссылку на пост, такой как:

1
www.example.com/2012/stephen/my-post

Документацию по этим параметрам можно найти в Кодексе WordPress . (Позже я покажу вам, как создавать свои собственные теги).

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

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

  • Просто зайдите на страницу Настройки -> Постоянная ссылка
  • Вызов flush_rewrite_rules() (рассматривается в части 2)

Что это делает? Напомним, что метод parse_request сравнивает запрос с массивом перезаписи. Этот массив живет в базе данных. Сброс правил перезаписи обновляет базу данных, чтобы отразить ваши изменения — и пока вы не сделаете это, они не будут распознаны. Но parse_request также записывает в файл .htaccess . Это делает это дорогостоящей операцией. Поэтому, хотя я не буду рассматривать использование flush_rewrite_rules() до второй части, я дам вам следующее предупреждение: не вызывайте flush_rewrite_rules при каждой загрузке страницы. Плагины должны вызывать это только тогда, когда плагин активирован и деактивирован .

add_rewrite_rule позволяет добавлять дополнительные правила в массив перезаписи. Эта функция принимает три аргумента:

  • rule — регулярное выражение, с которым сравнивается URL запроса
  • переписать — строка запроса, используемая для интерпретации правила. Массив $matches match содержит захваченные совпадения и начинается с индекса ‘1’.
  • позиция — « top » или « bottom ». Где разместить правило: вверху массива перезаписи или внизу. WordPress сканирует сверху вниз массив и останавливается, как только находит совпадение. Чтобы ваши правила имели приоритет над существующими правилами, вы должны установить для этого параметра значение « top ». По умолчанию это « bottom ».

Примечание: если вы используете add_rewrite_rule несколько раз, каждый с позицией « top » — первый вызов имеет приоритет над последующими вызовами.

Давайте предположим, что с нашими сообщениями связана дата события, и мы хотим, чтобы эта структура была: www.example.com/blog/the-olympics-begin/2012-07-27 интерпретирована как www.example.com/blog/index.php?postname=the-olympics-begin&eventdate=2012-07-27 тогда мы можем добавить это правило следующим образом:

1
2
3
4
5
6
7
8
function wptuts_add_rewrite_rules() {
       add_rewrite_rule(
           ‘^([^/]*)/([0-9]{4}-[0-9]{2}-[0-9]{2})/?$’ // String followed by a slash, followed by a date in the form ‘2012-04-21’, followed by another slash
           ‘index.php?pagename=$matches[1]&eventdate=$matches[2]’,
           ‘top’
       );
   }
   add_action( ‘init’, ‘wptuts_add_rewrite_rules’ );

Следующее будет интерпретировать www.example.com/olympics/2012/rowing как www.example.com/index.php?p=17&olymyear=2012&game=rowing

1
2
3
4
5
add_rewrite_rule(
       ‘^olympics/([0-9]{4})/([^/]*)’,
       ‘index.php?p=17&olymyear=$matches[1]&game=$matches[2]’,
       ‘top’
   );

Если вы не уверены в своих регулярных выражениях, вы можете найти это введение и этот инструмент полезным.

Вы можете подумать, что значение eventdate (2012-07-27 в приведенном выше примере), olymyear и game может быть доступно из внутренних get_query_var WordPress через get_query_var (так же, как get_query_var('paged') получает номер страницы, которую вы находятся на). Однако WordPress не распознает переменную eventdate автоматически, даже если она интерпретируется как переменная GET. Есть несколько способов заставить WordPress распознавать пользовательские переменные. Одним из них является использование фильтра query_vars как показано в разделе «Добавление пользовательской query_vars точки» ниже. В качестве альтернативы, мы можем пойти еще дальше и использовать add_rewrite_tag чтобы зарегистрировать пользовательский тег, например, по умолчанию %postname% и %year%

Эта функция принимает три аргумента:

  • имя тега — (с начальным и конечным%), например: %eventdate%
  • regex — регулярное выражение для проверки значения, например ‘ ([0-9]{4}-[0-9]{2}-[0-9]{2})
  • запрос — (необязательно), как интерпретируется тег, например, ‘ eventdate= ‘. Если указано, должно заканчиваться символом «=».
1
2
3
4
function wptuts_register_rewrite_tag() {
       add_rewrite_tag( ‘%eventdate%’, ‘([0-9]{4}-[0-9]{2}-[0-9]{2})’);
   }
   add_action( ‘init’, ‘wptuts_register_rewrite_tag’);

get_query_var('eventdate') вернет значение даты в URL-адресе, но вы также можете использовать тег %eventdate% в Настройках -> Постоянная ссылка (вместе со стандартным %year% , %postname% и т. Д.) И WordPress правильно его интерпретирует. К сожалению, когда генерируется постоянная ссылка на сообщение, WordPress не знает, как заменить %eventdate% на соответствующее значение: поэтому наши постоянные ссылки на сообщение заканчиваются следующим образом:

1
www.example.com/the-olympics-begin/%eventdate%

Нам нужно заменить %eventdate% на соответствующее значение, и мы можем сделать это, используя фильтр post_link . (В этом примере я предполагаю, что значение хранится в настраиваемом поле ‘ eventdate ‘).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
function wp_tuts_filter_post_link( $permalink, $post ) {
 
       // Check if the %eventdate% tag is present in the url:
       if ( false === strpos( $permalink, ‘%eventdate%’ ) )
           return $permalink;
 
       // Get the event date stored in post meta
       $event_date = get_post_meta($post->ID, ‘eventdate’, true);
 
       // Unfortunately, if no date is found, we need to provide a ‘default value’.
       $event_date = ( ! empty($event_date) ? $event_date : ‘2012-01-01’ );
 
       $event_date =urlencode($event_date);
 
       // Replace ‘%eventdate%’
       $permalink = str_replace( ‘%eventdate%’, $event_date , $permalink );
 
       return $permalink;
   }
   add_filter( ‘post_link’, ‘wp_tuts_filter_post_link’ , 10, 2 );

Во второй части этой серии я расскажу о пользовательских тегах для пользовательских типов записей.

Конечные точки — это теги, которые добавляются к URL (наиболее часто встречается /trackback/[value] ). Он имеет несколько других потенциальных применений: отображение различных шаблонов в зависимости от набора значений, пользовательских уведомлений и отображение сообщений в разных «форматах» (для печати, XML, JSON и т. Д.).

Вы можете создавать конечные точки с помощью add_rewrite_endpoint . Эта функция принимает два аргумента:

  • name — имя конечной точки, например, « json », « form » и т. д.
  • где — маска конечной точки, указывающая, где должна быть добавлена ​​конечная точка. Это должна быть одна из констант EP_ *, перечисленных ниже (или комбинация с использованием побитовых операторов). При регистрации пользовательских типов сообщений вы можете создать маску для этого типа сообщений:

Маски конечной точки по умолчанию:

  • EP_PERMALINK — для постоянных ссылок
  • EP_ATTACHMENT — для вложений
  • EP_DATE — для архивов даты
  • EP_YEAR — за год архивы
  • EP_MONTH — для месячных архивов
  • EP_DAY — для дневных архивов
  • EP_ROOT — для рута сайта
  • EP_COMMENTS — для комментариев
  • EP_SEARCH — для поисков
  • EP_CATEGORIES — для категорий
  • EP_TAGS — для тегов
  • EP_AUTHORS — для архива авторских постов
  • EP_PAGES — для страниц
  • EP_ALL — для всего

Конечные точки чрезвычайно гибки, вы можете использовать их с побитовыми операторами , например, вы можете добавить конечную точку для публикации и постоянных EP_PERMALINK | EP_PAGES страницы с помощью EP_PERMALINK | EP_PAGES EP_PERMALINK | EP_PAGES .

1
2
3
4
5
function wptuts_add_endpoints() {
       add_rewrite_endpoint(‘myendpoint’, EP_PERMALINK);
       add_rewrite_endpoint( ‘anotherendpoint’, EP_AUTHORS | EP_SEARCH);
   }
   add_action( ‘init’, ‘wptuts_add_endpoints’);

В качестве краткого примера, конечные точки могут быть полезны для отправки форм. Предположим, у нас есть страница контактной формы с именем contact-form и постоянной ссылкой: www.example.com/contact и нам нужны URL-адреса:

  • www.example.com/contact/submission/success — для отражения успешной отправки формы
  • www.example.com/contact/submission/error — для отражения неудачной отправки формы

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
   /**
   * Template Name: Contact Form
   */
   include(‘header.php’);?>
 
   <h1> My Simple Contact Form </h1>
   <?php if ( ‘success’ == get_query_var( ‘form’ ) ): ?>
       <div class=»message»>
           Your message has been sent!
       </div>
 
   <?php elseif( ‘error’ == get_query_var( ‘form’ )): ?>
       <div class=»message»>
           Oops!
       </div>
   <?php endif ?>
 
   <!
   <form method=’post’ action=»>
 
       <label> Your name: </label> <input type=»text» name=»wptuts_contact[name]» value=»»/>
       <label> Your message: </label> <textarea name=»wptuts_contact[message]» rows=»20″ cols=»30″></textarea>
 
       <!
       <?php wp_nonce_field(‘wptuts_send_message’,’wptuts_contact_nonce’);
 
       <input type=»hidden» name=»action» value=»wptuts_send_message»/>
 
       <!
       <style scoped>.wptuts-e-mail-conformation{display:none}</style>
       <span class=»wptuts-e-mail-conformation»><label for=»email-confirmation»>Email confirmation:</label><input type=»text» name=»wptuts_contact[confirmation]» value=»» />
 
       <input type=’submit’ name=’wptuts_contact[send]’ value=’Send’ />
   </form>
 
   <?php include(‘footer.php’);?>

(В случае, если вам интересно, что мед имеет в виду этот самый базовый метод ловли спама, описанный здесь . Это, конечно, не дурак, но правильная обработка форм и защита от спама здесь не обсуждаются). Теперь мы создаем нашу конечную точку:

1
2
3
4
function wptuts_add_endpoint() {
       add_rewrite_endpoint( ‘form’, EP_PAGES );
   }
   add_action( ‘init’, ‘wptuts_add_endpoint’);

Затем мы добавляем нашу переменную form в массив распознанных переменных:

1
2
3
4
5
function wptuts_add_queryvars( $query_vars ) {
       $query_vars[] = ‘form’;
       return $query_vars;
   }
   add_filter( ‘query_vars’, ‘wptuts_add_queryvars’ );

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function wptuts_form_handler() {
 
       // Are we wanting to process the form
       if( ! isset( $_POST[‘action’] ) || ‘wptuts_send_message’ != $_POST[‘action’] )
           return;
 
       // ID of the contact form page
       $form_id = 2163;
       $redirect= get_permalink($form_id);
 
       // Check nonces
       $data = $_POST[‘wptuts_contact’];
 
       if( !isset($_POST[‘wptuts_contact_nonce’] ) || !wp_verify_nonce($_POST[‘wptuts_contact_nonce’],’wptuts_send_message’) ) {
           // Failed nonce check
           $redirect .= ‘form/error’;
           wp_redirect($redirect);
           exit();
       }
 
       if( !empty( $data[‘confirmation’] ) ) {
           // Bees in the honey…
           $redirect .= ‘form/error’;
           wp_redirect($redirect);
           exit();
       }
 
       // Santize and validate data etc.
 
       // Then actually do something with the sanitized data
 
       // Successful!
       $redirect .= ‘form/success’;
       wp_redirect($redirect);
       exit();
   }
   add_action( ‘init’, ‘wptuts_form_handler’);

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

Если включены постоянные ссылки, WordPress автоматически создает красивые URL для канала вашего сайта: www.example.com/feed/rss . Функция add_feed позволяет вам создать пользовательский канал, который, если включены красивые постоянные ссылки, также будет иметь «симпатичный» URL. Эта функция принимает два аргумента:

  • имя канала — имя канала, как оно будет отображаться в feed/[feed-name]
  • обратный вызов канала — функция, отвечающая за отображение содержимого канала.

Следующее предназначено в качестве примера add_feed и предоставляет очень простой пользовательский канал.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function wptuts_events_feed_callback() {
       $custom_feed = new WP_Query(array(‘meta_key’ => ‘eventdate’));
 
       header(‘Content-Type: ‘ . feed_content_type(‘rss-http’) . ‘; charset=’ . get_option(‘blog_charset’), true);
       echo ‘<?xml version=»1.0″ encoding=»‘.get_option(‘blog_charset’).'»?’.’>’;
 
       <rss version=»2.0″>
       <channel>
           <title>My custom feed</title>
           <link><?php bloginfo_rss(‘url’) ?></link>
           <description><?php bloginfo_rss(«description») ?></description>
           <lastBuildDate><?php echo mysql2date(‘D, d MYH:i:s +0000’, get_lastpostmodified(‘GMT’), false);
           <language><?php echo get_option(‘rss_language’);
           <?php if($custom_feed->have_posts()): ?>
               <?php while( $custom_feed->have_posts()): $custom_feed->the_post();
                   <item>
                       <title><?php the_title_rss() ?></title>
                       <link><?php the_permalink_rss() ?></link>
                       <pubDate><?php echo mysql2date(‘D, d MYH:i:s +0000’, get_post_time(‘Ymd H:i:s’, true), false);
                       <guid isPermaLink=»false»><?php the_guid();
                       <description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
                   </item>
               <?php endwhile;
           <?php endif;
       </channel>
       </rss>
   <?php
   }
 
   function wptuts_add_feed() {
       add_feed(‘events’, ‘wptuts_events_feed_callback’);
   }
   add_action( ‘init’, ‘wptuts_add_feed );

После очистки постоянных ссылок канал будет доступен по адресу www.example.com/feed/events .


После того, как вы добавили некоторые свои собственные правила перезаписи (и сбросили их), вы, вероятно, захотите проверить, работают ли они должным образом — а если нет, выясните, что происходит не так. Для этого я настоятельно рекомендовал подключаемый модуль Monkeyman Rewrite Analyzer — бесплатный подключаемый модуль, доступный в репозитории WordPress. После активации этот плагин добавляет страницу в раздел «Инструменты», где перечислены все ваши правила перезаписи.

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

Веселитесь и следите за частью 2, которая скоро появится!

Обратите внимание: в настоящее время в нашей подсветке синтаксиса есть ошибка, которая отображает » empty() » как » emptyempty() «. Не забудьте соответствующим образом изменить свой код.