Last active
May 1, 2023 22:37
-
-
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."
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 clickedUpdate
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 myuser_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 ifcurrent_user_can( $ptype->cap->edit_others_posts )
which was overriding anything I used in myuser_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 calledproject-managers
with a custom fieldpm_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.