Je veux ajouter quelques éditeurs que canedit_others_posts
, mais je ne veux pas qu’ils soient capables de publierautres publications, uniquement enregistrerla publication en cliquant sur le bouton Soumettre pour Bouton de révision.
Comment puis-je faire ceci?
EDIT: Pour expliquer cela en détail. Actuellement, nous ne pouvons pas autoriser un utilisateur à éditer d'autres publications par seulementenregistrer la publication. Si edit_others_post
est activé pour l'utilisateur, il peut alors publierla publication.).
Le flux de travail que je vise:
Si je comprends bien, les utilisateurs ayant un rôle particulier sur votre site doivent:
Si tel est le cas, il me semble que ce rôle ressemble plus à un "auteur" qu'à un "éditeur".
Seules les différences avec l'auteur est que
La première suggestion que je puisse vous donner est de créer un rôle personnalisé, en utilisant le rôle 'author' comme point de départ, en supprimant les 3 majuscules non désirées et en ajoutant celui personnalisé, une classe simple qui le fait:
class CustomEditorRole {
private static $role = 'authorplus';
private $role_label;
function __construct() {
// here we need a real, loaded, text domain
$this->role_label = __( 'Author +', 'yout-txt-dmn' );
}
function addRole() {
global $wp_roles;
if ( ! $wp_roles instanceof WP_Roles ) {
$wp_roles = new WP_Roles;
}
$author = get_role( 'author' );
$caps = $author->capabilities; // start with author capabilities
$caps['publish_posts'] = FALSE;
$caps['edit_published_posts'] = FALSE;
$caps['delete_published_posts'] = FALSE;
$caps['edit_others_pending_posts'] = TRUE; // custom cap
// create new role with custom caps
add_role( self::$role, $this->role_label, $caps );
}
function removeRole() {
global $wp_roles;
if ( ! $wp_roles instanceof WP_Roles ) {
$wp_roles = new WP_Roles;
}
remove_role(self::$role);
}
}
Ajoutons l'action sur l'activation/désactivation du plugin:
register_activation_hook( __FILE__, array( new CustomEditorRole, 'addRole' ) );
register_deactivation_hook( __FILE__, array( new CustomEditorRole, 'removeRole' ) );
Ici, je suppose que le code précédent est dans le fichier du plugin principal.
Les fonctionnalités que nous avons définies ci-dessus sont valides pour chaque publication, quel que soit le statut de l'auteur ou de la publication de la publication. Nous devons maintenant permettre à un utilisateur doté de notre rôle personnalisé de modifier les autres publications en attente.
Le premier problème que nous rencontrons est que sur l'écran de liste de publication (edit.php
), si la fonctionnalité edit_others_posts
n'est pas activée pour l'utilisateur (et pour notre rôle personnalisé, elle ne l'est pas), les publications d'autres utilisateurs ne sont pas affichées dans la liste, car supprimées. À partir de la requête et lorsque la requête se produit, nous n’avons pas accès aux données des publications. Nous devons donc attribuer la capacité, l’état de la publication, au moins jusqu’à ce que la requête soit exécutée.
Le deuxième problème est que, lors de la sauvegarde, avant de donner à l'utilisateur doté de rôles personnalisés la limite edit_others_posts
, nous devons vérifier non seulement que l'état actuel est "en attente", mais également que l'utilisateur n'essaie pas de le modifier. Cela peut être fait en regardant les informations dans les données $_POST
. Cela signifie que nous avons besoin de 2 "routines", une qui s'exécute sur les écrans d'administration (edit.php
et post.php
) et la seconde qui s'exécute pendant la post-sauvegarde.
Pour donner à notre utilisateur de rôle personnalisé la capacité edit_others_post
uniquement pour les publications en attente, ajoutez un filtre à 'user_has_cap'
.
Dans le rappel du filtre, nous pouvons implémenter ce workflow:
'edit-post'
ou 'edit-others-posts'
, vérifions si nous sommes en tant qu'administrateur, vérifie si l'utilisateur dispose de notre fonctionnalité personnalisée et qu'il ne s'agit pas d'un éditeur ni d'un administrateur. Si toutes ces conditions sont vraies nous pouvons continuer, sinon nous ne devons rien faire, c'est-à-dire rendre les capacités d'origineRoutine lors de la sauvegarde:
'edit-others-posts'
('edit-post'
sera automatiquement mappé)Routine lorsque vous ne sauvegardez pas:
'edit-others-posts'
, nous n’avons pas de données de publication. Il suffit donc de l’affecter, mais seulement avant que la requête principale ne se produise pas et uniquement sur l’écran edit.php
.'edit-post'
, obtenir les données de publication et si celle-ci est en attente, attribuer à l'utilisateur le cap 'edit-others-posts'
('edit-post'
sera automatiquement mappé)Il y a une dernière chose à faire. À l'aide du rôle personnalisé décrit dans le flux de travail, les utilisateurs ne pourront pas prévisualiser les autres publications en attente, même s'ils sont en mesure de les modifier.
Nous pouvons filtrer à nouveau la capacité, mais il existe un moyen plus simple: lors d'une requête principale (en utilisant l'un des douze hooks déclenchés par WP_Query
), nous pouvons simplement prendre l'objet $wp_post_statuses['pending']
object et définir sa propriété public
à true lorsque l'utilisateur actuel a notre rôle personnalisé: le seul effet est que les publications en attente sont prévisualisées et que, si nous ne modifions aucune fonctionnalité, nous pouvons rester en sécurité.
Ok, il suffit de traduire les mots dans le code:
class CustomEditorCaps {
function manageCaps( $allcaps, $caps, $args, $user ) {
if ( ! $this->shouldManage( $args[0], $user ) ) {
return $allcaps;
}
// Are we saving?
$action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_STRING );
$method = strtoupper(filter_var($_SERVER['REQUEST_METHOD'], FILTER_SANITIZE_STRING ));
if ( $method !== 'POST' ) { // not saving
global $pagenow;
// we are interested only on post list and post edit screens
if (
is_admin()
&& in_array( $pagenow, array( 'post.php', 'post-new.php', 'edit.php' ), TRUE
) ) {
$screen_id = $pagenow === 'edit.php' ? 'edit-post' : 'post';
$allcaps = $this->maybeAllow( $args, $allcaps, $user, $screen_id );
}
} elseif ( $action === 'editpost' ) { // saving and right action
$allcaps = $this->maybeAllowOnSave( $args, $allcaps, $user );
}
return $allcaps; // always return: it's a filter
}
function lockPendingStatus( $data, $postarr ) {
if (
isset( $postarr['ID'] )
&& ! empty($postarr['ID'])
&& $data['post_type'] === 'post' // 'post' post type
&& $data['post_status'] !== 'pending' // a non pending status
&& ! current_user_can( 'delete_others_posts' ) // current user is not an admin
) {
$orig = get_post_status( $postarr['ID'] );
if ( $orig === 'pending' ) { // hey post was pending!
$data['post_status'] = 'pending'; // let's restore pending status
}
}
return $data; // always return: it's a filter
}
function allowPreview( $posts, $query ) {
if ( is_admin()
|| ! $query->is_main_query()
|| empty( $posts )
|| ! $query->is_single
|| $posts[0]->post_type !== 'post'
) {
return $posts; // return first argument: it's a filter
}
$status = get_post_status( $posts[0] );
$post_status_obj = get_post_status_object( $status );
if (
! $post_status_obj->public
&& $status === 'pending'
&& current_user_can('edit_others_pending_posts')
) {
// post is pending and our user has our special role
// allow preview
global $wp_post_statuses;
$wp_post_statuses[$status]->public = TRUE;
}
return $posts; // return first argument: it's a filter
}
private function maybeAllow( $args, $allcaps, $user, $screen ) {
if ( $args[0] === 'edit_others_posts' ) {
// if filtering 'edit_others_posts' we have no access to single post data
// allow cap only on post list screen and before querying posts
$allcaps['edit_others_posts'] = ! did_action('pre_get_posts')
&& $screen === 'edit-post';
return $allcaps;
}
$post = get_post( $args[2] );
if ( $post->post_status === 'pending' ) {
$allcaps['edit_others_posts'] = TRUE;
}
return $allcaps; // always return: it's a filter
}
private function maybeAllowOnSave( $args, $allcaps, $user ) {
$data = $this->getPostedData();
if ( $data['post_type'] !== 'post' || (int) $data['post_ID'] <= 0 ) {
return $allcaps;
}
$post = get_post( $data['post_ID'] );
if (
$post->post_status === 'pending'
&& $data['original_post_status'] === 'pending'
&& ( empty( $data['post_status'] ) || $data['post_status'] === 'pending' )
) {
// if post is pending and will stay pending allow editing
$allcaps['edit_others_posts'] = true;
}
return $allcaps;
}
private function shouldManage( $cap, $user ) {
return is_admin() // not affect frontend
&& in_array( $cap, array( 'edit_others_posts', 'edit_post' ), TRUE )
&& ! $user->has_cap( 'delete_others_posts' ) // real editor or more
&& $user->has_cap( 'edit_others_pending_posts' ) // our role
&& ! defined( 'DOING_AJAX' ); // does not affect ajax
}
private function getPostedData() {
return filter_input_array( INPUT_POST, array(
'post_type' => FILTER_SANITIZE_STRING,
'post_ID' => FILTER_SANITIZE_NUMBER_INT,
'original_post_status' => FILTER_SANITIZE_STRING,
'post_status' => FILTER_SANITIZE_STRING,
) );
}
}
Et ajoutez les 2 points d’accrochage appropriés: un pour le filtrage 'user_has_cap'
, un pour s’assurer que l’état en attente ne peut être modifié que par des administrateurs ou des éditeurs réels et le dernier filtre 'posts_results'
pour autoriser la prévisualisation:
$cap_manager = new CustomEditorCaps;
add_filter( 'user_has_cap', array( $cap_manager, 'manageCaps' ), PHP_INT_MAX, 4 );
add_filter( 'posts_results', array( $cap_manager, 'allowPreview' ), 10, 2 );
add_filter( 'wp_insert_post_data', array( $cap_manager, 'lockPendingStatus' ), 10, 2 );
Une fois que vous avez tout ce code dans un plugin et que vous l'activez, vous n'avez plus qu'à affecter aux utilisateurs le rôle personnalisé créé par le plugin.
Tout le code est disponible sous forme de plugin, dans un fichier Gist here .