# Developer Documentation

## Scope

This plugin is intended for front-end comment submissions and authenticated REST API comment creation. Auto-approval applies only when a user is logged in and the comment's `user_id` matches that session.

Import, CLI, cron, and other programmatic comment creation without a logged-in user are not affected; WordPress's default moderation and spam rules apply. To auto-approve comments created programmatically, set the approval status explicitly in your integration code.

## Open registration

When the "Anyone can register" setting is enabled, the plugin requires users to have a capability above the site's default role for new users before their comments bypass moderation or spam checks. Sites with closed registration are unaffected and continue to trust any logged-in registered user by default.

The minimum capability is determined from the default role:

* Roles without `edit_posts` (typically subscriber) require `edit_posts`.
* Roles with `edit_posts` but without `publish_posts` (typically contributor) require `publish_posts`.
* Roles that can already publish (typically author and above) require `publish_posts`.

Use the `c2c_never_moderate_registered_users_open_registration_caps` filter to customize this behavior for open registration sites.

## Privileged users setting

The "Trust only privileged users to bypass comment moderation and spam checks" checkbox on the Settings → Discussion admin page requires users to have the `publish_posts` or `moderate_comments` capability before their comments bypass moderation or spam checks. When enabled, this replaces the default behavior described above, including the open registration minimum capability.

Use the `c2c_never_moderate_registered_users_privileged_caps` filter to customize which capabilities identify privileged users.

## Hooks

The plugin exposes a number of filters and actions for hooking. Code using these hooks should ideally be put into a mu-plugin or site-specific plugin (which is beyond the scope of this readme to explain).

### `c2c_never_moderate_registered_users_open_registration_caps` _(filter)_

The `c2c_never_moderate_registered_users_open_registration_caps` filter allows you to customize the capabilities required to bypass moderation when open registration is enabled. It does not run when registration is closed.

#### Arguments:

* **$caps** _(array)_: Array of capabilities, one of which a user must have in order to bypass moderation checks on open registration sites. The default is a single capability derived from the site's default role (see [Open registration](#open-registration) above).

#### Example:

```php
/**
 * Require that users can publish posts when open registration is enabled.
 *
 * @param array $caps Trusted capabilities for open registration sites.
 * @return array
 */
function require_publish_posts_for_open_registration( $caps ) {
	return array( 'publish_posts' );
}
add_filter( 'c2c_never_moderate_registered_users_open_registration_caps', 'require_publish_posts_for_open_registration' );
```

### `c2c_never_moderate_registered_users_privileged_caps` _(filter)_

The `c2c_never_moderate_registered_users_privileged_caps` filter allows you to customize the capabilities that identify privileged users when the "Trust only privileged users" setting is enabled.

#### Arguments:

* **$caps** _(array)_: Array of capabilities, one of which a user must have in order to bypass moderation checks when the privileged users setting is enabled. Default is `publish_posts` and `moderate_comments`.

#### Example:

```php
/**
 * Require the edit_others_posts capability for privileged users.
 *
 * @param array $caps Privileged capabilities.
 * @return array
 */
function require_edit_others_posts_for_privileged_users( $caps ) {
	return array( 'edit_others_posts' );
}
add_filter( 'c2c_never_moderate_registered_users_privileged_caps', 'require_edit_others_posts_for_privileged_users' );
```

### `c2c_never_moderate_registered_users_caps` _(filter)_

The `c2c_never_moderate_registered_users_caps` filter allows you to define the capabilities that are automatically trusted, any one of which a user must have in order to never get moderated.

#### Arguments:

* **$caps** _(array)_: Array of capabilities, one of which a user must have in order to bypass moderation checks. Default is an empty array when registration is closed and the privileged users setting is disabled (meaning any registered user bypasses moderation checks). When open registration is enabled, the default is a single capability derived from the site's default role. When the privileged users setting is enabled, the default is the list of privileged capabilities. This filter runs after those defaults are determined.

#### Example:

```php
/**
 * Require that a user have at least the 'editor' role or the 'moderate_comments' capability
 * in order to be trusted enough not to be moderated.
 *
 * @param array $caps Array of trusted capabilities. If blank, then any user registered on the site is trusted.
 * @return array
 */
function dont_moderate_contributors( $caps ) {
	$caps[] = 'editor'; // a role
	$caps[] = 'moderate_comments'; // a capability
	return $caps;
}
add_filter( 'c2c_never_moderate_registered_users_caps', 'dont_moderate_contributors' );
```

### `c2c_never_moderate_registered_users_approved` _(filter)_

The `c2c_never_moderate_registered_users_approved` filter allows for granular control for whether a comment by a registered user that would otherwise be moderated or marked as spam should automatically be approved. Note: this filter only runs when a comment is from a registered user *and* is flagged for moderation or spam.

#### Note

Since WordPress 6.7, `wp_new_comment()` may invoke the `pre_comment_approved` filter twice for a single comment submitted via the standard front-end form: once inside `wp_allow_comment()`, and again after `wp_filter_comment()`. REST API comment creation typically invokes the filter only once, because it calls `wp_allow_comment()` directly without that second pass.

This plugin's main handler is idempotent, but the `c2c_never_moderate_registered_users_approved` filter may therefore run twice per front-end submission. Callbacks hooked to that filter should be idempotent and should not perform side effects such as logging or notifications; use the `c2c_never_moderate_registered_users_auto_approved` action for those instead.

#### Arguments:

* **$approved**    _(int|string)_ The approval status. Will be 1 unless changed by another plugin using this hook. May be passed 1, 0, or 'spam'. Hooking function can return any of those in addition to 'trash' or WP_Error.
* **$commentdata** _(array)_      Comment data.
* **$user**        _(WP_User)_    The commenting user.

#### Example:

```php
/**
 * Always moderate comments by registered users if they mention "Google".
 *
 * @param int|string $approved  Approval status. Will be one of 1, 0, 'spam', 'trash', or WP_Error.
 * @param array      $commentdata        Comment data.
 * @param WP_User    $user               The commenting user.
 * @return int|string|WP_Error Can a registered user's comment bypass moderation? Either 1, 0, 'spam', 'trash', or WP_Error.
 */
function c2c_even_registered_users_cannot_say_google( $approved, $commentdata, $user ) {
	if ( $approved && false !== stripos( $commentdata['comment_content'], 'google' ) ) {
		$approved = 0;
	}
	return $approved;
}
add_filter( 'c2c_never_moderate_registered_users_approved', 'c2c_even_registered_users_cannot_say_google', 10, 3 );
```

### `c2c_never_moderate_registered_users_auto_approved` _(action)_

The `c2c_never_moderate_registered_users_auto_approved` action fires after the plugin auto-approves a comment that would otherwise have been moderated or marked as spam, once the comment has been inserted. It runs only when the final approval status is approved (1). It does not run when the `c2c_never_moderate_registered_users_approved` filter changes the approval to something else, or when the comment was already approved before the plugin ran.

Use this action for side effects such as logging, auditing, or notifications. The `c2c_never_moderate_registered_users_approved` filter is intended for approval decisions and may run more than once per front-end submission; keep filter callbacks idempotent and avoid side effects there.

#### Note

The action is deferred to WordPress's `wp_insert_comment` hook so it fires once per inserted comment, even though `pre_comment_approved` may run twice during a front-end submission since WordPress 6.7.

#### Arguments:

* **$user**        _(WP_User)_ The commenting user.
* **$commentdata** _(array)_   Comment data.

#### Example:

```php
/**
 * Log when the plugin auto-approves a registered user's comment.
 *
 * @param WP_User $user        The commenting user.
 * @param array   $commentdata Comment data.
 */
function log_auto_approved_registered_user_comment( $user, $commentdata ) {
	error_log(
		sprintf(
			'Auto-approved comment by user %d on post %d.',
			$user->ID,
			$commentdata['comment_post_ID']
		)
	);
}
add_action( 'c2c_never_moderate_registered_users_auto_approved', 'log_auto_approved_registered_user_comment', 10, 2 );
```
