0

What is the right action to invoke before a custom post type is getting edited in dashboard and contains the argument the post id? The url /wp-admin/post.php?post=282&action=edit&classic-editor

here is what I try

    $userId = get_current_user_id();
    $affiliate = get_field('field_627ff399b5ef6', 'user_' . $userId);

    $this->currentAffiliate = $affiliate;

    $subPages = get_children([
        'post_parent' => $affiliate[0]->ID,
        'post_type' => 'affiliate',
    ]);

    $pageIds = collect($subPages)->pluck('ID')->push($affiliate[0]->ID)->toArray();

if edit page ID is not in $pageIds redirect to the not allowed screen

2
  • There are many actions/filters which fire which are passed the post ID. Which one is "right" depends on what you are attempting to accomplish
    – bosco
    Jun 2, 2022 at 18:03
  • I would like deny the access if the ID is not in the allowed range
    – fefe
    Jun 2, 2022 at 18:05

1 Answer 1

0

Ideally access controls would be implemented via WordPress's Roles and Capabilities system. But in highly-granular cases such as limiting access to a single post to a few users, the map_meta_cap filter can be used to shim in additional restrictions.

In this case, when WordPress is testing an edit_post capability for a user/post combination, we can deny access based on your custom meta field:

function wpse406371_restrict_affiliate_page_edit( $caps, $cap, $user_id, $args ) {
  if( $cap !== 'edit_post' )
    return $caps;

  $post_id = $args[0];

  if( get_post_type( $post_id ) !== 'affiliate' )
    return $caps;

  $affiliate = get_field( 'field_627ff399b5ef6', 'user_' . $user_id );

  if( empty( $affiliate ) )
    return $caps;

  $affiliate_page_id = $affiliate[0]->ID;

  if( $post_id == $affiliate_page_id )
    return $caps;

  $affiliate_child_page_ids = get_children([
    'post_type'   => 'affiliate',
    'post_parent' => $affiliate_page_id,
    'fields'      => 'ids',
  ]);

  if( !in_array( $post_id, $affiliate_child_page_ids ) )
    $caps[] = 'do_not_allow';

  return $caps;
}

add_filter( 'map_meta_cap', 'wpse406371_restrict_affiliate_page_edit', 10, 4 );

The above will be executed whenever WordPress tests a user's capabilities for an action. In the cases that the capability check is not for editing a post, the post is not an affiliate-type, or the user does not have field_627ff399b5ef6 meta-data, the check will return the unmodified capabilities early in order to mitigate additional work.

Checking if the post being edited is the parent affiliate post is performed early in order to skip the post query if possible.

I've also added the 'fields' => 'ids' argument to the child page query to save on overhead by only retrieving post IDs instead of querying full rows - but I still feel this could be an overly-expensive operation on a capabilities check. You might consider caching the post IDs in user meta sometime in the future should you determine that the query adds notable overhead.

Finally, if the current post's ID is not present in the queried ID list, the function adds the do_not_allow capability which will natively deny the user access. This will effect all core methods of editing a post - the Quick Edit form, via REST API, etc.

1
  • Thanks a lot for your Feedback! I'm not sure if is the right way to go, because initially I call my custom class on admin_init which would check for current_user_can('affiliate-editor') the class would add some capabilities on role/posttype (add_cap) than calling globals $pagenow, $typeof I check for ` if ($typenow == 'affiliate' && $pagenow === 'edit.php')` I make pre_get_-posts hook for the list page. Right after if I call the map_meta_caphook will throw me error because missing arguments
    – fefe
    Jun 3, 2022 at 7:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.