Запис #10 "Таксономія у WordPress. Створення своїх типів через код"

Додано: 2015-10-23 03:08:05 'admin

WordPress багатий своїми можливостями розширяти типи записів, створювати нові категорії та параметри постів. За допомогою гнучкої системи хуків та функціоналу коду WordPress можна добитись практично любої мети, яка пов'язана із записами. 

Раніше я вже описував загальні властивості таксономій у WordPress та як за допомогою плагінів можна розширити можливості системи. Кожен автор плагіну по таксономіям намагається вкласти у свій продукт максимальну кількість функціоналу, яка буде доступна із консолі користувачу. Це зроблено для того, щоб полегшити роботу людям, які або не знають, або не мають часу, або просто лінуються писати свій код. Та я знаю точно, що ні один плагін не замінить вам написаного власноруч коду. Хоча, це тільки моя точка зору.. І я вважаю так, тому що кожен плагін накладає свої правила та обмежує вас своїми можливостями. А в коді ви обмежуєтесь тільки можливостями мови, на якій пишете. Крім того ви по своїй волі приймаєте чужі помилки (якщо вони є), які можна не помічати аж до трагічних подій. А далі.. А далі читай ліцензію.. Хоч це треба робити в першу чергу.

Вибір місця для коду

Отже. В цій темі я спробую відтворити задачу із шкарпетками та варенням, використовуючи функції та хуки WordPress.

Для зручності спочатку оберу, де буде зберігатись мій код. Варіантів є декілька:
- створити окремий плагін для вмикання та вимикання можливостей;
- додати код безпосередньо до файлу функцій активної теми;
- створити код в окремому файлі із можливістю підключення його там, де це необхідно.

Перший варіант універсальний. Тобто код буде працювати при зміні шаблону. Буде мати можливість вимикання при необхідності та гнучкості оновлення коду. Але потребує додаткових знань створення плагінів.

Другий варіант самий найпростіший. Відкривається файл functions.php та у його кінець пишеться потрібний код. Тут проблема полягає у наступному пошуку кода, коли він буде необхідний, наприклад, при зміні активного шаблону або при редагуванні додаткових полів для категорій. Та й взагалі буде капарно виглядати сам файл.

Третій варіант самий оптимальний для цього прикладу, як на мій погляд. У теці inc активного шаблону (у мене стандартний 2015) створюється новий файл, назва якого може бути довільною. Наприклад, items.php. В нього буде додано потрібний код. А у файлі functions.php у кінці файла у одну строку прописується шлях до нього та функція підключення. Таким чином не потрібні знання по створенню плагіна. Відповідно зменшується об'єм коду. Не засмічується файл functions.php активного  шаблону. Легко віднайти та відредагувати код.

Додавання коду

Прописую в кінець functions.php:

require get_template_directory() . '/inc/items.php';

Самий код items.php:

<?php
//Крок №1. Створення нового типу записів.
//Хук на ініціалізацію. Створює новий тип записів. add_action( 'init', 'codex_items_init' ); function codex_items_init() { //Маркери для позначення назв нового типу $labels = array( 'name' => "Товар", 'singular_name' => "Товар", 'menu_name' => "Товар", 'name_admin_bar' => "Товар", 'add_new' => "Додати товар", 'add_new_item' => "Новий товар", 'new_item' => "Новий товар", 'edit_item' => "Редагувати товар", 'view_item' => "Переглянути товар", 'all_items' => "Увесь товар", 'search_items' => "Пошук товару", 'parent_item_colon' => "Батьківський рівень для товару", 'not_found' => "Товар не знайдено", 'not_found_in_trash' => "В кошику товар не знайдено" ); //Аргументи, які визначають новий тип. $args = array( 'labels' => $labels, //Тут масив із мітками 'description' => __( 'Description.', 'your-plugin-textdomain' ), 'public' => true, //Доступний в консолі 'publicly_queryable' => true, //Є доступ із запитів та шаблонів 'show_ui' => true, //Відкрите редагування в консолі 'show_in_menu' => true, //Відображається як пункт в меню 'query_var' => true, //Запити ввімкнено 'rewrite' => array( 'slug' => 'items' ), //префікс для посилань доступу 'capability_type' => 'post', //Права доступу як у звичайного типу записів 'has_archive' => true, //Включення сторінок архіву 'hierarchical' => false, //Не є ієрархічного типу 'menu_position' => null, //В меню буде у самому низу 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ), //Доступні блоки для редагування 'taxonomies' => array( 'category_items' ) //Зв'язані таксономії ); register_post_type( 'items', $args ); } //Крок №2. Створення таксономії - категорій товару. // Хук на ініціалізацію із створенням таксономії add_action( 'init', 'create_category_items_taxonomies');
function create_category_items_taxonomies() { //Маркери таксономії $labels = array( 'name' => "Категорії товару", 'singular_name' => "Категорія товару", 'search_items' => "Пошук категорії товару", 'all_items' => "Всі категорії товару", 'parent_item' => "Рівень вище для категорії товару", 'parent_item_colon' => "Рівень вище для категорії товару:", 'edit_item' => "Редагування категорії товару", 'update_item' => "Оновлення категорії товару", 'add_new_item' => "Додати нову категорію товару", 'new_item_name' => "Нова категорія товару", 'menu_name' => "Категорія товару", ); //аргументи таксономії $args = array( 'hierarchical' => true, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'rewrite' => array( 'slug' => 'category_items' ), ); //реєстрація таксономії register_taxonomy( 'category_items', array( 'items' ), $args ); } //Крок №3. Створення зв'язків між додатковими полями та об'єктами таксономій.
//Хук на подію додавання додаткових полів для запису. add_action( 'add_meta_boxes', 'source_for_jam'); function source_for_jam() { //Так як функція повинна видавати додаткові поля тільки для варення - йде перевірка категорії if( ! has_term( 'Варення', 'category_items' ) ){ return; } add_meta_box( 'myplugin_sectionid', 'Параметри варення', 'source_for_jam_callback', 'items' ); } /** * Callback функція для виводу HTML користувачу * */ function source_for_jam_callback( $post ) { // Генерація поля hidden nonce для безпеки wp_nonce_field( 'source_for_jam_save', 'myplugin_meta_box_nonce' ); $value_source = get_post_meta( $post->ID, 'source-jam', true ); //Отримання поточних даних по ключу з БД $value_volume = get_post_meta( $post->ID, 'volume-jam', true ); echo '<label for="source_for_jam"> З чого зроблене варення:<br />'; echo '<input type="text" id="source_for_jam" name="source_for_jam" value="' . esc_attr( $value_source ) . '" size="25" /><br />'; echo '<label for="volume_for_jam"> Об\'єм тари (л.):<br />'; echo '<input type="text" id="volume_for_jam" name="volume_for_jam" value="' . esc_attr( $value_volume ) . '" size="25" />'; } add_action( 'save_post', 'source_for_jam_save' ); /** * Коли йде збереження запису, выдбувається і паралельне збереження значення додаткового поля * */ function source_for_jam_save( $post_id ) { // Перевірка наявність nonce коду. if ( ! isset( $_POST['myplugin_meta_box_nonce'] ) ) { return; } // Перевірка правильності nonce коду. if ( ! wp_verify_nonce( $_POST['myplugin_meta_box_nonce'], 'source_for_jam_save' ) ) { return; } // Якщо форма із автозбереженням - ніяких дій не потрібно. if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } // Перевірка прав користувача. if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) { if ( ! current_user_can( 'edit_page', $post_id ) ) { return; } } else { if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } } /* OK, тепер все готово до збереження. */ // Перевірка, чи є поле з якого необхідно зберегти дані. if ( ! isset( $_POST['source_for_jam'] ) ) { return; } // Отримання даних. $my_data = sanitize_text_field( $_POST['source_for_jam'] ); // Збереження змін в БД. update_post_meta( $post_id, 'source-jam', $my_data ); } //Крок №4. Створення аналогічного мета боксу для шкарпеток add_action( 'add_meta_boxes', 'source_for_socks'); /** * Створення циклу, який буде обходити масив із типів, на яких потрібно вивести додаткове поле */ function source_for_socks() { //Так як функція повинна видавати додаткові поля тільки для шкарпеток - йде перевірка категорії if( ! has_term( 'Шкарпетки', 'category_items' ) ){ return; } add_meta_box( 'myplugin_sectionid', 'Параметри шкарпеток', 'source_for_socks_callback', 'items' ); } /** * Callback функція для виводу HTML користувачу * */ function source_for_socks_callback( $post ) { // Генерація поля hidden nonce для безпеки wp_nonce_field( 'source_for_socks_save', 'myplugin_meta_box_nonce' ); $value_source = get_post_meta( $post->ID, 'color-socks', true ); //Отримання поточних даних по ключу з БД $value_volume = get_post_meta( $post->ID, 'volume-socks', true ); echo '<label for="color_for_socks"> Колір:<br />'; echo '<input type="text" id="color_for_socks" name="color_for_socks" value="' . esc_attr( $value_source ) . '" size="25" /><br />'; echo '<label for="volume_for_socks"> Розмір:<br />'; echo '<input type="text" id="volume_for_socks" name="volume_for_socks" value="' . esc_attr( $value_volume ) . '" size="25" />'; } add_action( 'save_post', 'source_for_socks_save' ); /** * Коли йде збереження запису, выдбувається і паралельне збереження значення додаткового поля * */ function source_for_socks_save( $post_id ) { // Перевірка наявність nonce коду. if ( ! isset( $_POST['myplugin_meta_box_nonce'] ) ) { return; } // Перевірка правильності nonce коду. if ( ! wp_verify_nonce( $_POST['myplugin_meta_box_nonce'], 'source_for_socks_save' ) ) { return; } // Якщо форма із автозбереженням - ніяких дій не потрібно. if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } // Перевірка прав користувача. if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) { if ( ! current_user_can( 'edit_page', $post_id ) ) { return; } } else { if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } } /* OK, тепер все готово до збереження. */ // Отримання даних по основі варення $value_color = sanitize_text_field( $_POST['color_for_socks'] ); // Збереження змін в БД. update_post_meta( $post_id, 'color-socks', $value_color ); // Отримання даних по обєму $value_volume = sanitize_text_field( $_POST['volume_for_socks'] ); // Збереження змін в БД. update_post_meta( $post_id, 'volume-socks', $value_volume ); }

Опис коду

Код у ~240 рядків зробив те, що плагін вагою в 7,8Mb (плагін Types). Але. У ці ~240 рядків додана можливість гнучкого управління та редагування. У плагіна також є така можливість, але часто-густо це великі форми із, часом, не зрозумілим описом. Що ж. Залишу все-таки цю тему на розсуд кожного. 

Трошки по коду. Код розбито на 3 кроки:
1-й крок - створення власного типу записів.
2-й крок - створення таксономії, яка прив'язується до типу зписів. Після цього кроку стає доступним створення своїх категорій у консолі.
3-й та 4-й кроки - реалізація відображення/збереження/оновлення додаткових полів. При чому тут використовується перевірка категорії товару. І для кожного з товару передбаченні свої додаткові поля. 

Не зручністю даного коду є те, що при додаванні або зміні категорій товару - потрідно підредактовувати код для їх потреб (перевірка категорії товару та особисті додаткові поля).

Результат виконання коду:
 

Використанні функції WordPress:

- add_action()
- register_post_type()
- register_taxonomy()
- wp_nonce_field()
- get_post_meta()
- wp_verify_nonce()
- current_user_can()
- sanitize_text_field()
- update_post_meta()
- has_term()
- add_meta_box()

Використані хуки:

- init
- add_meta_boxes
- save_post
- add_meta_boxes

Прикріплені файли:

items.php

P.S. Під час перевірки роботи коду було виявленно, що після переходу по посиланню для перегляду категорій не відображаються елементи категорій. Це пов'язано із тим, що слеги таксономій WordPress зчитує із БД. Так як у коді використане динамічне створення таксономій, то необхідно перейти за адресою "Налаштування"->"Постійні посилання" та просто натиснути на кнопку "Зберегти зміни". БЕЗ ЗМІН У САМІЙ ФОРМІ.
 

Коментарі: