Files
rangerhq-logbook/inc/wp-notes-display.php
ranger 35920fea07 feat: persist empty-state notice dismissal via user_meta
The "No active/completed notes found" notice was already dismissible
per-page-load (WP core's X button hides it), but pressing X only
cleared it for the current view — it returned on the next refresh.
The dismissal is now persisted to user_meta per-user-per-list-type,
so once closed it stays closed across page loads until the flag is
reset.

MECHANICS
- inc/wp-notes-display.php now checks get_user_meta(uid,
  'wp_notes_dismissed_empty_<type>') before rendering and skips the
  notice render entirely when set.
- New AJAX handler wp_ajax_wp_notes_dismiss_empty validates a nonce
  and the edit_posts capability, then writes the flag via
  update_user_meta(). type=active|completed; anything else 400s.
- An inline jQuery handler in wp_notes_add_inline_scripts() listens
  for clicks on .wp-notes-empty .notice-dismiss (WP core's auto-
  injected X button) and fires the AJAX call. The visual hide is
  still WP core's job.
- The notice element carries data-wp-notes-empty-type and a fresh
  per-render data-wp-notes-nonce for the round trip.

RESET
The flag is per-user-meta keyed wp_notes_dismissed_empty_active /
wp_notes_dismissed_empty_completed. wp_delete_user removes them
automatically. A UI button to reset dismissed notices is not built
yet — flagged in the changelog as a future enhancement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:57:26 +01:00

133 lines
6.6 KiB
PHP

<?php
// inc/wp-notes-display.php
if (!defined('ABSPATH')) {
exit;
}
/**
* Display notes list with consistent styling and functionality
*
* @param string $type Either 'active' or 'completed'
* @return void
*/
function wp_notes_display_notes($type = 'active') {
// Get notes and validate user permissions
if (!current_user_can('edit_posts')) {
return;
}
$notes = ($type === 'active') ? get_option('wp_notes', array()) : get_option('wp_done_notes', array());
$page_anchor = ($type === 'active') ? '#active-notes' : '#completed-notes';
$section_title = ($type === 'active') ? 'Active Notes' : 'Completed Notes';
if (empty($notes)) {
/* Per-user persistent dismissal: if the current user has
dismissed the empty-state notice for this list type before,
we skip rendering it entirely. The flag stays set until they
explicitly reset it (or until we extend this to auto-clear
when a note is created — Option B for a future iteration).
Flag key: wp_notes_dismissed_empty_active / _completed. */
$dismiss_meta_key = 'wp_notes_dismissed_empty_' . $type;
if (get_user_meta(get_current_user_id(), $dismiss_meta_key, true)) {
return;
}
$nonce = wp_create_nonce('wp_notes_dismiss_empty');
printf(
'<div class="wp-notes-empty notice notice-info is-dismissible" data-wp-notes-empty-type="%1$s" data-wp-notes-nonce="%2$s"><p>%3$s</p></div>',
esc_attr($type),
esc_attr($nonce),
esc_html__('No ' . ($type === 'active' ? 'active' : 'completed') . ' notes found.', 'a-wp-notes')
);
return;
}
// Section header with status count
$status_class = ($type === 'active') ? 'status-active' : 'status-completed';
echo '<div class="wp-notes-section">';
echo '<h2 class="wp-notes-section-title">';
echo '<span class="' . $status_class . '">' . esc_html($section_title) . '</span>';
echo '<span class="note-count">(' . count($notes) . ')</span>';
echo '</h2>';
echo '<div class="wp-notes-list" id="' . esc_attr($type . '-notes') . '">';
echo '<table class="wp-list-table widefat fixed striped has-hover">';
echo '<thead><tr>';
/* No checkbox column — bulk actions are not wired up. Re-add this <th>
and the matching <td> below when bulk select/delete/done is built. */
echo '<th scope="col" class="manage-column column-primary">' . esc_html__('Note', 'a-wp-notes') . '</th>';
echo '<th scope="col" class="manage-column">' . esc_html__('Author', 'a-wp-notes') . '</th>';
echo '<th scope="col" class="manage-column">' . esc_html__('Created', 'a-wp-notes') . '</th>';
if ($type === 'completed') {
echo '<th scope="col" class="manage-column">' . esc_html__('Completed By', 'a-wp-notes') . '</th>';
echo '<th scope="col" class="manage-column">' . esc_html__('Completed On', 'a-wp-notes') . '</th>';
}
echo '<th scope="col" class="manage-column">' . esc_html__('Actions', 'a-wp-notes') . '</th>';
echo '</tr></thead><tbody>';
foreach ($notes as $key => $note) {
$text = esc_html($note['text']);
$color = esc_attr($note['color'] ?? '#000000');
$size = esc_attr($note['size'] ?? '14');
$font = esc_attr($note['font'] ?? 'Arial');
$timestamp = esc_html($note['timestamp'] ?? current_time('mysql'));
$author = esc_html($note['author_name'] ?? 'Unknown');
echo '<tr>';
echo '<td style="color: ' . $color . '; font-size: ' . $size . 'px; font-family: ' . $font . ';">' . $text . '</td>';
echo '<td>' . $author . '</td>';
echo '<td>' . $timestamp . '</td>';
if ($type === 'completed') {
echo '<td>' . esc_html($note['completed_by'] ?? 'Unknown') . '</td>';
echo '<td>' . esc_html($note['completed_on'] ?? 'Unknown') . '</td>';
}
echo '<td class="actions">';
if ($type === 'active') {
echo '<button type="button" class="button edit-note" data-note-id="' . esc_attr($key) . '">' .
esc_html__('Edit', 'a-wp-notes') . '</button> ';
echo '<form method="post" style="display:inline;">';
echo '<input type="hidden" name="note_id" value="' . esc_attr($key) . '">';
echo '<button type="submit" name="mark_done" class="button">' .
esc_html__('Mark as Done', 'a-wp-notes') . '</button>';
echo '</form>';
} else {
echo '<form method="post" style="display:inline;">';
echo '<input type="hidden" name="note_id" value="' . esc_attr($key) . '">';
echo '<button type="submit" name="restore_note" class="button">' .
esc_html__('Restore', 'a-wp-notes') . '</button>';
echo '</form>';
}
echo '</td></tr>';
// Edit form (for active notes only)
if ($type === 'active') {
/* Active rows have 4 columns: Note, Author, Created, Actions
(no longer a checkbox column). Edit form spans all 4. */
echo '<tr id="edit-note-' . esc_attr($key) . '" style="display:none;"><td colspan="4">';
echo '<form class="edit-note-form" data-note-id="' . esc_attr($key) . '">';
wp_nonce_field('wp_notes_nonce', '_wpnonce');
echo '<input type="hidden" name="note_id" value="' . esc_attr($key) . '">';
echo '<textarea name="new_text" class="large-text">' . esc_textarea($text) . '</textarea><br>';
echo '<div class="formatting-options">';
echo '<input type="color" name="edit_color" value="' . esc_attr($color) . '">';
echo '<input type="number" name="edit_size" value="' . esc_attr($size) . '" min="8" max="72">';
echo '<select name="edit_font">';
echo '<option value="Arial" ' . selected('Arial', $font, false) . '>Arial</option>';
echo '<option value="Helvetica" ' . selected('Helvetica', $font, false) . '>Helvetica</option>';
echo '<option value="Times New Roman" ' . selected('Times New Roman', $font, false) . '>Times New Roman</option>';
echo '<option value="Verdana" ' . selected('Verdana', $font, false) . '>Verdana</option>';
echo '</select>';
echo '</div>';
echo '<button type="submit" class="button button-primary">' . esc_html__('Save', 'a-wp-notes') . '</button>';
echo '<button type="button" class="button cancel-edit">' . esc_html__('Cancel', 'a-wp-notes') . '</button>';
echo '</form>';
echo '</td></tr>';
}
}
echo '</tbody></table></div>';
}