Cho phép người dùng chỉ có thể chỉnh sửa, chỉnh sửa


7

Tôi muốn thêm một vài biên tập viên có thể edit_others_posts , nhưng tôi không muốn họ có thể xuất bản bài đăng của người khác, chỉ lưu bài đăng bằng cách nhấp vào nút Gửi để xem xét .

Tôi có thể làm cái này như thế nào?

EDIT: Để giải thích điều này một cách chi tiết. Hiện tại, chúng tôi không thể cho phép người dùng chỉnh sửa bài đăng của người khác bằng cách chỉ lưu bài đăng. Nếu edit_others_postđược kích hoạt cho người dùng, sau đó họ có thể xuất bản bài đăng.

Quy trình làm việc tôi đang hướng tới:

  1. Người chỉnh sửa chỉ có thể chỉnh sửa bài đăng khác đang chờ xử lý ( giải quyết tại đây ).
  2. Người chỉnh sửa có thể lưu bài đăng đang chờ xử lý nhưng không xuất bản. Vì vậy, nút Gửi để đánh giá sẽ có sẵn cho họ (đó là nút "cập nhật bài đăng" khi bài đăng ở chế độ chờ xử lý)

Vì vậy, bạn muốn ngăn người dùng của một vai trò nhất định có thể thay đổi trạng thái bài viết?
Tom J Nowell

@TomJNowell Xem câu hỏi cập nhật của tôi với các chi tiết khác.
Christine Cooper

Bạn đã thử các hành động chuyển đổi trạng thái bài? (lõi tìm kiếm)
kaiser

Không nghe nói về điều này cho đến nay. Làm thế nào nó hoạt động trong khía cạnh này?
Christine Cooper

Ví dụ câu hỏi về móc chuyển tiếp bài.
kaiser

Câu trả lời:


8

Nếu tôi hiểu rõ, người dùng có vai trò đặc biệt trong trang web của bạn nên:

  • Có thể chỉnh sửa bài đăng của riêng mình trong tất cả các trạng thái nhưng 'xuất bản' và không thể xuất bản chúng, chỉ cần gửi để sửa đổi
  • Chỉ có thể chỉnh sửa các bài đăng của người khác khi đang chờ xử lý, nhưng không thể xuất bản chúng, chỉ cần gửi để sửa đổi
  • Không bao giờ có thể xóa các bài viết khác, bất kể trạng thái

Nếu vậy, dường như đối với tôi một vai trò giống với 'tác giả' hơn là 'biên tập viên'.

Chỉ khác với tác giả là

  • người dùng vai trò của bạn không thể chỉnh sửa các bài đăng được xuất bản, ngay cả khi họ là tác giả
  • người dùng vai trò của bạn có thể chỉnh sửa các bài đăng khác đang chờ xử lý nhưng không xuất bản chúng

Vì vậy, đề xuất đầu tiên tôi có thể đưa ra là tạo một vai trò tùy chỉnh, sử dụng vai trò 'tác giả' làm điểm thoát, loại bỏ 3 giới hạn không mong muốn và thêm một tùy chỉnh, một lớp đơn giản thực hiện điều đó:

class CustomEditorRole {

  private static $role = 'authorplus';
  private $role_label;

  function __construct() {
    // here we need a real, loaded, text domain
    $this->role_label = __( 'Author +', 'yout-txt-dmn' );
  }

  function addRole() {
    global $wp_roles;
    if ( ! $wp_roles instanceof WP_Roles ) {
      $wp_roles = new WP_Roles;
    }
    $author = get_role( 'author' ); 
    $caps = $author->capabilities; // start with author capabilities
    $caps['publish_posts'] = FALSE;
    $caps['edit_published_posts'] = FALSE;
    $caps['delete_published_posts'] = FALSE;
    $caps['edit_others_pending_posts'] = TRUE; // custom cap
    // create new role with custom caps
    add_role( self::$role, $this->role_label, $caps );
  }

  function removeRole() {
    global $wp_roles;
    if ( ! $wp_roles instanceof WP_Roles ) {
      $wp_roles = new WP_Roles;
    }
    remove_role(self::$role);
  }

}

Hãy thêm hành động kích hoạt / hủy kích hoạt plugin:

register_activation_hook( __FILE__, array( new CustomEditorRole, 'addRole' ) );
register_deactivation_hook( __FILE__, array( new CustomEditorRole, 'removeRole' ) );

Ở đây tôi giả sử mã trước đó là trong tập tin plugin chính.

Các khả năng chúng tôi đặt ở trên là hợp lệ cho mọi bài đăng, bất kể tác giả bài đăng hoặc trạng thái bài đăng, Bây giờ chúng tôi phải cho phép người dùng với vai trò tùy chỉnh của mình để chỉnh sửa bài đăng của người khác khi chờ xử lý.

Vấn đề đầu tiên chúng tôi gặp phải là trên màn hình danh sách bài đăng ( edit.php), nếu khả năng edit_others_postskhông được kích hoạt cho người dùng (và đối với vai trò tùy chỉnh của chúng tôi thì không), thì các bài đăng của người dùng khác sẽ không được hiển thị trong danh sách, vì bị loại khỏi truy vấn và khi truy vấn xảy ra, chúng tôi không có quyền truy cập vào dữ liệu bài đăng, vì vậy chúng tôi chỉ cần gán khả năng, trạng thái bài đăng quan trọng, ít nhất là cho đến khi truy vấn chạy.

Vấn đề thứ hai là, khi lưu, trước khi cấp cho người dùng với vai trò tùy chỉnh edit_others_postsgiới hạn, chúng tôi phải kiểm tra không chỉ trạng thái hiện tại là "đang chờ xử lý" mà còn người dùng không cố gắng thay đổi nó. Điều đó có thể được thực hiện nhìn vào thông tin trong $_POSTdữ liệu. Điều đó có nghĩa là chúng ta cần 2 "thói quen", một là chạy trên màn hình quản trị ( edit.phppost.php) thứ hai chạy trong khi lưu bài.

Cách cung cấp cho người dùng vai trò tùy chỉnh của chúng tôi edit_others_postkhả năng chỉ dành cho các bài đăng đang chờ xử lý là thêm bộ lọc vào 'user_has_cap'.

Trong cuộc gọi lại bộ lọc, chúng ta có thể thực hiện quy trình công việc này:

  1. kiểm tra xem khả năng lọc có phải là một trong 2 chúng tôi muốn quản lý không ( 'edit-post'hoặc 'edit-others-posts', kiểm tra xem chúng tôi có trong quản trị viên hay không, kiểm tra xem người dùng có khả năng tùy chỉnh của chúng tôi không và đó không phải là trình chỉnh sửa hoặc quản trị viên. tiếp tục, nếu không chúng ta không phải làm gì, tức là trả lại các khả năng ban đầu
  2. kiểm tra xem chúng tôi có tiết kiệm hay không và chạy 2 thói quen khác nhau:
    • Thói quen khi tiết kiệm
    • Thường xuyên khi không tiết kiệm

Thói quen khi tiết kiệm:

  1. kiểm tra xem hành động hiện tại là chỉnh sửa bài
  2. lấy thông tin bài đăng từ dữ liệu $ _POST, kiểm tra xem bài đăng có đúng loại bài đăng không và đang chờ xử lý
  3. kiểm tra xem trạng thái chờ xử lý chỉ có thể được thay đổi bởi quản trị viên hoặc biên tập viên "thực"
  4. nếu tất cả các kiểm tra trước đó vượt qua, hãy gán cho người dùng 'edit-others-posts'khả năng ( 'edit-post'sẽ được ánh xạ tự động)

Thói quen khi không tiết kiệm:

  1. Kiểm tra xem chúng tôi có ở một trong 2 màn hình quan tâm không, nếu không, không làm gì cả
  2. hành vi khác nhau tùy thuộc vào khả năng lọc:
    • Khi khả năng lọc là 'edit-others-posts'chúng tôi không có dữ liệu bài đăng, vì vậy chỉ cần gán nó nhưng chỉ trước khi truy vấn chính chưa xảy ra và chỉ trên edit.phpmàn hình
    • khi khả năng lọc được 'edit-post'lấy dữ liệu bài đăng và nếu bài đăng đang chờ xử lý, hãy gán cho người dùng 'edit-others-posts'giới hạn ( 'edit-post'sẽ được ánh xạ tự động)

Có điều cuối cùng phải làm. Sử dụng vai trò tùy chỉnh quy trình công việc được mô tả, người dùng sẽ không thể xem trước các bài đăng đang chờ xử lý khác, ngay cả khi họ có thể chỉnh sửa chúng.

Chúng ta có thể lọc lại khả năng, nhưng có một cách đơn giản hơn: trong khi truy vấn chính (sử dụng một trong số hàng chục hook được kích hoạt WP_Query), chúng ta chỉ có thể lấy $wp_post_statuses['pending']đối tượng và đặt thuộc tính của nó publicthành true khi người dùng hiện tại có vai trò tùy chỉnh của chúng ta: hiệu ứng duy nhất là rằng các bài đăng đang chờ xử lý có thể xem trước và một khi chúng tôi không thay đổi bất kỳ khả năng nào, chúng tôi có thể giữ an toàn.

Ok, chỉ cần dịch các từ trong mã:

class CustomEditorCaps {

  function manageCaps( $allcaps, $caps, $args, $user ) {    
    if ( ! $this->shouldManage( $args[0], $user ) ) {
      return $allcaps;
    }
    // Are we saving?
    $action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_STRING );
    $method = strtoupper(filter_var($_SERVER['REQUEST_METHOD'], FILTER_SANITIZE_STRING ));
    if ( $method !== 'POST' ) { // not saving
      global $pagenow;
      // we are interested only on post list and  post edit screens
      if (
        is_admin()
        && in_array( $pagenow, array( 'post.php', 'post-new.php', 'edit.php' ), TRUE
      ) ) {
        $screen_id = $pagenow === 'edit.php' ? 'edit-post' : 'post';
        $allcaps = $this->maybeAllow( $args, $allcaps, $user, $screen_id );
      }
    } elseif ( $action === 'editpost' ) { // saving and right action
      $allcaps = $this->maybeAllowOnSave( $args, $allcaps, $user  );
    }
    return $allcaps; // always return: it's a filter
  }

  function lockPendingStatus( $data, $postarr ) {
    if (
       isset( $postarr['ID'] )
       && ! empty($postarr['ID'])
       && $data['post_type'] === 'post' // 'post' post type
       && $data['post_status'] !== 'pending' // a non pending status
       && ! current_user_can( 'delete_others_posts' ) // current user is not an admin
    ) {
       $orig = get_post_status( $postarr['ID'] ); 
       if ( $orig === 'pending' ) { // hey post was pending!
          $data['post_status'] = 'pending'; // let's restore pending status
       }
    }
    return $data; // always return: it's a filter
  }

  function allowPreview( $posts, $query ) {
    if ( is_admin()
      || ! $query->is_main_query()
      || empty( $posts )
      || ! $query->is_single
      || $posts[0]->post_type !== 'post'
    ) {
      return $posts; // return first argument: it's a filter
    }
    $status = get_post_status( $posts[0] );
    $post_status_obj = get_post_status_object( $status );
    if (
      ! $post_status_obj->public
      && $status === 'pending'
      && current_user_can('edit_others_pending_posts')
    ) {
      // post is pending and our user has our special role
      // allow preview
      global $wp_post_statuses;
      $wp_post_statuses[$status]->public = TRUE;
    }
    return $posts; // return first argument: it's a filter
  }

  private function maybeAllow( $args, $allcaps, $user, $screen ) {
    if ( $args[0] === 'edit_others_posts' ) {
      // if filtering 'edit_others_posts' we have no access to single post data
      // allow cap only on post list screen and before querying posts
      $allcaps['edit_others_posts'] = ! did_action('pre_get_posts')
        && $screen === 'edit-post';
      return $allcaps;
    }
    $post = get_post( $args[2] );
    if (  $post->post_status === 'pending' ) {
      $allcaps['edit_others_posts'] = TRUE;
    }
    return $allcaps; // always return: it's a filter
  }

  private function maybeAllowOnSave( $args, $allcaps, $user ) {
    $data = $this->getPostedData();
    if ( $data['post_type'] !== 'post' || (int) $data['post_ID'] <= 0 ) {
      return $allcaps;
    }
    $post = get_post( $data['post_ID'] );
    if (
      $post->post_status === 'pending'
      && $data['original_post_status'] === 'pending'
      && ( empty( $data['post_status'] ) || $data['post_status'] === 'pending' )
    ) {
      // if post is pending and will stay pending allow editing
      $allcaps['edit_others_posts'] = true;
    }
    return $allcaps;
  }

  private function shouldManage( $cap, $user ) {
    return is_admin() // not affect frontend
      && in_array( $cap, array( 'edit_others_posts', 'edit_post' ), TRUE )
      && ! $user->has_cap( 'delete_others_posts' ) // real editor or more
      && $user->has_cap( 'edit_others_pending_posts' ) // our role
      && ! defined( 'DOING_AJAX' ); // does not affect ajax
  }

  private function getPostedData() {
    return filter_input_array( INPUT_POST, array(
      'post_type'            => FILTER_SANITIZE_STRING,
      'post_ID'              => FILTER_SANITIZE_NUMBER_INT,
      'original_post_status' => FILTER_SANITIZE_STRING,
      'post_status'          => FILTER_SANITIZE_STRING,
    ) );
  }

}

Và thêm 2 móc liên quan: một để lọc 'user_has_cap', một để đảm bảo trạng thái chờ xử lý chỉ có thể được thay đổi bởi quản trị viên hoặc người chỉnh sửa thực và bộ lọc cuối cùng 'posts_results'để cho phép xem trước:

$cap_manager = new CustomEditorCaps;
add_filter( 'user_has_cap', array( $cap_manager, 'manageCaps' ), PHP_INT_MAX, 4 );
add_filter( 'posts_results', array( $cap_manager, 'allowPreview' ), 10, 2 );
add_filter( 'wp_insert_post_data', array( $cap_manager, 'lockPendingStatus' ), 10, 2 );

Khi bạn có tất cả mã này trong một plugin và bạn kích hoạt nó, bạn chỉ phải gán cho người dùng mà plugin vai trò tùy chỉnh tạo ra.


Tất cả mã có sẵn dưới dạng plugin, trong Gist ở đây .


1
+ gmazzap rằng ý chính không còn nữa
mawalker

1
@mawalker đã cập nhật liên kết Gist, ngay cả khi đó không phải là một số mã tôi sẽ tự hào về ngày hôm nay ...
gmazzap
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.