WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

Добавляем колонки у постов в админке (сортируемые)

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

В этой статье, в качестве примера, создадим колонку "Визиты", с данными произвольного поля views, куда записываются посещения. Колонка получится сортируемая.

dop

Хуки для создания колонок

manage_(screen_id)_columns

Позволяет добавить колонки в таблицу записей на указанном экране (у нас edit-post).

Передает массив с данными колонок, который мы можем изменить, добавив свою колонку (views) или удалить существующую через unset(). Название нашего фильтра будет: manage_edit-post_columns.

manage_(post_type)_posts_columns
Аналогичный предыдущему - добавляет колонки. Только тут указывается тип записи а не ID экрана... Название нашего фильтра будет: manage_post_posts_columns. С версии 3.1. рекомендуется использовать этот хук.
manage_(post_type)_posts_custom_column

Отвечает за заполнение данных колонки на странице постов. В нашем случае: manage_post_posts_custom_column.

Передает название колонки и ID поста.

manage_(screen_id)_sortable_columns

Аналогичный первому — регистрирует сортируемую колонку, где мы указываем имя запроса orderby.

Также передает массив с зарегистрированными сортируемыми колонками. В нашем случае фильтр выглядит так: manage_edit-post_sortable_columns.

pre_get_posts (wp-includes/query.php)

Этот фильтр-действие срабатывает в самом начале метода get_posts() класса WP_query.

Хук передает весь класс по ссылке (&$this). Используя этот фильтр, мы можем задать параметры главного запроса WP ($wp_query), по которому потом строится вывод.

Чтобы узнать screen_id используем функцию get_current_screen(). Её можно повесить на хук in_admin_header:

add_action( 'in_admin_header', function(){  
	echo '<pre>'. print_r( get_current_screen(), 1 ) .'</pre>';
} );

В нашем случае screen_id = edit-post - это страница редактирования постов в админке.

меню

Создаем колонку

Вставляем такой код в файл темы function.php:

// создаем новую колонку
add_filter( 'manage_'.'post'.'_posts_columns', 'add_views_column', 4 );
function add_views_column( $columns ){
	$num = 2; // после какой по счету колонки вставлять новые

	$new_columns = array(
		'views' => 'Визиты',
	);

	return array_slice( $columns, 0, $num ) + $new_columns + array_slice( $columns, $num );
}

// заполняем колонку данными
// wp-admin/includes/class-wp-posts-list-table.php
add_action('manage_'.'post'.'_posts_custom_column', 'fill_views_column', 5, 2 );
function fill_views_column( $colname, $post_id ){
	if( $colname === 'views' ){
		echo get_post_meta( $post_id, 'views', 1 ); 
	}
}

На этом можно остановится, если нам не нужно сортировать колонку — будет просто колонка с данными.

меню

Делаем колонку сортируемой

// добавляем возможность сортировать колонку
add_filter( 'manage_'.'edit-post'.'_sortable_columns', 'add_views_sortable_column' );
function add_views_sortable_column( $sortable_columns ){
	$sortable_columns['views'] = [ 'views_views', false ]; 
											   // false = asc (по умолчанию)
											   // true  = desc

	return $sortable_columns;
}

Здесь ключ views должен совпадать с ключом при регистрации колонки: $out['views'] и $sortable_columns['views']. Значение: views_views будет значением параметра запроса "orderby", который WordPress добавит автоматически (&orderby=views_views). Это же значение будет добавлено в параметры запрос WP_query и если оно будет совпадать со значениями известными WP ('title', 'date', 'modified', 'comment_count' и т.д.), то WP сам отсортирует колонку как нужно и тут можно остановится. Полный список значений известных WP, исключения составляют: meta_value и meta_value_num.

Если мы укажем meta_value вместо views_views, WP не сможет автоматически выполнить правильную сортировку. Поэтому, если в параметре orderby указывается наше значение views_views (&orderby=views_views), то мы создадим кастомный, нужный нам запрос.

Для сортировки по произвольному полю, проще всего изменить аргументы базового запроса, использовав хук pre_get_posts. Но важно понимать, что этот хук глобальный и срабатывает всякий раз, когда генерируется страница и не только в админке, но и на фронте. Поэтому мы должны точно указать в каком случае изменять запрос, этим случаем у нас будет значение аргумента orderby = views_views. Во всех остальных случаях запрос не трогаем.

Вариант 1:

// изменяем запрос при сортировке колонки
add_action( 'pre_get_posts', 'add_column_views_request' );
function add_column_views_request( $query ){
	if( ! is_admin() 
		|| ! $query->is_main_query() 
		|| $query->get('orderby') !== 'views_views' 
		|| get_current_screen()->id !== 'edit-post'
	)
		return;

	$query->set( 'meta_key', 'views' );
	$query->set( 'orderby', 'meta_value_num' );
}

Вариант 2: принцип точно такой же, только используется хук request:

// изменяем запрос при сортировке колонки
add_filter( 'request', 'add_column_views_request' );
function add_column_views_request( $vars ) {
	if( isset($vars['orderby']) && $vars['orderby'] === 'views_views' ){
		$vars['meta_key'] = 'views';
		$vars['orderby'] = 'meta_value_num';
	}

	return $vars;
}

Вариант 3: принцип взял из статьи Sortable Taxonomy Columns.

Тут мы изменяем SQL запрос, а не параметры передаваемые WP_query. Пригодится, если нужно создать какую-нибудь уникальную сортировку. Переделал под наш случай:

// изменяем запрос при сортировке колонки
add_filter( 'posts_clauses', 'add_column_views_request', 10, 2 );
function add_column_views_request( $clauses, $wp_query ){
	if( 'views_views' != $wp_query->query['orderby'] )
		return $clauses;

	global $wpdb;

	$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID={$wpdb->postmeta}.post_id";
	//$clauses['where'] .= " AND {$wpdb->postmeta}.meta_key='views'";
	$clauses['orderby']  = " {$wpdb->postmeta}.meta_value+0 ";
	$clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';

	// еще изменяемые элементы
	//$clauses['groupby']
	//$clauses['distinct']
	//$clauses['fields'] // wp_posts.*
	//$clauses['limits'] // LIMIT 0, 20

	return $clauses;
}

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

Заметка

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

Например, так (или аналогичным способом) сделать не получится:

// НЕРАБОЧИЙ КОД!!!
add_action( 'pre_get_posts', 'pre_get_posts_views' );
function pre_get_posts_views( $wp_query ) {

		$wp_query->set( 'orderby', 'views_exists' );

		$wp_query->set( 'meta_query', [
			'relation'         => 'OR',
			'views_exists'     => [
				'key'     => 'views',
				'compare' => 'EXISTS',
				'type'    => 'numeric',
			],
			[
				'key'     => 'views',
				'compare' => 'NOT EXISTS',
			],
		] );
	}
}
меню

Ширина колонки

Еще может пригодится отредактировать ширину колонки, а то бывает растягивается без надобности. Ширину указываем так:

// подправим ширину колонки через css
add_action('admin_head', 'add_views_column_css');
function add_views_column_css(){
	echo '<style type="text/css">.column-views{ width:10%; }</style>';
}

Код целиком

/* Дополнительные сортируемые колонки для постов в админке 
------------------------------------------------------------------------ */
// создаем новую колонку
add_filter('manage_post_posts_columns', 'add_views_column', 4);
function add_views_column( $columns ){
	// удаляем колонку Автор
	//unset($columns['author']);

	// вставляем в нужное место - 3 - 3-я колонка
	$out = array();
	foreach($columns as $col=>$name){
		if(++$i==3)
			$out['views'] = 'Визиты';
		$out[$col] = $name;
	}

	return $out;
}
// заполняем колонку данными -  wp-admin/includes/class-wp-posts-list-table.php
add_filter('manage_post_posts_custom_column', 'fill_views_column', 5, 2);
function fill_views_column( $colname, $post_id ){
	if( $colname === 'views' ){
		echo get_post_meta($post_id, 'views', 1);
	}
}

// подправим ширину колонки через css
add_action('admin_head', 'add_views_column_css');
function add_views_column_css(){
	if( get_current_screen()->base == 'edit')
		echo '<style type="text/css">.column-views{width:10%;}</style>';
}

// добавляем возможность сортировать колонку
add_filter('manage_edit-post_sortable_columns', 'add_views_sortable_column');
function add_views_sortable_column($sortable_columns){
	$sortable_columns['views'] = 'views_views';

	return $sortable_columns;
}

// изменяем запрос при сортировке колонки
add_filter('pre_get_posts', 'add_column_views_request');
function add_column_views_request( $object ){
	if( $object->get('orderby') != 'views_views' )
		return;

	$object->set('meta_key', 'views');
	$object->set('orderby', 'meta_value_num');
}
34 коммента
Полезные 1 Вопросы 2 Все
  • Сергей

    Большое спасибо. Всё отлично работает. good

    Ответить6.5 лет назад #
  • Дмитрий cайт: www.laserkeep.ru

    а вот бы еще редактировать эти колонки.. У меня колонка "цена", было бы удобно редактировать колонку не открывая самой записиудобно,не заходя в саму запись

    Ответить6.4 лет назад #
    • Kama7489

      В планах есть, нечто подобное описать. Для комментариев правда. Это совсем не сложно сделать, если хоть немного разбираетесь в php и js: заполняете колонку полем input и кнопку рядом например, по нажатию на которую срабатывает AJAX запрос...

      1
      Ответить6.4 лет назад #
      • @ Alex

        Не, новый дизайн 146% лучше. Все стильно, все супер! Был привет из 90-х. Блог супер. У Вас уже не блог, у вас уже энциклопедия по WP!

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

        Ответить6.4 лет назад #
      • @ VRS

        victory было бы здорово!
        а так можно вывести произвольные поля записи? чтобы их редактировать сразу на странице списка постов mda ?

        Ответить6.3 лет назад #
  • Anopsa cайт: azov-stil.org.ua/lisova_pisnya

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

    Ответить5.9 лет назад #
  • @ Alexey cайт: fotoshq.com

    Большое спасибо! То что я искал thank_you

    Ответить4.10 года назад #
  • Yulia

    Спасибо большое. Очень помогает ваша "энциклопедия". Код работает.

    Ответить4.9 года назад #
  • @ Alexey cайт: fotoshq.com

    Как сделать сортировку в этом случае:

    /* Property ID Parameter */
    if( isset($_GET['property-id']) && !empty($_GET['property-id'])){
    $property_id = trim($_GET['property-id']);
    $meta_query[] = array(
    'key' => 'REAL_HOMES_property_id',
    'value' => $property_id,
    'compare' => 'LIKE',
    'type'=> 'CHAR'
    );
    }

    Эта функция уже включена в теме.

    Ответить4.8 года назад #
    • Kama7489

      Не понятно, как вы меняете запрос, где используется этот код?

      Ответить4.8 года назад #
  • Сергей

    Здравствуйте!
    Есть доп. поле с датой (date_end). Нужно вывести в колонке эти даты с возможностью сортировки.
    Не получается именно сортировка.

    Сделал так:

    // создаем новую колонку
    add_filter('manage_edit-post_columns', 'add_date_end_column', 4);
    function add_date_end_column( $columns ){
    	$columns['date_end'] = 'Exp. date';
    	return $columns;
    }
    
    // заполняем колонку данными
    add_filter('manage_post_posts_custom_column', 'fill_date_end_column', 5, 2); // wp-admin/includes/class-wp-posts-list-table.php
    function fill_date_end_column($column_name, $post_id) {
    	if( $column_name != 'date_end' )
    		return;
    	$date_end = get_post_meta($post_id, 'date_end', true);
    	$date_end = mysql2date( 'd.m.Y', $date_end );
    	echo $date_end;
    }
    
    // добавляем возможность сортировать колонку
    add_filter('manage_edit-post_sortable_columns', 'add_date_end_sortable_column');
    function add_date_end_sortable_column($sortable_columns){
    	$sortable_columns['date_end'] = 'date_end_date_end'; //пробовал здесь просто date, опустив след. пункт, все равно сортирует рандомно..
    	return $sortable_columns;
    }
    
    // изменяем запрос при сортировке колонки
    add_filter('pre_get_posts', 'add_column_date_end_request');
    function add_column_date_end_request( $object ){
    	if( $object->get('orderby') != 'date_end_date_end' )
    		return;
    	$object->set('meta_key', 'date_end');
    	$object->set('orderby', 'meta_value_num');
    }

    В чем может быть проблема?

    Ответить4.3 года назад #
    • Kama7489

      Вы дату в мета поле как штамп времени пишите? Если да, то ваш код работает! Щас проверил на тестовом сайте. Только нужно преобразование в дату изменить, строку:

      //  $date_end = mysql2date( 'd.m.Y', $date_end );
      	$date_end = $date_end ? date_i18n( 'd.m.Y', $date_end ) : '';

      mysql2date() вторым парам. получает строку а не число (штамп)

      Ответить4.3 года назад #
  • Кирилл

    Кама, а как сделать, чтобы сортировка по умолчанию была по кастомному столбцу и его значениям?
    Например есть дата, которая выбирается через datepicker плагина ACF, значения получил, сортировку сделал, но хотелось бы установить её по умолчанию, т.е. зашел на страничку и вижу записи отсортированные по кастомной дате.

    Ответить3.4 года назад #
    • Kama7489

      В 'pre_get_posts' допишите правило: если это наша страница и не установлена сортировка по полю ..., то делать что вам нужно...

      Ответить3.4 года назад #
  • @ Сергей

    Здравствуйте,
    Огромное спасибо за Ваш труд.
    Скажите пожалуйста, если необходимо вывести в новую колонку ID записи, то в качестве views что нужно указать?

    Ответить3 года назад #
    • campusboy3377 cайт: www.youtube.com/c/wpplus

      Привет!

      echo get_post_meta($post_id, 'views', 1);

      заменить на:

      echo $post_id;

      По идее должно сработать!

      2
      Ответить3 года назад #
      • @ Сергей

        Сработало! Ещё раз, большое спасибо за помощь

        Ответить3 года назад #
  • Александр

    У Вас хороший ресурс, но начанающим не все понятно, подскажите пожалуйста, что в этой записи обозначает цифра 4, третий передаваемый параметр

    add_filter('manage_edit-post_columns', 'add_views_column', 4);

    Ответить2.6 года назад #
    • Kama7489

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

      Ответить2.6 года назад #
Здравствуйте, !     Войти . Зарегистрироваться