Support

Account

Home Forums Front-end Issues Frontend bbPress Media Upload fails if ACF is active

Solved

Frontend bbPress Media Upload fails if ACF is active

  • Hi all,

    I have a probably caused by me weird problem which I’ve narrowed down to something ACF is doing.

    I’m currently building a forum using bbPress. New topics and replies both can upload media using the Visual / Text Editor and Media Upload, i.e. it replicates wp-admin New Post.

    This in itself required some custom functions, including for bbPress Participants and Moderators roles, and WP Contributor role, giving them file upload capabilities with add_cap( ‘upload_files’ ).

    So far, so good. It all works. Unless ACF is involved.

    I’m using ACF for a couple of things, including handling Topic Tags so they have auto-complete capability, for some fairly complex event management, and for extending members’ profiles.

    When ACF is active, Participants uploading throws the following error:

    Sorry, you are not allowed to attach files to this post.

    This is generated in wp-admin/includes/ajax-actions.php:2512 by wp_ajax_upload_attachment()

    This doesn’t happen for other, higher bbPress roles. Changing Participants default WP roles to e.g. Editor or even Admin also doesn’t ‘fix’ it. Adding additional WP and bbPress capabilities to Participants doesn’t fix it either. But if I downgrade
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
    to e.g.
    if ( ! current_user_can( 'read', $post_id ) ) {
    uploading works. Obviously I’m not going to hack Core, this is just tracing the error.

    What does seem to fix it is this explanation and code:

    https://wordpress.stackexchange.com/questions/175346/add-media-upload-capabilities-needed-for-custom-role-for-non-posts

    function allow_own_attachments( $user_caps, $req_caps, $args, $UserObj ) {
    	if ( empty($args[2]) ) {
    		return $user_caps;  // nothing to check
    	}
    	$post = get_post( $args[2] );  // post_id was passed here
    
    	if (is_object($post)){  //check if $post is an object. If it isn't checked the code throws this Notice: Trying to get property 'post_author' of non-object 
    		if ( $post->post_author == $UserObj->ID ) {  // this is my post
    			foreach ( (array) $req_caps as $cap ) {
    				if ( empty( $user_caps[ $cap ] ) )
    					$user_caps[ $cap ] = true;
    			}
    		}
    	}
    
    	if ( current_user_can( 'bbp_participant' ) ) { // my addition
    		$user_caps['edit_post'] = true; // tested by wp_ajax_upload_attachment()
    	}
    	return $user_caps;
    }
    
    add_filter( 'user_has_cap', 'allow_own_attachments', 10, 4 );

    except I need to comment out

    if ( $post->post_author == $UserObj->ID ) {

    My understanding is that for a new Topic, at that point it somehow isn’t associated with the user, or I need to get the Topic author and user ID in another way.

    For the moment, I’ve commented out that line, but, while I understand what’s going on, I have no real idea of the consequences, especially around capabilities creep.

    So, does anyone have an actual idea what’s happening? Is this an ok way to resolve it?

    Thanks,

    Francesca

  • I do not know if this will help you or not. When I was building my options page admin plugin I ran into a similar situation. My plugin creates a post type to store settings for each ACF options page created. One of the settings is the post ID to use to store the options values to just like you can do when creating an options page through code. One of the settings is to save the values to the post created by the plugin. So, for example if you create an options page and the settings create a post id of “1234” then all the values from the options page will be saved against post “1234”.

    Everything for this worked fine except for attachments. This happened when an “editor” or “author” tried to update an options page that they were allowed to edit. This is due to the plugin (by default) requiring that the user has the “manage_options” capability in order to create/edit options pages.

    What I had to do was temporarily alter the users capabilities to allow the uploads. I did this by adding a filter on the “user_has+cap” hook.

    
    add_filter('user_has_cap', 'your_function_name', 10, 4);
    

    Here is the function with as much explanation as I can give

    
    function your_function_name($allcaps, $caps, $args, $user) {
      if (!defined('DOING_AJAX') || !DOING_AJAX || // files are uploaded using ajax
          !isset($_REQUEST['post_id']) || // the ajax request includes the "post_id"
          !in_array('edit_post', $args) // the user is edtitng a post
      ) {
        // this happens if
        //    1) the request is not an ajax request
        //    2) the post ID is not included in the AJAX request
        //    3) the user is doing anything other than editing a post
        return $allcaps;
      }
      $id = intval($_REQUEST['post_id']);
      if (get_post_type($id) != $this->post_type ||  // post being edited matches the post typr of the post
          !isset($this->options_pages[$id]) // the post ID is a post in this post type
      ) {
        // in my case this is part of a class with the post type name defined in the class
        // $this->options_pages is an array of all of the currently active options page settings
        // this happens if the post type being edited is not an active options page
        return $allcaps;
      }
      // remove this filter to prevent infinite loop
      remove_filter('user_has_cap', 'your_function_name', 10);
      
      // get the options page setting from the option pages array
      $page = $this->options_pages[$id];
      // get the capability needed to edit values on this options page
      $cap = $page['acf']['capability'];
      // check to see if the current user has the capability required to edit
      // the options page being edited
      if (current_user_can($cap)) {
        // this user is allowed to edit the options page
        // add all $caps to $allcaps
        // what this does is temporarily grant the user with all capabilities
        // as if they have the "manage_options" capability
        foreach ($caps as $add) {
          $allcaps[$add] = true;
        }
      }
      // readd this filter
      add_filter('user_has_cap', 'your_function_name', 10, 4);
      return $allcaps;
    }
    
  • Hi John,

    firstly thanks so much for your detailed reply!

    I was looking into it a bit more and thought the problem might have stemmed from a separate function redirecting non-admins out of wp-admin if they tried to access it. e.g.

    https://support.advancedcustomfields.com/forums/topic/front-end-form-image-upload-issues/#post-14656

    Which didn’t fix it.

    But did point me in (hopefully 😬) the right direction comparing it to your function.

    The primary issue with my ‘user_has_cap’ function was it caused capabilities creep, giving participants the ability to edit others’ topics.

    Prefacing my function with your ‘DOING_AJAX’ block seems to fix it: participants can upload and don’t have edit or mod rights for others’ topics.

    Thanks again!

    Francesca

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.