Блог Александра Лысенко о верстке, фрилансе и жизни

Как получить ID страницы, поста, рубрики и произвольного типа записи в WordPress

20 августа 2024г.

Как получить ID страницы, поста, рубрики и произвольного типа записи в WordPressЗа 15 лет работы с WordPress эта задача всплывает постоянно — то нужно вывести произвольные поля для конкретной страницы, то навесить стиль по ID, то отфильтровать вывод в шаблоне. Ниже — все рабочие способы без воды, сразу к делу.

1. ID главной страницы WordPress

<?php $frontpage_id = get_option(‘page_on_front’); ?>

2. Внутри цикла (The Loop)

Классика:


1
2
3
4
5
6
if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        $id = get_the_ID();
    }
}
1
get_the_ID()

работает только внутри Loop или там, где выставлен глобальный

1
$post

. Вне цикла вернёт

1
null

.

3. Вне цикла, через глобальный объект


1
2
global $post;
$id = $post-&gt;ID;

Работает на одиночных шаблонах (

1
single.php

,

1
page.php

), но не гарантирован на архивах, где

1
$post

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

4. get_queried_object_id()

Универсальная функция, которая знает, что сейчас «запрошено» — страницу, пост, рубрику, автора, дату:


1
$id = get_queried_object_id();
  • на
    1
    single.php

    — ID поста;

  • на
    1
    page.php

    — ID страницы;

  • на
    1
    category.php

    — ID рубрики;

  • на
    1
    author.php

    — ID автора;

  • на
    1
    tag.php

    — ID метки.

Это то, что я использую в 90% случаев в

1
functions.php

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

5. ID главной страницы и страницы блога

Отдельная больная тема, потому что

1
is_front_page()

и

1
is_home()

путают многих.


1
2
$front_page_id = get_option( 'page_on_front' );
$posts_page_id = get_option( 'page_for_posts' );

Работает только если в Настройки → Чтение выставлено «Статическая страница». Если на главной — лента постов,

1
page_on_front

будет пустым (0).

6. По слагу (slug) или по заголовку

Если известен URL-адрес (slug), но не ID:


1
2
$page = get_page_by_path( 'about-us' ); // slug страницы
$id   = $page ? $page-&gt;ID : 0;

С WordPress 6.2

1
get_page_by_path()

и

1
get_page_by_title()

официально задепрекейчены на прямое использование в пользу

1
WP_Query

. Рабочий вариант без депрекейт-варнингов:


1
2
3
4
5
6
7
8
$query = new WP_Query( array(
    'name'        =&gt; 'about-us',
    'post_type'   =&gt; 'page',
    'post_status' =&gt; 'publish',
    'numberposts' =&gt; 1,
) );

$id = $query-&gt;have_posts() ? $query-&gt;posts[0]-&gt;ID : 0;

7. По URL целиком

Если есть полный адрес страницы (например, распарсили ссылку из текста):


1
$id = url_to_postid( 'https://site.ru/about-us/' );

Функция сама разберёт rewrite-правила и вернёт ID поста/страницы. Возвращает

1
0

, если не нашла соответствие.

8. ID рубрики / метки / произвольной таксономии

По названию или слагу:


1
2
$term = get_term_by( 'slug', 'news', 'category' ); // или 'name', 'term_id'
$id   = $term ? $term-&gt;term_id : 0;

Для меток то же самое, меняешь третий параметр на

1
post_tag

, для кастомной таксономии — на её слаг.

Устаревшая, но ещё встречающаяся в легаси-коде функция:


1
$id = get_cat_ID( 'Новости' ); // работает только с категориями, ищет по точному названию

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


1
$id = get_queried_object_id(); // как в пункте 4

9. ID произвольного типа записи (Custom Post Type)

Никакой магии — все функции выше работают одинаково для CPT, просто добавляй

1
post_type

:


1
2
3
4
5
6
7
$query = new WP_Query( array(
    'post_type'   =&gt; 'portfolio',
    'name'        =&gt; 'project-slug',
    'numberposts' =&gt; 1,
) );

$id = $query-&gt;have_posts() ? $query-&gt;posts[0]-&gt;ID : 0;

Или через

1
get_posts()

, если не нужен полный объект

1
WP_Query

:


1
2
3
4
5
6
7
$posts = get_posts( array(
    'post_type'      =&gt; 'portfolio',
    'name'           =&gt; 'project-slug',
    'posts_per_page' =&gt; 1,
) );

$id = $posts ? $posts[0]-&gt;ID : 0;

10. По произвольному полю (meta)

Когда ID неизвестен, но известно значение мета-поля:


1
2
3
4
5
6
7
8
$posts = get_posts( array(
    'post_type'   =&gt; 'any',
    'meta_key'    =&gt; 'sku',
    'meta_value'  =&gt; 'ABC-123',
    'numberposts' =&gt; 1,
) );

$id = $posts ? $posts[0]-&gt;ID : 0;

Учитывай, что

1
meta_value

без индекса на больших базах — это full scan таблицы

1
wp_postmeta

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

1
meta_query

с явным типом сравнения, но чуда это не даст — узкое место в структуре

1
wp_postmeta

, а не в коде.

11. Через REST API

Если работаешь с фронтом на JS или дергаешь WP как headless:


1
2
3
GET /wp-json/wp/v2/pages?slug=about-us
GET /wp-json/wp/v2/posts?slug=my-post
GET /wp-json/wp/v2/categories?slug=news

В ответе — массив объектов,

1
id

берёшь из первого элемента. Для кастомных типов эндпоинт будет

1
/wp-json/wp/v2/{post_type_rest_base}

.

12. Напрямую из базы (когда php-контекста нет)

Иногда проще дернуть SQL — например, в миграционном скрипте:


1
SELECT ID FROM wp_posts WHERE post_name = 'about-us' AND post_type = 'page';

Для терминов:


1
2
3
4
SELECT t.term_id
FROM wp_terms t
JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
WHERE t.slug = 'news' AND tt.taxonomy = 'category';

Через

1
wpdb

в коде плагина/темы:


1
2
3
4
5
6
global $wpdb;
$id = $wpdb-&gt;get_var( $wpdb-&gt;prepare(
    "SELECT ID FROM {$wpdb-&gt;posts} WHERE post_name = %s AND post_type = %s",
    'about-us',
    'page'
) );

Обязательно через

1
$wpdb-&gt;prepare()

— без этого получаешь SQL-инъекцию на ровном месте.

Частые грабли

  • 1
    get_the_ID()

    вне Loop возвращает

    1
    null

    — типичная причина «функция не работает», хотя на самом деле контекст не тот.

  • Page ID vs Front Page ID — если на сайте на главной статическая страница,
    1
    is_front_page()

    истинно, но

    1
    get_queried_object_id()

    всё равно вернёт корректный ID этой страницы, а не 0. Путаница чаще в обратную сторону: когда на главной лента постов,

    1
    get_option('page_on_front')

    вернёт 0, и это нормально.

  • 1
    get_page_by_title()

    ищет по неточному совпадению в старых версиях WP (до депрекейта) — можно словить не ту запись, если заголовки похожи. Работайте через slug, а не через title, где это возможно.

  • Кэш объектов. Если правите базу напрямую (SQL), а потом сразу дергаете
    1
    get_post()

    — можете получить закэшированные старые данные. Чистите object cache (

    1
    wp_cache_flush()

    ) при отладке.