Users can’t upload images on frontend if they haven’t got access to the wp backend

First, it is important to consider why you are restricting access to wp-admin. If you are doing this mainly for aesthetic purposes, then the solution provided below is fine. However, if you are doing it because you don’t want your users to be able to perform certain functions provided via the back-end, you should be using WordPress’s built-in roles and capabilities API instead. Give your users a role with only those capabilities that you want them to have. Otherwise, granting access to the Ajax actions will probably allow them to do things that you were trying to prevent them from doing.

Which brings us to the cause of your problem. Ajax is involved in uploading the image, and the Ajax handler (wp-admin/admin-ajax.php) is technically back-end, even when called from the front end. So your code hooked to 'admin_init' is being triggered. What you need to do is check if the request is an Ajax request in that function, and only exit/redirect if it is not. Since WP 4.7, you can now use the wp_doing_ajax() function for this.

function redirect_non_admin_users() {
    if ( wp_doing_ajax() ) {
        return; // Don't block Ajax requests.
    }

    if ( ! current_user_can( 'manage_options' ) && '/wp-admin/admin-ajax.php' != $_SERVER['PHP_SELF'] ) {
        wp_redirect( home_url() );
        exit;
    }
}
add_action( 'admin_init', 'redirect_non_admin_users' );

If you only want to allow your users access to uploading attachments, you could probably change the condition to this:

    if ( wp_doing_ajax() && isset( $_POST['action'] ) && 'upload-attachment' === $_POST['action'] ) {
        return; // Don't block attachment upload requests.
    }

However, note that many plugins provide their own Ajax actions as well, which would be blocked in this case. So you will be better off using the role and capability API, as stated above.

Leave a Comment