Выбор подписчика в качестве автора записи в админке?
Я хочу иметь возможность выбирать подписчика в качестве автора записи в админке, чтобы отображалось его имя как автора, но при этом не хочу давать ему никаких дополнительных прав (если он залогинится, он должен иметь доступ только к своему профилю).
Есть ли простой способ сделать это без изменения ролей и возможностей?
Спасибо

Это простой хак, который я написал в похожей ситуации. Он будет отображать всех Подписчиков
в выпадающем списке Автор
при редактировании/добавлении записи или страницы, где вы можете выбрать любого из них. Думаю, это должно сработать и в вашем случае...
add_filter('wp_dropdown_users', 'MySwitchUser');
function MySwitchUser($output)
{
//Глобальная переменная $post доступна здесь, поэтому вы можете проверить тип записи
$users = get_users('role=subscriber');
$output = "<select id=\"post_author_override\" name=\"post_author_override\" class=\"\">";
//Оставляем администратора в списке
$output .= "<option value=\"1\">Администратор</option>";
foreach($users as $user)
{
$sel = ($post->post_author == $user->ID)?"selected='selected'":'';
$output .= '<option value="'.$user->ID.'"'.$sel.'>'.$user->user_login.'</option>';
}
$output .= "</select>";
return $output;
}
Секрет в том, что после отправки формы WordPress считывает только $user->ID из этого выпадающего списка в массиве $_POST и назначает его автором записи. Именно этого мы и добиваемся!

Огромное спасибо, Rutwick! Именно то, что мне было нужно! Мне только пришлось изменить $users = get_users(); иначе не отображались пользователи с другими ролями

Всегда пожалуйста, дружище! :) Вообще-то я использовал это для кастомной роли, поэтому и параметры такие... Рад, что смог помочь!

Только что обнаружил небольшую проблему - когда я возвращаюсь на страницу редактирования поста, выпадающий список по умолчанию выбирает администратора, так что если я вношу изменения и сохраняю без повторного выбора автора, он меняет автора на администратора. Есть идеи как это исправить?

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

По какой-то причине $post->post_author ничего не возвращает в экране редактирования записи, и я не могу понять почему!

Обратите внимание, что пользователь с ID 1
может быть, а может и не быть администратором. Получение реального администратора из WordPress сработает лучше.

Я внес небольшие изменения в это решение, на случай если кому-то понадобится. Итак, если вы хотите отображать "display name" в выпадающем списке, просто измените вторую строку внутри foreach на это: $output .= '<option value="'.$user->ID.'"'.$sel.'>'.$user->display_name.'</option>'; А если вы хотите добавить конкретного пользователя (с другой ролью), добавьте это перед foreach: $output .= "<option value=\"[ID]\">Имя</option>"; (замените [ID] на фактический ID)

Начиная с WordPress 4.4.0 вы можете использовать фильтр wp_dropdown_users_args
. Код стал значительно проще:
add_filter( 'wp_dropdown_users_args', 'add_subscribers_to_dropdown', 10, 2 );
function add_subscribers_to_dropdown( $query_args, $r ) {
$query_args['who'] = '';
return $query_args;
}

Это должен быть правильный/принятый ответ. Прямо из Codex: https://developer.wordpress.org/reference/hooks/wp_dropdown_users_args/#user-contributed-notes

Этот подход аналогичен методу @brasofilo. Однако он работает только на экране редактирования записи, а не в быстром редактировании, и включает всех пользователей (не только авторов и подписчиков).
/* Удалить метабокс "Автор" из редактирования записи */
function wpse50827_author_metabox_remove() {
remove_meta_box('authordiv', 'post', 'normal');
}
add_action('admin_menu', 'wpse50827_author_metabox_remove');
/* Заменить на пользовательский метабокс "Автор" */
function wpse39084_custom_author_metabox() {
add_meta_box( 'authordiv', __('Автор'), 'wpse39084_custom_author_metabox_insdes','post');
}
add_action( 'add_meta_boxes', 'wpse39084_custom_author_metabox');
/* Включить всех пользователей в выпадающий список авторов записи */
/* Копирует стандартный метабокс http://core.trac.wordpress.org/browser/trunk/wp-admin/includes/meta-boxes.php#L514 */
function wpse39084_custom_author_metabox_insdes() {
global $user_ID;
global $post;
?>
<label class="screen-reader-text" for="post_author_override"><?php _e('Автор'); ?></label>
<?php
wp_dropdown_users( array(
'name' => 'post_author_override',
'selected' => empty($post->ID) ? $user_ID : $post->post_author,
'include_selected' => true
) );
}
Этот код имитирует стандартный метабокс автора, но вызов wp_dropdown_users
пропускает аргумент who=>'editors'
. По умолчанию используется единственное другое значение, которое включает всех пользователей.

Спасибо, Стивен. В итоге я использовал решение Rutwick, так как оно уже работает с CPT, но ценю ваш ответ :)

Это код, предоставленный @Innate в комментарии (решение) к его собственному вопросу, я лишь немного адаптировал его и протестировал в WP 3.3.2 (функция wpse39084). Он будет отображать подписчиков в редактировании записей и быстром редактировании.
Также добавлено несколько действий (функции wpse50827) для перемещения метабокса "Автор" внутрь метабокса "Действия публикации", чтобы упростить управление.
Все относится только к записям, не к страницам и не к пользовательским типам записей...
foreach( array( 'edit.php', 'post.php' ) as $hook )
add_action( "load-$hook", 'wpse39084_replace_post_meta_author' );
/* Показывать подписчиков в выпадающем списке авторов записей - при редактировании и быстром редактировании */
function wpse39084_replace_post_meta_author()
{
global $typenow;
if( 'post' != $typenow )
return;
add_action( 'admin_menu', 'wpse50827_author_metabox_remove' );
add_action( 'post_submitbox_misc_actions', 'wpse50827_author_metabox_move' );
add_filter( 'wp_dropdown_users', 'wpse39084_showme_dropdown_users' );
}
/* Изменить выпадающий список авторов */
function wpse39084_showme_dropdown_users( $args = '' )
{
$post = get_post();
$selected = $post->post_author;
$siteusers = get_users( 'orderby=nicename&order=ASC' ); // можно передавать фильтры и опции
$re = '';
if( count( $siteusers ) > 0 )
{
$re = '<select name="post_author_override" id="post_author_override">';
foreach( $siteusers as $user )
{
$re .= '<option value="' . $user->ID . '">' . $user->user_nicename . '</option>';
}
$re .= '</select>';
$re = str_replace( 'value="' . $selected . '"', 'value="' . $selected . '" selected="selected"', $re );
}
echo $re;
}
/* Удалить метабокс "Автор" из редактирования записи */
function wpse50827_author_metabox_remove()
{
remove_meta_box( 'authordiv', 'post', 'normal' );
}
/* Переместить метабокс "Автор" внутрь метабокса "Действия публикации" */
function wpse50827_author_metabox_move()
{
global $post;
echo '<div id="author" class="misc-pub-section" style="border-top-style:solid; border-top-width:1px; border-top-color:#EEEEEE; border-bottom-width:0px;">Автор: ';
post_author_meta_box( $post );
echo '</div>';
}

Более правильный способ сделать это...
add_filter('wp_dropdown_users', 'MySwitchUser');
function MySwitchUser()
{
global $post; // можно удалить, если не используется
// здесь доступна global $post, поэтому можно проверить тип записи
$users = get_users('role=subscriber');
echo'<select id="post_author_override" name="post_author_override" class="">';
echo'<option value="1">Администратор</option>';
foreach($users as $user)
{
echo '<option value="'.$user->ID.'"';
if ($post->post_author == $user->ID){ echo 'selected="selected"'; }
echo'>';
echo $user->user_login.'</option>';
}
echo'</select>';
}

Я сделал что-то похожее на принятый ответ здесь, но хотел показывать только администраторов и, в моем случае, пользователей с кастомной ролью 'producers' вместе.
add_filter('wp_dropdown_users', 'custom_author_select');
function custom_author_select($output){
// Здесь доступна global $post, поэтому можно проверить тип записи
$admins = get_users('role=administrator');
$producers = get_users('role=producer');
$users = array_merge($admins, $producers);
$output = "<select id=\"post_author_override\" name=\"post_author_override\" class=\"\">";
// Оставляем администратора в списке
$output .= "<option value=\"1\">Admin</option>";
foreach($users as $user){
$sel = ($post->post_author == $user->ID)?"selected='selected'":'';
$output .= '<option value="'.$user->ID.'"'.$sel.'>'.$user->user_login.'</option>';
}
$output .= "</select>";
return $output;
}

Это может быть решением для избежания ошибки при быстром редактировании, где "cpt_slug" следует заменить на слаг вашего пользовательского типа записи
add_filter('wp_dropdown_users', 'MySwitchUser');
function MySwitchUser($output)
{
global $typenow;
if ((is_edit_page('edit') && "cpt_slug" == $typenow)||(is_edit_page('new') && "cpt_slug" == $typenow)){
global $post;
$users = get_users();
$output = "<select id=\"post_author_override\" name=\"post_author_override\" class=\"\">";
foreach($users as $user)
{
$sel = ($post->post_author == $user->ID)?"selected='selected'":'';
$output .= '<option value="'.$user->ID.'"'.$sel.'>'.$user->user_login.'</option>';
}
$output .= "</select>";
}
return $output;
}
function is_edit_page($new_edit = null){
global $pagenow;
if (!is_admin()) return false;
if($new_edit == "edit")
return in_array($pagenow, array('post.php'));
elseif($new_edit == "new")
return in_array($pagenow, array('post-new.php'));
else
return in_array($pagenow, array('post.php', 'post-new.php'));
}

Тут немного запутанно. Похоже, есть 3 способа решения, и это зависит от того, используете ли вы Классический редактор или Гутенберг.
Если вы используете Классический редактор:
- Вы можете переопределить HTML с помощью фильтра
wp_dropdown_users
, как предлагалось в других ответах - Или переопределить параметры запроса с помощью
wp_dropdown_users_args
Если вы используете Гутенберг, выпадающий список авторов реализован по-другому.
Как отметил Томас Леви в этом GitHub issue:
- Функция блоков для заполнения выпадающего списка авторов использует wordpress/data/select( 'core' ).getAuthors()
- Это вызывает конечную точку REST API: /wp/v2/users/?who=authors&per_page=-1
- Эта конечная точка передает данные в WP_User_Query
- WP_User_Query с параметром "who=>author" добавит запрос usermeta в запрос.
- Это выберет любого пользователя с user_level не равным 0
Чтобы пользовательские роли отображались в выпадающем списке авторов, вам нужно добавить возможность level_1
для роли. Уровни были заменены возможностями в WordPress 2.0 еще в 2005 году, но это поведение/баг сохранилось до сих пор.
$role = add_role( 'mycustomrole', 'Моя Пользовательская Роль' );
$role->add_cap( 'level_1' );
Чтобы добавить эту возможность существующим пользователям, выполните это один раз:
$custom_role = get_users( 'role=mycustomrole' );
foreach ( $custom_role as $role ) {
$role->add_cap( 'level_1' );
}

Я перепробовал все решения, указанные здесь, а также некоторые другие, но единственное, что сработало для меня, это решение из пользовательских заметок в WordPress Codex.
Там говорится, что нужно предоставить подписчикам соответствующую возможность, но в моем случае я этого не хотел. Мне просто нужно было, чтобы они отображались в выпадающем списке авторов.
// Отображать подписчиков в выпадающем списке 'автор' в классическом редакторе записей
function wpdocs_add_subscribers_to_dropdown( $query_args ) {
$query_args['who'] = ''; // сбросить запрос
$query_args['capability'] = ''; // сбросить запрос
$query_args['role__in'] = array( 'administrator', 'subscriber', 'author', 'editor' );
$query_args['capability__in'] = array( 'edit_own_posts' ); // Пользовательская возможность для подписчиков
return $query_args;
}
add_filter( 'wp_dropdown_users_args', 'wpdocs_add_subscribers_to_dropdown' );
Ссылка на страницу Codex: https://developer.wordpress.org/reference/hooks/wp_dropdown_users_args/#user-contributed-notes
