- підключення
- Метапол в адмінці
- Як створити метабокси з метапол?
- Тонка настройка виведення
- Корисні посилання
Є багато плагінів для SEO, але майже у всіх з них головне завдання - це створити SEO мета-теги (метадані) для сторінки: title, description, robots, Open Graph. Іноді є сенс не підключати подібні плагіни, а використовувати свій невеликий код - з ним простіше управлятися і вирішувати нестандартні завдання ... У цій статті я ділюся своїм «велосипедом» в цій галузі.
Код нижче був написаний вже давно, для статті: Порівняння СЕО плагінів platinum SEO Pack і All in One SEO Pack . І, незважаючи на те що є плагіни, раз у раз з'являється необхідність користуватися цим кодом. Він використовується іноді, як альтернатива, і судячи з коментарів це буває потрібно не тільки мені ... Тому було прийнято стратегічне рішення винести цей код в окрему статтю і підтримувати його вже тут.
Якщо ви не розбираєтеся в PHP, то настійно рекомендую використовувати SEO плагіни - це набагато зручніше! Втім, іноді плагіни зручніше і для тих, хто знає PHP, я допустимо не завжди юзаю цей код, і плагінами на кшталт SEO Yoast не гребують ...
Базова задача SEO плагінів - це дати можливість створювати чотири метапол для сторінки: title, description, robots і keywords. А також створення додаткових Open Graph даних.
Код, який все це реалізує (див. Коментарі в коді):
// видалимо стандартний висновок title і викличемо свій remove_action ( 'wp_head', '_wp_render_title_tag', 1); add_action ( 'wp_head', 'kama_render_seo_tags', 1); function kama_render_seo_tags () {// remove_theme_support ( 'title-tag'); // не обов'язково echo '<title>'. kama_meta_title ( '-'). '</ title>'. "\ n \ n"; echo kama_meta_description (); echo kama_meta_keywords (); echo kama_meta_robots (); echo kama_og_meta (); // Open Graph, twitter дані} / ** * Open Graph, twitter дані в <head>. * Документація: http://ogp.me/ * * @version 7 * / function kama_og_meta () {$ obj = get_queried_object (); // тільки для записів або термінів if (isset ($ obj-> post_type)) $ post = $ obj; elseif (isset ($ obj-> term_id)) $ term = $ obj; $ Is_post = isset ($ post); $ Is_term = isset ($ term); $ Title = kama_meta_title ( '-'); $ Desc = preg_replace ( '/^.+content="([^"]*)".*$/s', '$ 1', kama_meta_description ()); // Open Graph $ els = array (); $ els [ 'og: locale'] = '<meta property = "og: locale" content = "'. get_locale (). ' "/>'; $ els [ 'og: site_name'] = '<meta property =" og: site_name "content ="'. esc_attr (get_bloginfo ( 'name')). ' "/>'; $ els [ 'og: title'] = '<meta property =" og: title "content ="'. esc_attr ($ title). ' "/>'; $ els [ 'og: description'] = '<meta property =" og: description "content ="'. esc_attr ($ desc). ' "/>'; $ els [ 'og: type'] = '<meta property =" og: type "content ="'. (is_singular ()? 'article': 'object') . ' "/>'; if ($ is_post) $ pageurl = get_permalink ($ post); if ($ is_term) $ pageurl = get_term_link ($ term); if (isset ($ pageurl)) $ els [ 'og: url '] =' <meta property = "og: url" content = " '. esc_attr ($ pageurl). ' "/>'; if (apply_filters ( 'kama_og_meta_show_article_section', true)) {if (is_singular () && $ post_taxname = get_object_taxonomies ($ post-> post_type)) {$ post_terms = get_the_terms ($ post , reset ($ post_taxname)); if ($ post_terms && $ post_term = array_shift ($ post_terms)) $ els [ 'article: section'] = '<meta property = "article: section" content = "'. esc_attr ($ post_term-> name). ' "/>';}} // image if ( 'image') {$ fn__get_thumb_id_from_text = function ($ text) {if (preg_match ( '/ <img + src * = * [ \ ' "] ([^ \'"] +) [\ ' "] /', $ text, $ mm) && ($ mm [1] {0} === '/' || strpos ($ mm [ 1], $ _SERVER [ 'HTTP_HOST']))) {$ name = basename ($ mm [1]); $ Name = preg_replace ( '~ - [0-9] + x [0-9] + (? = \ .. {2,6}) ~', '', $ name); // видалимо розмір (-80x80) $ name = preg_replace ( '~ \. [^.] + $ ~', '', $ Name); // видалимо розширення $ name = sanitize_title (sanitize_file_name ($ name)); // приведемо до стандартного вигляду global $ wpdb; $ Thumb_id = $ wpdb-> get_var ($ wpdb-> prepare ( "SELECT ID FROM $ wpdb-> posts WHERE post_name =% s AND post_type = 'attachment'", $ name)); } Return empty ($ thumb_id)? 0: $ thumb_id; }; $ Thumb_id = 0; if ($ is_post) {// мініатюра поста if (! $ thumb_id = get_post_thumbnail_id ($ post)) {// вкладення з контенту поста if (apply_filters ( 'kama_og_meta_thumb_id_find_in_content', true)) {if (! $ thumb_id = $ fn__get_thumb_id_from_text ( $ post-> post_content)) {// перше вкладення поста $ attach = get_children ([ 'numberposts' => '1', 'post_mime_type' => 'image', 'post_type' => 'attachment', 'post_parent' = > $ post-> ID]); if ($ attach && $ attach = array_shift ($ attach)) $ thumb_id = $ attach-> ID; }}}} Elseif ($ is_term) {if (! $ Thumb_id = get_term_meta ($ term-> term_id, '_thumbnail_id', 1)) {$ thumb_id = $ fn__get_thumb_id_from_text ($ term-> description); }} $ Thumb_id = apply_filters ( 'kama_og_meta_thumb_id', $ thumb_id); if ($ thumb_id) {if (is_numeric ($ thumb_id)) list ($ image_url, $ img_width, $ img_height) = image_downsize ($ thumb_id, 'full'); elseif (is_array ($ thumb_id)) list ($ image_url, $ img_width, $ img_height) = $ thumb_id; else $ image_url = $ thumb_id; // Open Graph image $ els [ 'og: image'] = '<meta property = "og: image" content = "'. Esc_url ($ image_url). '" />'; if (isset ($ img_width)) $ els [ 'og: image: width'] = '<meta property = "og: image: width" content = "'. (int) $ img_width. '" />'; if (isset ($ img_height)) $ els [ 'og: image: height'] = '<meta property = "og: image: height" content = "'. (int) $ img_height. '" />'; }} // twitter $ els [ 'twitter: card'] = '<meta name = "twitter: card" content = "summary" />'; $ Els [ 'twitter: description'] = '<meta name = "twitter: description" content = "'. Esc_attr ($ desc). '" />'; $ Els [ 'twitter: title'] = '<meta name = "twitter: title" content = "'. Esc_attr ($ title). '" />'; if (isset ($ image_url)) $ els [ 'twitter: image'] = '<meta name = "twitter: image" content = "'. esc_url ($ image_url). '" />'; $ Els = apply_filters ( 'kama_og_meta_elements', $ els); return "\ n \ n". implode ( "\ n", $ els). "\ n \ n"; } / ** * Виводить заголовок сторінки <title> * * Для міток і категорій вказується в налаштуваннях, в описі: [title = Заголовок]. * Для записів, якщо потрібно, щоб заголовок сторінки відрізнявся від заголовка запису, * створіть довільне поле title і впишіть туди довільний заголовок. * * @Version 4.8 * * @param string $ sep роздільник * @param true | false $ add_blog_name додавати чи назву блогу в кінець заголовка для архівів. * / Function kama_meta_title ($ sep = ' »', $ add_blog_name = true) {static $ cache; if ($ cache) return $ cache; global $ post; $ L10n = apply_filters ( 'kama_meta_title_l10n', array ( '404' => 'Помилка 404: такої сторінки не існує', 'search' => 'Результати пошуку за запитом:% s', 'compage' => 'Коментарі% s ',' author '=>' Статті автора:% s ',' archive '=>' Архів за ',' paged '=>' (сторінка% d) ',)); $ Parts = array ( 'prev' => '', 'title' => '', 'after' => '', 'paged' => '',); $ Title = & $ parts [ 'title']; // спростимо $ after = & $ parts [ 'after']; // спростимо if (0) {} // 404 elseif (is_404 ()) {$ title = $ l10n [ '404']; } // пошук elseif (is_search ()) {$ title = sprintf ($ l10n [ 'search'], get_query_var ( 's')); } // головна elseif (is_front_page ()) {if (is_page () && $ title = get_post_meta ($ post-> ID, 'title', 1)) {// $ title визначено} else {$ title = get_bloginfo ( ' name '); $ After = get_bloginfo ( 'description'); }} // окрема сторінка elseif (is_singular () || (is_home () &&! Is_front_page ()) || (is_page () &&! Is_front_page ())) {$ title = get_post_meta ($ post-> ID, 'title ', 1); // вказаний title у записи в пріоритеті if (! $ Title) $ title = apply_filters ( 'kama_meta_title_singular', '', $ post); if (! $ title) $ title = single_post_title ( '', 0); if ($ cpage = get_query_var ( 'cpage')) $ parts [ 'prev'] = sprintf ($ l10n [ 'compage'], $ cpage); } // архів типу поста elseif (is_post_type_archive ()) {$ title = post_type_archive_title ( '', 0); $ After = 'blog_name'; } // таксономії elseif (is_category () || is_tag () || is_tax ()) {$ term = get_queried_object (); $ Title = get_term_meta ($ term-> term_id, 'title', 1); if (! $ title) {$ title = single_term_title ( '', 0); if (is_tax ()) $ parts [ 'prev'] = get_taxonomy ($ term-> taxonomy) -> labels-> name; } $ After = 'blog_name'; } // архів автора elseif (is_author ()) {$ title = sprintf ($ l10n [ 'author'], get_queried_object () -> display_name); $ After = 'blog_name'; } // архів дати elseif ((get_locale () === 'ru_RU') && (is_day () || is_month () || is_year ())) {$ rus_month = array ( '', 'січні', 'лютий ',' Март ',' Апрель ',' травня ',' червня ',' липні ',' серпня ',' вересня ',' жовтня ',' листопаді ',' грудня '); $ Rus_month2 = array ( '', 'січні', 'лютий', 'Март', 'Апрель', 'травня', 'червня', 'липні', 'серпня', 'вересня', 'Жовтня', 'листопаді ',' грудня '); $ Year = get_query_var ( 'year'); $ Monthnum = get_query_var ( 'monthnum'); $ Day = get_query_var ( 'day'); if (is_year ()) $ dat = "$ year рік"; elseif (is_month ()) $ dat = "$ rus_month [$ monthnum] $ year року"; elseif (is_day ()) $ dat = "$ day $ rus_month2 [$ monthnum] $ year року"; $ Title = sprintf ($ l10n [ 'archive'], $ dat); $ After = 'blog_name'; } // інші архіви else {$ title = get_the_archive_title (); $ After = 'blog_name'; } // номера сторінок для пагінацію і ділення записи $ pagenum = get_query_var ( 'paged')?: Get_query_var ( 'page'); if ($ pagenum) $ parts [ 'paged'] = sprintf ($ l10n [ 'paged'], $ pagenum); // дозволяє фільтрувати title як завгодно. Сам заголово // $ parts містить масив з елементами: prev - текст до, title - заголовок, after - текст після $ parts = apply_filters_ref_array ( 'kama_meta_title_parts', array ($ parts, $ l10n)); if ($ after == 'blog_name') $ after = $ add_blog_name? get_bloginfo ( 'name'): ''; // додамо пагінацію в title if ($ parts [ 'paged']) {$ parts [ 'title']. = "{$ Parts [ 'paged']}"; unset ($ parts [ 'paged']); } $ Title = implode ( ''. Trim ($ sep). '', Array_filter ($ parts)); // $ title = apply_filters ( 'kama_meta_title', $ title); $ Title = wptexturize ($ title); $ Title = esc_html ($ title); return $ cache = $ title; } / ** * Виводить метатег description. * * Для елементів таксономій: метапол description або в описі такої шоткод [description = текст опису] * У постів спочатку перевіряється, метапол description, або цитата, або початкова частина контенту. * Цитата або контент обрізаються до зазначеного в $ maxchar символів. * * @Param string $ home_description Вказується опис для головної сторінки сайту. * @Param int $ maxchar Максимальна довжина опису (в символах). * * @Version 2.2.1 * / function kama_meta_description ($ home_description = '', $ maxchar = 260) {static $ cache; if ($ cache) return $ cache; global $ post; $ Cut = true; $ Desc = ''; // front if (is_front_page ()) {// коли для головної встановлена сторінка if (is_page () && $ desc = get_post_meta ($ post-> ID, 'description', true)) {$ cut = false; } If (! $ Desc) $ desc = $ home_description?: Get_bloginfo ( 'description', 'display'); } // singular elseif (is_singular ()) {if ($ desc = get_post_meta ($ post-> ID, 'description', true)) $ cut = false; if (! $ desc) $ desc = $ post-> post_excerpt?: $ post-> post_content; $ Desc = trim (strip_tags ($ desc)); } // term elseif (is_category () || is_tag () || is_tax ()) {$ term = get_queried_object (); $ Desc = get_term_meta ($ term-> term_id, 'meta_description', true); if (! $ desc) $ desc = get_term_meta ($ term-> term_id, 'description', true); $ Cut = false; if (! $ desc && $ term-> description) {$ desc = strip_tags ($ term-> description); $ Cut = true; }} $ Origin_desc = $ desc; if ($ desc = apply_filters ( 'kama_meta_description_pre', $ desc)) {$ desc = str_replace (array ( "\ n", "\ r"), '', $ desc); $ Desc = preg_replace ( '~ \ [[^ \]] + \] (?! \ () ~', '', $ Desc); // видаляємо шоткоди. Ми залишаємо маркдаун [foo] (URL) if ($ cut ) {$ char = mb_strlen ($ desc); if ($ char> $ maxchar) {$ desc = mb_substr ($ desc, 0, $ maxchar); $ words = explode ( '', $ desc); $ maxwords = count ($ words) - 1; // прибираємо останнє слово, воно в 90% випадків неповне $ desc = join ( '', array_slice ($ words, 0, $ maxwords)). '...';}} $ desc = preg_replace ( '/ \ s + / s', '', $ desc);} if ($ desc = apply_filters ( 'kama_meta_description', $ desc, $ origin_desc, $ cut, $ maxchar)) return $ cache = '<meta name = "description" content = " '. esc_attr (trim ($ desc)).'" />'."\n "; return $ cache = '';} / ** * Метатег robots * * Щоб задати свої атрибути метатега robots записи, створіть довільне поле з ключем robots * і необхідним значенням, наприклад: noindex, nofollow * * Вкажіть параметр $ allow_types, щоб дозволити індексацію типів сторінок. * * @ $ Allow_types Які типи сторінок потрібно індексувати (через кому): * cpage, is_category, is_tag, is_tax, is_author, is_year, is_month, * is_attachment, is_day, is_search, is_feed, is_post_type_archive, is_paged * (можна використовувати будь-які умовні теги у вигляді рядка) * cpage - сторінки коментарів * @ $ robots Як закривати індексацію: noindex, nofollow * * version 0.6 * / function kama_meta_robots ($ allow_types = null, $ robots = 'noindex, nofollow ') {global $ post; if (null === $ allow_types) $ allow_types = 'cpage, is_category, is_attachment, is_tag, is_tax, is_paged, is_post_type_archive'; if ((is_home () || is_front_page ()) &&! is_paged ()) return; if (is_singular ()) {// якщо це не вкладення або вкладення але воно дозволено if (! is_attachment () || false! == strpos ($ allow_types, 'is_attachment')) {$ robots = get_post_meta ($ post-> ID, 'robots', true); }} Else {$ types = preg_split ( '~ [,] + ~', $ allow_types); $ Types = array_filter ($ types); foreach ($ types as $ type) {if ($ type == 'cpage' && strpos ($ _ SERVER [ 'REQUEST_URI'], '/ comment-page')) $ robots = false; elseif (function_exists ($ type) && $ type ()) $ robots = false; }} $ Robots = apply_filters ( 'kama_meta_robots_close', $ robots); if ($ robots) return "<meta name = \" robots \ "content = \" $ robots \ "/> \ n"; } / ** * Генерує метатег keywords для head частини сайту * * Щоб задати свої keywords для запису, створіть довільне поле keywords і впишіть в значення необхідні ключові слова. * Для постів (post) ключові слова генеруються з міток і назви категорій, якщо не вказано довільне поле keywords. * * Для міток, категорій і довільних таксономій, ключові слова вказуються в описі, в шоткоде: [keywords = слово1, слово2, слово3] * * @ $ home_keywords: Для головної, ключові слова вказуються в першому параметрі: kama_meta_keywords ( 'слово1, слово2 , слово3 '); * @ $ Def_keywords: наскрізні ключові слова - вкажемо і вони будуть додаватися до решти на всіх сторінках * * version 0.7 * / function kama_meta_keywords ($ home_keywords = '', $ def_keywords = '') {global $ wp_query, $ post; $ Out = ''; if (is_front_page ()) {$ out = $ home_keywords; } Elseif (is_singular ()) {$ out = get_post_meta ($ post-> ID, 'keywords', true); // для постів вказуємо ключами мітки і категорії, якщо не вказані ключі в довільному поле if (! $ Out && $ post-> post_type == 'post') {$ res = wp_get_object_terms ($ post-> ID, array ( 'post_tag ',' category '), array (' orderby '=>' none ')); // отримуємо категорії і мітки if ($ res &&! Is_wp_error ($ res)) foreach ($ res as $ tag) $ out. = ", $ Tag-> name"; $ Out = ltrim ($ out, ','); }} Elseif (is_category () || is_tag () || is_tax ()) {$ term = get_queried_object (); // wp 4.4 if (function_exists ( 'get_term_meta')) {$ out = get_term_meta ($ term-> term_id, "keywords", true); } Else {preg_match ( '! \ [Keywords = ([^ \]] +) \]! IU', $ term-> description, $ match); $ Out = isset ($ match [1])? $ Match [1]: ''; }} If ($ out && $ def_keywords) $ out = $ out. ','. $ Def_keywords; if ($ out) return "<meta name = \" keywords \ "content = \" $ out \ "/> \ n"; }підключення
Рекомендую скопіювати код в окремий php файл, наприклад seo.php і підключити його в файл теми functions.php.
require_once 'seo.php';Це все, код відразу починає працювати, більше не потрібно нічого нікуди додавати - все працює через хукі. Єдине, потрібно переконатися що в файлі теми header.php є виклик функції wp_head () і що там немає виводитися жорстко тег <title> і інші SEO теги ...
Метапол в адмінці
Код вище тільки виводить потрібні SEO мета-теги, але не додає метапол для записів або елементів таксономій - їх потрібно створити окремо.
На сторінці редагування записи або терміна вам потрібно створити метабокс з мета-полями:
title - альтернативний SEO заголовок буде використовуватися в мета-теги <title>, замість заголовка запису.
description - опис для сторінки. Якщо його немає, то буде взяти текст з цитати, якщо і його немає, то шматок з початку контенту записи.
meta_description - так повинно називатися метапол опису для термінів, тому що ключ description для таксономій зайнятий ...
keywords - мета-тег keywords. Не знаю потрібен він чи ні взагалі в сучасних реаліях.
- robots - вказане тут значення виводиться як є, наприклад noindex, nofollow.
Як створити метабокси з метапол?
Зробити це можна за допомогою класу Kama_Post_Meta_Box , просто кодом або за допомогою плагінів Carbon Fields , Meta Box .
Для елементів таксономій (термінів), використовуйте приклад з хука (Taxonomy) _edit_form_fields або все ті ж плагіни.
Тонка настройка виведення
Код містить всі необхідні хукі, щоб повністю або частково змінити висновок кожного метапол.
Одна з переваг цього коду над плагінами, це швидке рішення нестандартної задачі. Все це робиться через хукі і тут і в плагінах, тільки знайти потрібних хук в плагіні зазвичай займає більше часу. Крім того ви можете переписати частину коду під свою конкретну задачу ...
Корисні посилання
Статті до цього: SEO Is_singular ()?IU', $ term-> description, $ match); $ Out = isset ($ match [1])?
Як створити метабокси з метапол?