Skip to content

Instantly share code, notes, and snippets.

@brandonjp
Last active May 1, 2023 22:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brandonjp/bf8a2ef3cab014b5ae3dba3e510bca2d to your computer and use it in GitHub Desktop.
Save brandonjp/bf8a2ef3cab014b5ae3dba3e510bca2d to your computer and use it in GitHub Desktop.
Allow non-Author to edit & save a published wordpress post. This works around issues with `_wp_translate_postdata` & `user_has_cap` - Fixes "Sorry, you are not allowed to edit posts as this user."
<?php
/*
*
* ALLOW USER TO EDIT POST IF THEY ARE SELECTED AS THE PM
* Preferred way would be to use `user_has_cap` - see:
* - https://wordpress.stackexchange.com/a/360990/5380
* - https://developer.wordpress.org/reference/hooks/user_has_cap/
* However, WordPress has a nasty long standing issue with this line:
* - https://bit.ly/3I72jOn
* Where it forces a check to make sure the author is current user, which prevents any efforts to customize capabilities by using a `user_has_cap` filter. The bug is documented here:
* - https://core.trac.wordpress.org/ticket/30452
* - https://wordpress.stackexchange.com/a/186280/5380
* So instead we're getting very hacky and maniuplating how WP checks capabilites:
* - https://core.trac.wordpress.org/ticket/30452#comment:3
* By modifiying code from @danielbachhuber:
* - https://gist.github.com/danielbachhuber/18850d571c5dce419f8b
* Which he created for his plugin, Co-Authors Plus (which might be the better option than the code below)
* - https://wordpress.org/plugins/co-authors-plus/
*
*/
function filter_map_meta_cap_allow_nonauthor_to_save_post( $caps, $cap, $user_id, $args ) {
// Adapted from @danielbachhuber : https://gist.github.com/danielbachhuber/18850d571c5dce419f8b
// To solve issue with `_wp_translate_postdata` : https://core.trac.wordpress.org/ticket/30452#comment:4
global $pagenow;
switch ( $cap ) {
case 'edit_post':
case 'edit_others_posts':
$post_obj = false;
if ( 'edit_post' === $cap ) {
$post_obj = get_post( (int) $args[0] );
/* Allow original authors to 'edit_others_posts' when updating
* Addresses core bug in _wp_translate_postdata()
*
* @see https://core.trac.wordpress.org/ticket/30452
*/
} else if ( 'edit_others_posts' === $cap
&& 'post.php' === $pagenow
&& ! empty( $_POST['post_ID'] ) ) {
$post_obj = get_post( (int) $_POST['post_ID'] );
}
if ( ! $post_obj ) {
break;
}
$post_type = get_post_type($post_obj);
$post_author = $post_obj->post_author;
$post_ID = $post_obj->ID;
// Allow user to edit the post based on custom meta
if ( 'custom-job' == $post_type ) {
// My custom meta is saved on a MetaBox.io custom taxonomy field
// you'll want to replace all the code below to check if your user should have access
// retrieve the term object from the job/post
$jobsTable = ['storage_type' => 'custom_table', 'table' => 'custom_jobs'];
$pm_term_obj = rwmb_get_value('job_pm_taxonomy', $jobsTable, $post_ID);
$pm_term_id = $pm_term_obj->term_id;
// retrieve the user id from the related term meta
$pm_user_id = get_term_meta( $pm_term_id, 'pm_related_user', true );
// check if the pm user account id matches the current logged in user id
$currentUserID = wp_get_current_user()->ID;
if ($pm_user_id == $currentUserID) {
// Don't require editing others' posts
if ( false !== ( $key = array_search( 'edit_others_posts', $caps ) ) ) {
unset( $caps[ $key ] );
}
// If the post is published...
if ( 'publish' == get_post_status($post_obj)) {
$caps[] = 'edit_published_posts';
} elseif ( 'trash' == get_post_status($post_obj)) {
if ( 'publish' == get_post_meta( $post_ID, '_wp_trash_meta_status', true ) ) {
$caps[] = 'edit_published_posts';
}
} else {
// If the post is draft...
$caps[] = 'edit_posts';
}
}
break;
}
}
return $caps;
}
add_filter( 'map_meta_cap', 'filter_map_meta_cap_allow_nonauthor_to_save_post', 10, 4 );
@brandonjp
Copy link
Author

BACKGROUND

I spent forever trying to figure out why my filter for user_has_cap was not permitting allowed users to edit/save posts. The user could view the edit screen, but when they clicked Update button on a published post that they did not author/create, they would get an error: Sorry, you are not allowed to edit posts as this user . even though I was correctly setting all the required capabilities in my user_has_cap filter.

ISSUE

I finally tracked it down to this line in WordPress core post.php which basically was re-running a check to see if current_user_can( $ptype->cap->edit_others_posts ) which was overriding anything I used in my user_has_cap filter, like setting: $allcaps['edit_others_posts]=true && $allcaps['edit_published_posts]=true

SOURCES

Thanks to help from @jeremyclarke & @danielbachhuber via this trac ticket & this stackoverflow answer

NOTES ON THE SOLUTION IN THIS GIST

This was adapted from https://gist.github.com/danielbachhuber/18850d571c5dce419f8b for his plugin Co-Authors Plus, which might be a better solution for your needs.

If not, you'll need to customize the code above between line 49 and line 65 to run your checks to see if the user should be permitted to edit/save

My site has a Custom Post Type called custom-job stored in a custom table (custom_jobs) with custom taxonomy called project-managers with a custom field pm_related_user which stores a user ID. I'm using MetaBox.io for custom fields, posts types, taxonomies, views, etc., but none of that should matter as you'll be writing your own check for the user's permissions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment