Skip to content

Commit a841fbc

Browse files
enejbsimison
authored andcommitted
Update the sidebar counter to match
Replaces legacy unread feedback count logic with new static methods in Contact_Form_Plugin and Feedback classes, storing the count in a new option. Updates backend to recalculate and return the unread count after marking feedback as read/unread. Frontend now updates the admin menu counter dynamically using the new count from the server, improving accuracy and consistency.
1 parent ea4283b commit a841fbc

File tree

7 files changed

+140
-57
lines changed

7 files changed

+140
-57
lines changed

projects/packages/forms/src/contact-form/class-contact-form-endpoint.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ public function update_read_status( $request ) {
10911091

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

1094+
Contact_Form_Plugin::recalculate_unread_count();
10941095
if ( ! $success ) {
10951096
return new WP_Error(
10961097
'rest_cannot_update',
@@ -1103,6 +1104,7 @@ public function update_read_status( $request ) {
11031104
array(
11041105
'id' => $post_id,
11051106
'is_unread' => $feedback_response->is_unread(),
1107+
'count' => Contact_Form_Plugin::get_unread_count(),
11061108
)
11071109
);
11081110
}

projects/packages/forms/src/contact-form/class-contact-form-plugin.php

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,70 +1406,91 @@ public function allow_feedback_rest_api_type( $post_types ) {
14061406
* Display the count of new feedback entries received. It's reset when user visits the Feedback screen.
14071407
*
14081408
* @since 4.1.0
1409-
*
1410-
* @param object $screen Information about the current screen.
14111409
*/
1412-
public function unread_count( $screen ) {
1413-
if ( isset( $screen->post_type ) && 'feedback' === $screen->post_type || $screen->id === 'jetpack_page_jetpack-forms-admin' ) {
1414-
update_option( 'feedback_unread_count', 0 );
1415-
} else {
1416-
global $submenu, $menu;
1417-
if ( apply_filters( 'jetpack_forms_use_new_menu_parent', true ) && current_user_can( 'edit_pages' ) ) {
1418-
// show the count on Jetpack and Jetpack → Forms
1419-
$unread = get_option( 'feedback_unread_count', 0 );
1420-
1421-
if ( $unread > 0 && isset( $submenu['jetpack'] ) && is_array( $submenu['jetpack'] ) && ! empty( $submenu['jetpack'] ) ) {
1422-
$forms_unread_count_tag = " <span class='count-{$unread} awaiting-mod'><span>" . number_format_i18n( $unread ) . '</span></span>';
1423-
$jetpack_badge_count = $unread;
1424-
1425-
// Main menu entries
1426-
foreach ( $menu as $index => $main_menu_item ) {
1427-
if ( isset( $main_menu_item[1] ) && 'jetpack_admin_page' === $main_menu_item[1] ) {
1428-
// Parse the menu item
1429-
$jetpack_menu_item = $this->parse_menu_item( $menu[ $index ][0] );
1430-
1431-
if ( isset( $jetpack_menu_item['badge'] ) && is_numeric( $jetpack_menu_item['badge'] ) && intval( $jetpack_menu_item['badge'] ) ) {
1432-
$jetpack_badge_count += intval( $jetpack_menu_item['badge'] );
1433-
}
1410+
public function unread_count() {
14341411

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

1439-
$jetpack_unread_tag = " <span class='count-{$jetpack_badge_count} awaiting-mod'><span>" . number_format_i18n( $jetpack_badge_count ) . '</span></span>';
1417+
if ( $unread > 0 && isset( $submenu['jetpack'] ) && is_array( $submenu['jetpack'] ) && ! empty( $submenu['jetpack'] ) ) {
1418+
$forms_unread_count_tag = " <span class='jp-feedback-unread-counter count-{$unread} awaiting-mod'><span class='feedback-unread-counter'>" . number_format_i18n( $unread ) . '</span></span>';
1419+
$jetpack_badge_count = $unread;
14401420

1441-
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1442-
$menu[ $index ][0] = $jetpack_menu_item['title'] . ' ' . $jetpack_unread_tag;
1421+
// Main menu entries
1422+
foreach ( $menu as $index => $main_menu_item ) {
1423+
if ( isset( $main_menu_item[1] ) && 'jetpack_admin_page' === $main_menu_item[1] ) {
1424+
// Parse the menu item
1425+
$jetpack_menu_item = $this->parse_menu_item( $menu[ $index ][0] );
1426+
1427+
if ( isset( $jetpack_menu_item['badge'] ) && is_numeric( $jetpack_menu_item['badge'] ) && intval( $jetpack_menu_item['badge'] ) ) {
1428+
$jetpack_badge_count += intval( $jetpack_menu_item['badge'] );
14431429
}
1444-
}
14451430

1446-
// Jetpack submenu entries
1447-
foreach ( $submenu['jetpack'] as $index => $menu_item ) {
1448-
if ( 'jetpack-forms-admin' === $menu_item[2] ) {
1449-
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1450-
$submenu['jetpack'][ $index ][0] .= $forms_unread_count_tag;
1431+
if ( isset( $jetpack_menu_item['count'] ) && is_numeric( $jetpack_menu_item['count'] ) && intval( $jetpack_menu_item['count'] ) ) {
1432+
$jetpack_badge_count += intval( $jetpack_menu_item['count'] );
14511433
}
1434+
1435+
$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>';
1436+
1437+
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1438+
$menu[ $index ][0] = $jetpack_menu_item['title'] . ' ' . $jetpack_unread_tag;
1439+
}
1440+
}
1441+
1442+
// Jetpack submenu entries
1443+
foreach ( $submenu['jetpack'] as $index => $menu_item ) {
1444+
if ( 'jetpack-forms-admin' === $menu_item[2] ) {
1445+
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1446+
$submenu['jetpack'][ $index ][0] .= $forms_unread_count_tag;
14521447
}
14531448
}
1454-
return;
14551449
}
1456-
if ( isset( $submenu['feedback'] ) && is_array( $submenu['feedback'] ) && ! empty( $submenu['feedback'] ) ) {
1457-
foreach ( $submenu['feedback'] as $index => $menu_item ) {
1458-
if ( 'edit.php?post_type=feedback' === $menu_item[2] ) {
1459-
$unread = get_option( 'feedback_unread_count', 0 );
1460-
if ( $unread > 0 ) {
1461-
$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>' : '';
1462-
1463-
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1464-
$submenu['feedback'][ $index ][0] .= $unread_count;
1465-
}
1466-
break;
1450+
return;
1451+
}
1452+
1453+
if ( isset( $submenu['feedback'] ) && is_array( $submenu['feedback'] ) && ! empty( $submenu['feedback'] ) ) {
1454+
foreach ( $submenu['feedback'] as $index => $menu_item ) {
1455+
if ( 'edit.php?post_type=feedback' === $menu_item[2] ) {
1456+
$unread = self::get_unread_count();
1457+
1458+
if ( $unread > 0 ) {
1459+
$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>' : '';
1460+
1461+
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
1462+
$submenu['feedback'][ $index ][0] .= $unread_count;
14671463
}
1464+
break;
14681465
}
14691466
}
14701467
}
14711468
}
14721469

1470+
/**
1471+
* Get the count of unread feedback entries.
1472+
*
1473+
* @since $$next-version$$
1474+
*
1475+
* @return int The count of unread feedback entries.
1476+
*/
1477+
public static function get_unread_count() {
1478+
return (int) get_option( 'feedback_unread_count_v2', 0 );
1479+
}
1480+
1481+
/**
1482+
* Recalculate the count of unread feedback entries.
1483+
*
1484+
* @since $$next-version$$
1485+
*
1486+
* @return int The count of unread feedback entries.
1487+
*/
1488+
public static function recalculate_unread_count() {
1489+
$count = Feedback::get_unread_count();
1490+
update_option( 'feedback_unread_count_v2', $count );
1491+
return $count;
1492+
}
1493+
14731494
/**
14741495
* Handles all contact-form POST submissions
14751496
*

projects/packages/forms/src/contact-form/class-contact-form.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,9 +1929,7 @@ public function process_submission() {
19291929
update_post_meta( $post_id, '_feedback_extra_fields', $this->addslashes_deep( $extra_values ) );
19301930

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

19371935
if ( defined( 'AKISMET_VERSION' ) ) {

projects/packages/forms/src/contact-form/class-feedback.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,24 @@ public function mark_as_unread() {
795795
return false;
796796
}
797797

798+
/**
799+
* Get the count of unread feedback entries.
800+
*
801+
* @return int
802+
*/
803+
public static function get_unread_count() {
804+
$query = new \WP_Query(
805+
array(
806+
'post_type' => self::POST_TYPE,
807+
'post_status' => 'publish',
808+
'comment_status' => self::STATUS_UNREAD,
809+
'posts_per_page' => -1,
810+
'fields' => 'ids',
811+
)
812+
);
813+
return (int) $query->found_posts;
814+
}
815+
798816
/**
799817
* Get the uploaded files from the feedback entry.
800818
*

projects/packages/forms/src/dashboard/inbox/dataviews/actions.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@ import { store as noticesStore } from '@wordpress/notices';
77
import { notSpam, spam } from '../../icons';
88
import { store as dashboardStore } from '../../store';
99
import InboxResponse from '../response';
10+
/**
11+
* Update the unread count in the admin menu.
12+
*
13+
* @param {number} count - The new unread count.
14+
*/
15+
export const updateMenuCounter = count => {
16+
// iterate over all elements with the class 'feedback-unread-counter' and update their text content
17+
document.querySelectorAll( '.jp-feedback-unread-counter' ).forEach( item => {
18+
if ( item.dataset.unreadDiff ) {
19+
const newCount = parseInt( item.dataset.unreadDiff, 10 ) + count;
20+
item.textContent = newCount > 0 ? newCount : '';
21+
item.style.display = newCount > 0 ? '' : 'none';
22+
} else {
23+
item.textContent = count > 0 ? count : '';
24+
item.style.display = count > 0 ? '' : 'none';
25+
}
26+
} );
27+
};
1028

1129
export const BULK_ACTIONS = {
1230
markAsSpam: 'mark_as_spam',
@@ -320,7 +338,16 @@ export const markAsReadAction = {
320338
path: `/wp/v2/feedback/${ id }/read`,
321339
method: 'POST',
322340
data: { is_unread: false },
323-
} );
341+
} )
342+
.then( ( { count } ) => {
343+
// Update the unread count in the store.
344+
updateMenuCounter( count );
345+
} )
346+
.catch( () => {
347+
// Revert the change in the store if the server update fails.
348+
editEntityRecord( 'postType', 'feedback', id, { is_unread: true } );
349+
throw new Error( 'Failed to mark as read' );
350+
} );
324351
} )
325352
);
326353
if ( promises.every( ( { status } ) => status === 'fulfilled' ) ) {
@@ -376,7 +403,16 @@ export const markAsUnreadAction = {
376403
path: `/wp/v2/feedback/${ id }/read`,
377404
method: 'POST',
378405
data: { is_unread: true },
379-
} );
406+
} )
407+
.then( ( { count } ) => {
408+
// Update the unread count in the store.
409+
updateMenuCounter( count );
410+
} )
411+
.catch( () => {
412+
// Revert the change in the store if the server update fails.
413+
editEntityRecord( 'postType', 'feedback', id, { is_unread: false } );
414+
throw new Error( 'Failed to mark as unread' );
415+
} );
380416
} )
381417
);
382418
if ( promises.every( ( { status } ) => status === 'fulfilled' ) ) {

projects/packages/forms/src/dashboard/inbox/response.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import clsx from 'clsx';
2727
import CopyClipboardButton from '../components/copy-clipboard-button';
2828
import Gravatar from '../components/gravatar';
2929
import { useMarkAsSpam } from '../hooks/use-mark-as-spam';
30+
import { updateMenuCounter } from './dataviews/actions';
3031
import { getPath } from './utils';
3132

3233
const getDisplayName = response => {
@@ -320,10 +321,15 @@ const InboxResponse = ( { response, loading, onModalStateChange } ) => {
320321
path: `/wp/v2/feedback/${ response.id }/read`,
321322
method: 'POST',
322323
data: { is_unread: false },
323-
} ).catch( error => {
324-
// eslint-disable-next-line no-console
325-
console.error( 'Failed to mark feedback as read:', error );
326-
} );
324+
} )
325+
.then( ( { count } ) => {
326+
updateMenuCounter( count );
327+
} )
328+
.catch( () => {
329+
editEntityRecord( 'postType', 'feedback', response.id, {
330+
is_unread: true,
331+
} );
332+
} );
327333
}, [ response, editEntityRecord ] );
328334

329335
const handelImageLoaded = useCallback( () => {

projects/packages/forms/tests/php/contact-form/Contact_Form_Endpoint_Test.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,10 +738,12 @@ public function test_mark_feedback_as_read() {
738738
$response = $this->server->dispatch( $request );
739739
$data = $response->get_data();
740740
$this->assertFalse( $data['is_unread'] );
741+
$this->assertIsInt( 0, Contact_Form_Plugin::get_unread_count() );
741742

742743
// Verify Feedback class method
743744
$feedback = \Automattic\Jetpack\Forms\ContactForm\Feedback::get( $post_id );
744745
$this->assertFalse( $feedback->is_unread() );
746+
$this->assertIsInt( 1, Contact_Form_Plugin::get_unread_count() );
745747
}
746748

747749
/**

0 commit comments

Comments
 (0)