Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions src/wp-includes/class-wp-comment-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,33 @@ final class WP_Comment_Type {
*/
public $internal = false;

/**
* The string to use to build the read, edit, and delete capabilities.
*
* May be registered as an array to allow for alternative plurals when using
* this argument as a base to construct the capabilities, e.g.
* array( 'story', 'stories' ). set_props() collapses the array form back to
* the singular base once the capabilities are built. Default 'comment'.
*
* @since 7.1.0
* @var string
*/
public $capability_type = 'comment';

/**
* Capabilities for this comment type.
*
* Built by {@see get_comment_type_capabilities()} from the
* `capability_type` and `capabilities` arguments. This is advisory metadata
* describing the capabilities associated with the comment type; the
* capability mapping in {@see map_meta_cap()} is not affected by this
* property in this release.
*
* @since 7.1.0
* @var stdClass
*/
public $cap;

/**
* Whether this comment type is a native or "built-in" comment type.
*
Expand Down Expand Up @@ -183,17 +210,28 @@ public function set_props( $args ) {
* treated as a provided value and overwrite the default name with false.
*/
$defaults = array(
'labels' => array(),
'description' => '',
'public' => true,
'internal' => false,
'_builtin' => false,
'labels' => array(),
'description' => '',
'public' => true,
'internal' => false,
'capability_type' => 'comment',
'capabilities' => array(),
'_builtin' => false,
);

$args = array_merge( $defaults, $args );

$args['name'] = $this->name;

// Build the capabilities object, then remove the input array from the props.
$this->cap = get_comment_type_capabilities( (object) $args );
unset( $args['capabilities'] );

// Collapse an array capability type back to its singular base.
if ( is_array( $args['capability_type'] ) ) {
$args['capability_type'] = $args['capability_type'][0];
}

foreach ( $args as $property_name => $property_value ) {
$this->$property_name = $property_value;
}
Expand Down
116 changes: 103 additions & 13 deletions src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,19 +361,31 @@ function create_initial_comment_types() {
* @param array|string $args {
* Optional. Array or string of arguments for registering a comment type. Default empty array.
*
* @type string $label Name of the comment type. Usually plural.
* Default is the value of $labels['name'].
* @type string[] $labels An array of labels for this comment type. If not set, the
* default comment labels are used. See get_comment_type_labels()
* for a full list of supported labels.
* @type string $description A short descriptive summary of what the comment type is.
* Default empty.
* @type bool $public Whether the comment type is intended for use publicly either via
* the admin interface or by front-end users. Core does not
* currently act on this argument. Default true.
* @type bool $internal Whether the comment type is for internal use only. Core does not
* currently consult this flag; it is intended to drive default
* query exclusions in the future. Default false.
* @type string $label Name of the comment type. Usually plural.
* Default is the value of $labels['name'].
* @type string[] $labels An array of labels for this comment type. If not set, the
* default comment labels are used. See
* get_comment_type_labels() for a full list of supported
* labels.
* @type string $description A short descriptive summary of what the comment type is.
* Default empty.
* @type bool $public Whether the comment type is intended for use publicly
* either via the admin interface or by front-end users.
* Core does not currently act on this argument.
* Default true.
* @type bool $internal Whether the comment type is for internal use only. Core
* does not currently consult this flag; it is intended to
* drive default query exclusions in the future.
* Default false.
* @type string|array $capability_type The string to use to build the read, edit, and delete
* capabilities. May be passed as an array to allow for
* alternative plurals when using this argument as a base to
* construct the capabilities, e.g. array( 'story', 'stories' ).
* Default 'comment'.
* @type string[] $capabilities Array of capabilities for this comment type.
* $capability_type is used as a base to construct
* capabilities by default.
* See get_comment_type_capabilities().
* }
* @return WP_Comment_Type|WP_Error The registered comment type object on success,
* WP_Error object on failure.
Expand Down Expand Up @@ -611,6 +623,84 @@ function get_comment_type_labels( $comment_type_object ) {
return $labels;
}

/**
* Builds an object with all comment type capabilities out of a comment type object.
*
* Comment type capabilities use the `capability_type` argument as a base, if
* the capability is not set in the `capabilities` argument.
*
* This is advisory metadata describing the capabilities associated with a comment
* type, modeled on {@see get_post_type_capabilities()}. The capability mapping in
* {@see map_meta_cap()} is not affected by these capabilities in this release.
*
* The capability strings are built from the `capability_type` argument, which may
* be a string or an array. When a string, the plural is created by appending an
* 's'. When an array, the first element is the singular base and the second the
* plural base, e.g. array( 'story', 'stories' ).
*
* Note: With the default `capability_type` of 'comment', most of the generated
* primitive capabilities (`edit_comments`, `edit_others_comments`,
* `delete_comments`) exist in no default role and are not consulted by the
* default capability mapping; `moderate_comments` is the only generated
* primitive that default roles grant. Consumers should check the meta
* capabilities together with a comment ID instead of testing those primitives
* directly.
*
* Note: The `capability_type` property of the passed object is normalized to
* its array form as a side effect of calling this function, matching
* get_post_type_capabilities().
*
* @since 7.1.0
*
* @param object $args Comment type registration arguments. Expects the
* `capability_type` and `capabilities` properties.
* @return object {
* Object with all the capabilities as member variables.
*
* @type string $edit_comment Meta capability to edit a comment of this type.
* Default 'edit_comment'.
* @type string $read_comment Meta capability to read a comment of this type.
* Default 'read_comment'.
* @type string $delete_comment Meta capability to delete a comment of this type.
* Default 'delete_comment'.
* @type string $moderate_comment Meta capability to moderate a comment of this type.
* Default 'moderate_comment'.
* @type string $edit_comments Primitive capability to edit comments of this type.
* Default 'edit_comments'.
* @type string $edit_others_comments Primitive capability to edit comments of this type
* authored by other users. Default 'edit_others_comments'.
* @type string $delete_comments Primitive capability to delete comments of this type.
* Default 'delete_comments'.
* @type string $moderate_comments Primitive capability to moderate comments of this type.
* Default 'moderate_comments'.
* }
*/
function get_comment_type_capabilities( $args ) {
if ( ! is_array( $args->capability_type ) ) {
$args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
}

// Singular base for meta capabilities, plural base for primitive capabilities.
list( $singular_base, $plural_base ) = $args->capability_type;

$default_capabilities = array(
// Meta capabilities.
'edit_comment' => 'edit_' . $singular_base,
'read_comment' => 'read_' . $singular_base,
'delete_comment' => 'delete_' . $singular_base,
'moderate_comment' => 'moderate_' . $singular_base,
// Primitive capabilities used outside of map_meta_cap().
'edit_comments' => 'edit_' . $plural_base,
'edit_others_comments' => 'edit_others_' . $plural_base,
'delete_comments' => 'delete_' . $plural_base,
'moderate_comments' => 'moderate_' . $plural_base,
);

$capabilities = array_merge( $default_capabilities, $args->capabilities );

return (object) $capabilities;
}

/**
* Retrieves all of the WordPress supported comment statuses.
*
Expand Down
117 changes: 117 additions & 0 deletions tests/phpunit/tests/comment/types.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,121 @@ public function test_registered_comment_type_action_receives_type_and_object() {
$this->assertInstanceOf( 'WP_Comment_Type', $args[0][1] );
$this->assertSame( 'foo', $args[0][1]->name );
}

/**
* @ticket 35214
*/
public function test_registered_comment_type_exposes_cap_object() {
register_comment_type( 'foo', array( 'capability_type' => 'review' ) );

$cobj = get_comment_type_object( 'foo' );

$this->assertSame( 'edit_reviews', $cobj->cap->edit_comments );
$this->assertSame( 'moderate_reviews', $cobj->cap->moderate_comments );
}

/**
* The built-in comment type's capabilities match the existing core comment capabilities.
*
* @ticket 35214
*/
public function test_built_in_comment_type_capabilities_are_backward_compatible() {
$cobj = get_comment_type_object( 'comment' );

$this->assertSame( 'edit_comment', $cobj->cap->edit_comment );
$this->assertSame( 'moderate_comments', $cobj->cap->moderate_comments );
}

/**
* @ticket 35214
*
* @covers ::get_comment_type_capabilities
*/
public function test_get_comment_type_capabilities_from_string() {
$caps = get_comment_type_capabilities(
(object) array(
'capability_type' => 'review',
'capabilities' => array(),
)
);

$this->assertSame( 'edit_review', $caps->edit_comment );
$this->assertSame( 'edit_reviews', $caps->edit_comments );
$this->assertSame( 'edit_others_reviews', $caps->edit_others_comments );
$this->assertSame( 'delete_review', $caps->delete_comment );
$this->assertSame( 'moderate_reviews', $caps->moderate_comments );
}

/**
* @ticket 35214
*
* @covers ::get_comment_type_capabilities
*/
public function test_get_comment_type_capabilities_honors_capabilities_override() {
$caps = get_comment_type_capabilities(
(object) array(
'capability_type' => 'comment',
'capabilities' => array(
'edit_comments' => 'manage_stuff',
),
)
);

$this->assertSame( 'manage_stuff', $caps->edit_comments );
}

/**
* The full set of meta and primitive capabilities is generated from the base.
*
* @ticket 35214
*
* @covers ::get_comment_type_capabilities
*/
public function test_get_comment_type_capabilities_generates_full_set() {
$caps = get_comment_type_capabilities(
(object) array(
'capability_type' => 'review',
'capabilities' => array(),
)
);

$expected = array(
// Meta capabilities.
'edit_comment' => 'edit_review',
'read_comment' => 'read_review',
'delete_comment' => 'delete_review',
'moderate_comment' => 'moderate_review',
// Primitive capabilities.
'edit_comments' => 'edit_reviews',
'edit_others_comments' => 'edit_others_reviews',
'delete_comments' => 'delete_reviews',
'moderate_comments' => 'moderate_reviews',
);

$this->assertSame( $expected, (array) $caps );
}

/**
* An array capability type supplies an explicit plural base for primitive caps.
*
* @ticket 35214
*
* @covers ::get_comment_type_capabilities
*/
public function test_get_comment_type_capabilities_from_array() {
$caps = get_comment_type_capabilities(
(object) array(
'capability_type' => array( 'story', 'stories' ),
'capabilities' => array(),
)
);

// Singular base drives the meta capabilities.
$this->assertSame( 'edit_story', $caps->edit_comment );
$this->assertSame( 'read_story', $caps->read_comment );
// Explicit plural base drives the primitive capabilities.
$this->assertSame( 'edit_stories', $caps->edit_comments );
$this->assertSame( 'delete_stories', $caps->delete_comments );
$this->assertSame( 'moderate_stories', $caps->moderate_comments );
}
}
Loading
Loading