Skip to content
Merged
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
4 changes: 4 additions & 0 deletions projects/packages/forms/changelog/add-forms-unread-state
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Forms: add read and unread state
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,29 @@ public function register_routes() {
'callback' => array( $this, 'get_forms_config' ),
)
);

// Mark feedback as read/unread endpoint.
register_rest_route(
$this->namespace,
$this->rest_base . '/(?P<id>\d+)/read',
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'update_read_status' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => array(
'id' => array(
'type' => 'integer',
'required' => true,
'sanitize_callback' => 'absint',
),
'is_unread' => array(
'type' => 'boolean',
'required' => true,
'sanitize_callback' => 'rest_sanitize_boolean',
),
),
)
);
}

/**
Expand Down Expand Up @@ -488,6 +511,16 @@ public function get_item_schema() {
'readonly' => true,
);

$schema['properties']['is_unread'] = array(
'description' => __( 'Whether the form response is unread.', 'jetpack-forms' ),
'type' => 'boolean',
'context' => array( 'view', 'edit', 'embed' ),
'arg_options' => array(
'sanitize_callback' => 'rest_sanitize_boolean',
),
'readonly' => true,
);

$this->schema = $schema;

return $this->add_additional_fields_schema( $this->schema );
Expand Down Expand Up @@ -631,6 +664,10 @@ public function prepare_item_for_response( $item, $request ) {
$data['has_file'] = $feedback_response->has_file();
}

if ( rest_is_field_included( 'is_unread', $fields ) ) {
$data['is_unread'] = $feedback_response->is_unread();
}

$response->set_data( $data );

return rest_ensure_response( $response );
Expand Down Expand Up @@ -1033,6 +1070,45 @@ public function disable_integration( $request ) {
return rest_ensure_response( array( 'deleted' => $is_deleted ) );
}

/**
* Updates the read/unread status of a feedback item.
*
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_read_status( $request ) {
$post_id = $request->get_param( 'id' );
$is_unread = $request->get_param( 'is_unread' );

$feedback_response = Feedback::get( $post_id );
if ( ! $feedback_response ) {
return new WP_Error(
'rest_post_invalid_id',
__( 'Invalid feedback ID.', 'jetpack-forms' ),
array( 'status' => 404 )
);
}

$success = $is_unread ? $feedback_response->mark_as_unread() : $feedback_response->mark_as_read();

Contact_Form_Plugin::recalculate_unread_count();
if ( ! $success ) {
return new WP_Error(
'rest_cannot_update',
__( 'Failed to update feedback read status.', 'jetpack-forms' ),
array( 'status' => 500 )
);
}

return rest_ensure_response(
array(
'id' => $post_id,
'is_unread' => $feedback_response->is_unread(),
'count' => Contact_Form_Plugin::get_unread_count(),
)
);
}

/**
* Return consolidated Forms config payload.
*
Expand Down
119 changes: 71 additions & 48 deletions projects/packages/forms/src/contact-form/class-contact-form-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1406,70 +1406,93 @@ public function allow_feedback_rest_api_type( $post_types ) {
* Display the count of new feedback entries received. It's reset when user visits the Feedback screen.
*
* @since 4.1.0
*
* @param object $screen Information about the current screen.
*/
public function unread_count( $screen ) {
if ( isset( $screen->post_type ) && 'feedback' === $screen->post_type || $screen->id === 'jetpack_page_jetpack-forms-admin' ) {
update_option( 'feedback_unread_count', 0 );
} else {
global $submenu, $menu;
if ( apply_filters( 'jetpack_forms_use_new_menu_parent', true ) && current_user_can( 'edit_pages' ) ) {
// show the count on Jetpack and Jetpack → Forms
$unread = get_option( 'feedback_unread_count', 0 );

if ( $unread > 0 && isset( $submenu['jetpack'] ) && is_array( $submenu['jetpack'] ) && ! empty( $submenu['jetpack'] ) ) {
$forms_unread_count_tag = " <span class='count-{$unread} awaiting-mod'><span>" . number_format_i18n( $unread ) . '</span></span>';
$jetpack_badge_count = $unread;

// Main menu entries
foreach ( $menu as $index => $main_menu_item ) {
if ( isset( $main_menu_item[1] ) && 'jetpack_admin_page' === $main_menu_item[1] ) {
// Parse the menu item
$jetpack_menu_item = $this->parse_menu_item( $menu[ $index ][0] );

if ( isset( $jetpack_menu_item['badge'] ) && is_numeric( $jetpack_menu_item['badge'] ) && intval( $jetpack_menu_item['badge'] ) ) {
$jetpack_badge_count += intval( $jetpack_menu_item['badge'] );
}
public function unread_count() {

if ( isset( $jetpack_menu_item['count'] ) && is_numeric( $jetpack_menu_item['count'] ) && intval( $jetpack_menu_item['count'] ) ) {
$jetpack_badge_count += intval( $jetpack_menu_item['count'] );
}
global $submenu, $menu;
if ( apply_filters( 'jetpack_forms_use_new_menu_parent', true ) && current_user_can( 'edit_pages' ) ) {
// show the count on Jetpack and Jetpack → Forms
$unread = self::get_unread_count();

$jetpack_unread_tag = " <span class='count-{$jetpack_badge_count} awaiting-mod'><span>" . number_format_i18n( $jetpack_badge_count ) . '</span></span>';
if ( isset( $submenu['jetpack'] ) && is_array( $submenu['jetpack'] ) && ! empty( $submenu['jetpack'] ) ) {
$inline_style = ( $unread > 0 ) ? '' : 'style="display: none;"';

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$menu[ $index ][0] = $jetpack_menu_item['title'] . ' ' . $jetpack_unread_tag;
$forms_unread_count_tag = " <span class='jp-feedback-unread-counter count-{$unread} awaiting-mod' {$inline_style}><span class='feedback-unread-counter'>" . number_format_i18n( $unread ) . '</span></span>';
$jetpack_badge_count = $unread;

// Main menu entries
foreach ( $menu as $index => $main_menu_item ) {
if ( isset( $main_menu_item[1] ) && 'jetpack_admin_page' === $main_menu_item[1] ) {
// Parse the menu item
$jetpack_menu_item = $this->parse_menu_item( $menu[ $index ][0] );

if ( isset( $jetpack_menu_item['badge'] ) && is_numeric( $jetpack_menu_item['badge'] ) && intval( $jetpack_menu_item['badge'] ) ) {
$jetpack_badge_count += intval( $jetpack_menu_item['badge'] );
}
}

// Jetpack submenu entries
foreach ( $submenu['jetpack'] as $index => $menu_item ) {
if ( 'jetpack-forms-admin' === $menu_item[2] ) {
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$submenu['jetpack'][ $index ][0] .= $forms_unread_count_tag;
if ( isset( $jetpack_menu_item['count'] ) && is_numeric( $jetpack_menu_item['count'] ) && intval( $jetpack_menu_item['count'] ) ) {
$jetpack_badge_count += intval( $jetpack_menu_item['count'] );
}

$jetpack_unread_tag = " <span data-unread-diff='" . ( $jetpack_badge_count - $unread ) . "' class='jp-feedback-unread-counter count-{$jetpack_badge_count} awaiting-mod'><span class='feedback-unread-counter'>" . number_format_i18n( $jetpack_badge_count ) . '</span></span>';

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$menu[ $index ][0] = $jetpack_menu_item['title'] . ' ' . $jetpack_unread_tag;
}
}

// Jetpack submenu entries
foreach ( $submenu['jetpack'] as $index => $menu_item ) {
if ( 'jetpack-forms-admin' === $menu_item[2] ) {
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$submenu['jetpack'][ $index ][0] .= $forms_unread_count_tag;
}
}
return;
}
if ( isset( $submenu['feedback'] ) && is_array( $submenu['feedback'] ) && ! empty( $submenu['feedback'] ) ) {
foreach ( $submenu['feedback'] as $index => $menu_item ) {
if ( 'edit.php?post_type=feedback' === $menu_item[2] ) {
$unread = get_option( 'feedback_unread_count', 0 );
if ( $unread > 0 ) {
$unread_count = current_user_can( 'publish_pages' ) ? " <span class='feedback-unread count-{$unread} awaiting-mod'><span class='feedback-unread-count'>" . number_format_i18n( $unread ) . '</span></span>' : '';

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$submenu['feedback'][ $index ][0] .= $unread_count;
}
break;
return;
}

if ( isset( $submenu['feedback'] ) && is_array( $submenu['feedback'] ) && ! empty( $submenu['feedback'] ) ) {
foreach ( $submenu['feedback'] as $index => $menu_item ) {
if ( 'edit.php?post_type=feedback' === $menu_item[2] ) {
$unread = self::get_unread_count();

if ( $unread > 0 ) {
$unread_count = current_user_can( 'publish_pages' ) ? " <span class='feedback-unread jp-feedback-unread-counter count-{$unread} awaiting-mod'><span class='feedback-unread-count'>" . number_format_i18n( $unread ) . '</span></span>' : '';

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$submenu['feedback'][ $index ][0] .= $unread_count;
}
break;
}
}
}
}

/**
* Get the count of unread feedback entries.
*
* @since $$next-version$$
*
* @return int The count of unread feedback entries.
*/
public static function get_unread_count() {
return (int) get_option( 'jetpack_feedback_unread_count', 0 ); // previously defaulted named "feedback_unread_count".
}

/**
* Recalculate the count of unread feedback entries.
*
* @since $$next-version$$
*
* @return int The count of unread feedback entries.
*/
public static function recalculate_unread_count() {
$count = Feedback::get_unread_count();
update_option( 'jetpack_feedback_unread_count', $count );
return $count;
}

/**
* Handles all contact-form POST submissions
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1929,9 +1929,7 @@ public function process_submission() {
update_post_meta( $post_id, '_feedback_extra_fields', $this->addslashes_deep( $extra_values ) );

if ( 'publish' === $feedback_status ) {
// Increase count of unread feedback.
$unread = (int) get_option( 'feedback_unread_count', 0 ) + 1;
update_option( 'feedback_unread_count', $unread );
Contact_Form_Plugin::recalculate_unread_count();
}

if ( defined( 'AKISMET_VERSION' ) ) {
Expand Down
Loading
Loading