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
49 changes: 43 additions & 6 deletions src/wp-includes/class-wp-comment-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,32 @@ final class WP_Comment_Type {
*/
public $show_ui;

/**
* 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'.
*
* @since 7.1.0
* @var string|array
*/
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 @@ -187,12 +213,14 @@ 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,
'show_ui' => null,
'_builtin' => false,
'labels' => array(),
'description' => '',
'public' => true,
'internal' => false,
'show_ui' => null,
'capability_type' => 'comment',
'capabilities' => array(),
'_builtin' => false,
);

$args = array_merge( $defaults, $args );
Expand All @@ -204,6 +232,15 @@ public function set_props( $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
59 changes: 57 additions & 2 deletions src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,16 @@ function create_initial_comment_types() {
* the admin interface or by front-end users. Default true.
* @type bool $internal Whether the comment type is for internal use only and should be
* excluded from default public-facing contexts. Default false.
* @type bool $show_ui Whether to generate and allow a UI for managing this comment type
* in the admin. Default is value of $public.
* @type bool $show_ui Whether to generate and allow a UI for managing this comment
* type in the admin. Default is value of $public.
* @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 @@ -569,6 +577,53 @@ 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' ).
*
* @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.
*/
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 @@ -291,4 +291,121 @@ static function ( $labels ) {

$this->assertSame( 'Filtered Foo', get_comment_type_object( 'foo' )->labels->singular_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 );
}
}
77 changes: 77 additions & 0 deletions tests/phpunit/tests/comment/wpCommentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,81 @@ public function test_reset_default_labels_clears_cache() {
$labels = WP_Comment_Type::get_default_labels();
$this->assertSame( 'Comments', $labels['name'][0] );
}

/**
* @ticket 35214
*
* @covers ::set_props
*/
public function test_default_capability_type_and_cap_object() {
$comment_type = new WP_Comment_Type( 'foo' );

$this->assertSame( 'comment', $comment_type->capability_type );
$this->assertIsObject( $comment_type->cap );
$this->assertSame( 'edit_comment', $comment_type->cap->edit_comment );
$this->assertSame( 'moderate_comments', $comment_type->cap->moderate_comments );
}

/**
* @ticket 35214
*
* @covers ::set_props
*/
public function test_custom_capability_type_builds_cap_object() {
$comment_type = new WP_Comment_Type( 'foo', array( 'capability_type' => 'review' ) );

$this->assertSame( 'review', $comment_type->capability_type );
$this->assertSame( 'edit_review', $comment_type->cap->edit_comment );
$this->assertSame( 'edit_reviews', $comment_type->cap->edit_comments );
$this->assertSame( 'moderate_reviews', $comment_type->cap->moderate_comments );
}

/**
* An array capability type allows an explicit plural and is collapsed to its singular base.
*
* @ticket 35214
*
* @covers ::set_props
*/
public function test_array_capability_type_uses_explicit_plural() {
$comment_type = new WP_Comment_Type( 'foo', array( 'capability_type' => array( 'story', 'stories' ) ) );

$this->assertSame( 'story', $comment_type->capability_type );
$this->assertSame( 'edit_story', $comment_type->cap->edit_comment );
$this->assertSame( 'edit_stories', $comment_type->cap->edit_comments );
}

/**
* @ticket 35214
*
* @covers ::set_props
*/
public function test_capabilities_argument_overrides_generated_caps() {
$comment_type = new WP_Comment_Type(
'foo',
array(
'capability_type' => 'review',
'capabilities' => array(
'moderate_comments' => 'manage_reviews',
),
)
);

$this->assertSame( 'manage_reviews', $comment_type->cap->moderate_comments );
// Non-overridden caps are still generated from the capability type.
$this->assertSame( 'edit_reviews', $comment_type->cap->edit_comments );
}

/**
* The input `capabilities` array is consumed and not kept as a public property.
*
* @ticket 35214
*
* @covers ::set_props
*/
public function test_capabilities_input_is_not_retained_as_property() {
$comment_type = new WP_Comment_Type( 'foo', array( 'capabilities' => array( 'edit_comments' => 'x' ) ) );

$this->assertObjectNotHasProperty( 'capabilities', $comment_type );
}
}
Loading