Restrict editing of post type to list stored in user meta

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.