Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9df37a35e8 | |||
| 431c31a95b | |||
| c5d8a34296 |
@@ -9,6 +9,94 @@ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [3.4.2] — 2026-05-27
|
||||||
|
|
||||||
|
### Fixed — Restore actually works now (v3.4.1 was incomplete)
|
||||||
|
|
||||||
|
David retested after v3.4.1 and reported the same symptom: *"the restore still not working."*
|
||||||
|
|
||||||
|
Root cause (the real one): the per-row Restore form in `inc/wp-notes-display.php` sends a hidden `$_POST['note_id']` (singular) when the button is clicked — but the handler in `wp_notes_page_callback()` was checking for `$_POST['done_ids']` (plural), an array of IDs that used to come from bulk-action checkboxes **removed in v3.1.0**. So the handler's `isset($_POST['done_ids'])` guard was always false, the handler body never ran, and clicking Restore was a no-op all the way back to v3.1.0. The bug was masked before v3.4.0 because the page re-rendered with both Active and Completed sections visible, so the user could see the (unchanged) completed note still sitting there and assume they'd misclicked. v3.4.0's single-pane render made the no-op symptom unmissable.
|
||||||
|
|
||||||
|
The v3.4.1 redirect added inside the handler was syntactically correct but never reached — the entire `if` block was dead code.
|
||||||
|
|
||||||
|
Fix: rewrite the handler to match the working **single-note** mark-done handler pattern that lives just above it:
|
||||||
|
|
||||||
|
- Check `isset($_POST['note_id'])` (singular) instead of `done_ids` (plural array)
|
||||||
|
- `absint()` the ID for sanitization
|
||||||
|
- `isset($done_notes[$note_id])` lookup instead of iterating with `in_array()`
|
||||||
|
- Move the note across with the existing `restored_by` annotation
|
||||||
|
- Keep the redirect-to-Active-tab from v3.4.1
|
||||||
|
|
||||||
|
The handler now mirrors the pattern of the mark-done handler that's been working all along.
|
||||||
|
|
||||||
|
### Why this took two attempts to fix
|
||||||
|
|
||||||
|
v3.4.1's diagnosis stopped at the missing redirect — which was real but not load-bearing because the handler body was unreachable. Lesson recorded: when a handler appears to "do nothing", verify it's being entered at all (matching `$_POST` keys) before assuming the issue is downstream (missing redirect, failed update, etc.).
|
||||||
|
|
||||||
|
### Files changed
|
||||||
|
|
||||||
|
- `wp-notes.php` — Restore handler rewritten (lines around 1340). The change replaces the old bulk-checkbox-era handler with a single-note handler matching the live form. Adds a load-bearing comment block recording the v3.4.1/v3.4.2 bug history so future-Claude understands why the structure mirrors mark-done.
|
||||||
|
- Plugin header `Version: 3.4.1 → 3.4.2`; `WP_NOTES_VERSION` constant updated to match. PATCH bump (bug fix).
|
||||||
|
|
||||||
|
### Not changed
|
||||||
|
|
||||||
|
- The display code in `inc/wp-notes-display.php` — the form was already correct; the handler was the one out of sync.
|
||||||
|
- The Active and Completed tabs, storage model, CSS, other handlers — all unchanged.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [3.4.1] — 2026-05-27
|
||||||
|
|
||||||
|
### Fixed — Restore button now sends you to the Active tab where the restored note lives
|
||||||
|
|
||||||
|
After v3.4.0 introduced the Active/Completed tab strip, clicking **Restore** on a completed note appeared to "do something" but the restored note never showed up. David reported it as *"the complete log does not return to active."*
|
||||||
|
|
||||||
|
Root cause: the Restore action handler in `wp_notes_page_callback()` (line ~1340) was the **only** action handler in the file without a `wp_redirect() + exit;` after its `update_option()` calls — every other handler (new note, mark-as-done single, mark-as-done bulk) had one. So Restore was relying on the page falling through and re-rendering, which used to work when both Active and Completed sections rendered on the same page (the user could just glance up to see the restored note in the Active section). v3.4.0's single-pane tab render exposed the latent bug: after Restore, the URL still said `?tab=completed`, so only Completed re-rendered (minus the now-restored note), and the restored note was invisible on Active.
|
||||||
|
|
||||||
|
Fix: add the missing redirect to `admin.php?page=wp-notes` (which defaults to the Active tab) after the restore completes. The restored note now appears in its new home immediately.
|
||||||
|
|
||||||
|
### Files changed
|
||||||
|
|
||||||
|
- `wp-notes.php` — `wp_notes_page_callback()` Restore handler: added `wp_redirect(admin_url('admin.php?page=wp-notes')); exit;` after the two `update_option()` calls. Five-line change plus a load-bearing comment explaining the bug history so future-Claude doesn't reintroduce it.
|
||||||
|
- Plugin header `Version: 3.4.0 → 3.4.1`; `WP_NOTES_VERSION` constant updated to match. PATCH bump (bug fix, no API or behavioural changes beyond the fix itself).
|
||||||
|
|
||||||
|
### Not changed
|
||||||
|
|
||||||
|
- The other three action handlers (new note, mark-as-done) — they already had correct redirects; no need to touch.
|
||||||
|
- Storage model, tab structure, CSS — all unchanged from v3.4.0.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [3.4.0] — 2026-05-27
|
||||||
|
|
||||||
|
### Added — Active / Completed tabs on the My Log page
|
||||||
|
|
||||||
|
The main Logbook page used to render two stacked sections — Active notes from `wp_notes` above, Completed notes from `wp_done_notes` below. As the lists grew, this became a "wall of stacked sections" with Completed pushing content off the visible fold and users having to scroll past it to scan their active work.
|
||||||
|
|
||||||
|
v3.4.0 replaces the stacked layout with a **single-pane tabbed view** using WordPress's native `subsubsub` filter-tab pattern (the same one Posts / Comments / Plugins admin pages use):
|
||||||
|
|
||||||
|
- **Two tabs**: `Active (N)` and `Completed (M)`. Counts in the labels match the actual list lengths.
|
||||||
|
- **URL-driven state**: `?page=wp-notes&tab=active` (default) and `?page=wp-notes&tab=completed`. Bookmarkable, refresh-stable, back-button works. Invalid tab values fall back to Active server-side.
|
||||||
|
- **No JavaScript**: each tab is a hyperlink. WP-admin core CSS handles the `.subsubsub` and `.current` styling; we just add a small top/bottom margin block.
|
||||||
|
- **Single-pane render**: only the selected tab's section is in the DOM, so no flash-of-wrong-content and no wasted markup.
|
||||||
|
- **"Add a Note" form stays visible on both tabs** — even from Completed you can think of something new to log.
|
||||||
|
|
||||||
|
This was flagged in the 2026-05-25 UX audit as the highest-payoff next move (Tier 3 item #7). When the v4 roadmap's timer / `time_logged` field ships, the tab structure can extend naturally to three tabs (TODO / IN PROGRESS / Completed) in the same place; for now, without that field, an IN PROGRESS tab would always be empty, so v3.4.0 ships the 2-tab version that matches the current data model.
|
||||||
|
|
||||||
|
### Files changed
|
||||||
|
|
||||||
|
- `wp-notes.php` — `wp_notes_page_callback()`: tab detection from `$_GET['tab']` (sanitized + whitelisted), `subsubsub` markup with link-builder via `add_query_arg`, single-pane conditional render of either the active or completed section. Replaces the previous two-stacked-section block.
|
||||||
|
- `inc/wp-notes-styles.php` — minor spacing (`margin: 12px 0 18px`) on `.subsubsub` so the tab strip has breathing room.
|
||||||
|
- Plugin header `Version: 3.3.5 → 3.4.0`; `WP_NOTES_VERSION` constant updated to match. MINOR bump (new feature, no breaking changes).
|
||||||
|
|
||||||
|
### Not changed
|
||||||
|
|
||||||
|
- Storage model — Active and Completed remain in their separate options (`wp_notes`, `wp_done_notes`).
|
||||||
|
- The `wp_notes_display_notes($type)` function in `inc/wp-notes-display.php` — already accepts the section type, no signature change needed.
|
||||||
|
- No new DB writes, schema changes, AJAX endpoints, or dependencies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [3.3.5] — 2026-05-25
|
## [3.3.5] — 2026-05-25
|
||||||
|
|
||||||
### Changed — Admin-menu icon
|
### Changed — Admin-menu icon
|
||||||
|
|||||||
@@ -198,6 +198,14 @@ function wp_notes_admin_styles() {
|
|||||||
color: #3c763d;
|
color: #3c763d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v3.4.0 — Active/Completed tab strip on the My Log page.
|
||||||
|
WP-admin core already styles .subsubsub and .current;
|
||||||
|
we only need to add breathing room above + below. */
|
||||||
|
.wp-notes-page .subsubsub,
|
||||||
|
.wrap > .subsubsub {
|
||||||
|
margin: 12px 0 18px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media screen and (max-width: 782px) {
|
@media screen and (max-width: 782px) {
|
||||||
.wp-notes-formatting {
|
.wp-notes-formatting {
|
||||||
|
|||||||
+73
-25
@@ -5,7 +5,7 @@
|
|||||||
* Plugin Name: Logbook
|
* Plugin Name: Logbook
|
||||||
* Plugin URI: https://icanhelp.ie/wp-notes
|
* Plugin URI: https://icanhelp.ie/wp-notes
|
||||||
* Description: A lightweight task & logbook plugin for WordPress. Log your daily work, mark tasks done, and keep a tidy record inside the dashboard. Perfect for freelancers showing clients what's been delivered and students proving work to teachers.
|
* Description: A lightweight task & logbook plugin for WordPress. Log your daily work, mark tasks done, and keep a tidy record inside the dashboard. Perfect for freelancers showing clients what's been delivered and students proving work to teachers.
|
||||||
* Version: 3.3.5
|
* Version: 3.4.2
|
||||||
* Requires at least: 5.0
|
* Requires at least: 5.0
|
||||||
* Requires PHP: 7.2
|
* Requires PHP: 7.2
|
||||||
* Author: IR240474
|
* Author: IR240474
|
||||||
@@ -33,7 +33,7 @@ if (!isset($wp_notes_init)) {
|
|||||||
$wp_notes_init = true;
|
$wp_notes_init = true;
|
||||||
|
|
||||||
// Plugin Constants
|
// Plugin Constants
|
||||||
if (!defined('WP_NOTES_VERSION')) define('WP_NOTES_VERSION', '3.3.5');
|
if (!defined('WP_NOTES_VERSION')) define('WP_NOTES_VERSION', '3.4.2');
|
||||||
if (!defined('WP_NOTES_FILE')) define('WP_NOTES_FILE', __FILE__);
|
if (!defined('WP_NOTES_FILE')) define('WP_NOTES_FILE', __FILE__);
|
||||||
if (!defined('WP_NOTES_PATH')) define('WP_NOTES_PATH', plugin_dir_path(__FILE__));
|
if (!defined('WP_NOTES_PATH')) define('WP_NOTES_PATH', plugin_dir_path(__FILE__));
|
||||||
if (!defined('WP_NOTES_URL')) define('WP_NOTES_URL', plugin_dir_url(__FILE__));
|
if (!defined('WP_NOTES_URL')) define('WP_NOTES_URL', plugin_dir_url(__FILE__));
|
||||||
@@ -832,6 +832,14 @@ function wp_notes_page_callback() {
|
|||||||
$total_notes = count($notes);
|
$total_notes = count($notes);
|
||||||
$total_done = count($done_notes);
|
$total_done = count($done_notes);
|
||||||
|
|
||||||
|
// v3.4.0 — which tab is selected? Default 'active'. Whitelist-only.
|
||||||
|
$current_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'active';
|
||||||
|
if (!in_array($current_tab, array('active', 'completed'), true)) {
|
||||||
|
$current_tab = 'active';
|
||||||
|
}
|
||||||
|
$active_tab_url = esc_url(add_query_arg(array('page' => 'wp-notes', 'tab' => 'active'), admin_url('admin.php')));
|
||||||
|
$completed_tab_url = esc_url(add_query_arg(array('page' => 'wp-notes', 'tab' => 'completed'), admin_url('admin.php')));
|
||||||
|
|
||||||
// Get user settings
|
// Get user settings
|
||||||
$settings = get_option('wp_notes_settings', array(
|
$settings = get_option('wp_notes_settings', array(
|
||||||
'default_font' => 'Arial',
|
'default_font' => 'Arial',
|
||||||
@@ -1005,15 +1013,36 @@ function wp_notes_page_callback() {
|
|||||||
|
|
||||||
<!-- Notes List -->
|
<!-- Notes List -->
|
||||||
<h2>Log entries</h2>
|
<h2>Log entries</h2>
|
||||||
<!-- Active Notes List -->
|
|
||||||
<div class="wp-notes-active" id="active-notes">
|
|
||||||
<?php wp_notes_display_notes('active'); ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Completed Notes List -->
|
<!-- v3.4.0 — WP-native subsubsub tab strip. Single-pane: only the
|
||||||
<div class="wp-notes-completed" id="completed-notes">
|
selected tab's section is rendered below. URL-driven state
|
||||||
<?php wp_notes_display_notes('completed'); ?>
|
(?tab=active|completed) so it's bookmarkable + refresh-stable.
|
||||||
</div>
|
WP-admin core supplies .subsubsub and .current styling. -->
|
||||||
|
<ul class="subsubsub">
|
||||||
|
<li>
|
||||||
|
<a href="<?php echo $active_tab_url; ?>"<?php echo $current_tab === 'active' ? ' class="current"' : ''; ?>>
|
||||||
|
<?php esc_html_e('Active', 'a-wp-notes'); ?>
|
||||||
|
<span class="count">(<?php echo (int) $total_notes; ?>)</span>
|
||||||
|
</a> |
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="<?php echo $completed_tab_url; ?>"<?php echo $current_tab === 'completed' ? ' class="current"' : ''; ?>>
|
||||||
|
<?php esc_html_e('Completed', 'a-wp-notes'); ?>
|
||||||
|
<span class="count">(<?php echo (int) $total_done; ?>)</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div style="clear:both;"></div>
|
||||||
|
|
||||||
|
<?php if ($current_tab === 'active') : ?>
|
||||||
|
<div class="wp-notes-active" id="active-notes">
|
||||||
|
<?php wp_notes_display_notes('active'); ?>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="wp-notes-completed" id="completed-notes">
|
||||||
|
<?php wp_notes_display_notes('completed'); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Footer: support link (lives at the BOTTOM, not the top) -->
|
<!-- Footer: support link (lives at the BOTTOM, not the top) -->
|
||||||
<p class="wp-notes-footer-support">
|
<p class="wp-notes-footer-support">
|
||||||
@@ -1307,25 +1336,44 @@ function wp_notes_handle_actions() {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle restore note action
|
// Handle restore note action (per-row form on the Completed tab).
|
||||||
if (isset($_POST['restore_note']) && isset($_POST['done_ids'])) {
|
//
|
||||||
|
// v3.4.2 fix: this handler used to expect $_POST['done_ids'] — an
|
||||||
|
// array of IDs from bulk-action checkboxes that were removed in
|
||||||
|
// v3.1.0. The per-row Restore form in inc/wp-notes-display.php
|
||||||
|
// sends a hidden $_POST['note_id'] (singular) instead, so the old
|
||||||
|
// handler's isset($_POST['done_ids']) check was always false and
|
||||||
|
// the handler body never executed. Clicking Restore therefore
|
||||||
|
// looked like it did nothing — David's "the complete log does not
|
||||||
|
// return to active." The v3.4.1 redirect added below was correct
|
||||||
|
// but never reached because the handler was already dead code.
|
||||||
|
//
|
||||||
|
// Rewritten to match the working mark-done single-note handler
|
||||||
|
// pattern: expect note_id (singular), absint() it, isset() lookup
|
||||||
|
// in $done_notes, move with the restored_by annotation, then
|
||||||
|
// redirect to the Active tab where the restored note now lives.
|
||||||
|
if (isset($_POST['restore_note']) && isset($_POST['note_id'])) {
|
||||||
$notes = get_option('wp_notes', array());
|
$notes = get_option('wp_notes', array());
|
||||||
$done_notes = get_option('wp_done_notes', array());
|
$done_notes = get_option('wp_done_notes', array());
|
||||||
|
$note_id = absint($_POST['note_id']);
|
||||||
$current_user = wp_get_current_user();
|
$current_user = wp_get_current_user();
|
||||||
$new_done_notes = array();
|
|
||||||
|
if (isset($done_notes[$note_id])) {
|
||||||
foreach ($done_notes as $key => $note) {
|
$note = $done_notes[$note_id];
|
||||||
if (in_array($key, $_POST['done_ids'])) {
|
$note['last_modified'] = current_time('mysql');
|
||||||
$note['last_modified'] = current_time('mysql');
|
$note['restored_by'] = $current_user->display_name;
|
||||||
$note['restored_by'] = $current_user->display_name;
|
$notes[] = $note;
|
||||||
$notes[] = $note;
|
unset($done_notes[$note_id]);
|
||||||
} else {
|
|
||||||
$new_done_notes[] = $note;
|
update_option('wp_notes', $notes);
|
||||||
}
|
update_option('wp_done_notes', $done_notes);
|
||||||
|
|
||||||
|
// Redirect to the Active tab — without this, the page falls
|
||||||
|
// through and re-renders with the URL's current ?tab=completed,
|
||||||
|
// so the restored note (now on Active) would be invisible.
|
||||||
|
wp_redirect(admin_url('admin.php?page=wp-notes'));
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_option('wp_notes', $notes);
|
|
||||||
update_option('wp_done_notes', $new_done_notes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle edit note action
|
// Handle edit note action
|
||||||
|
|||||||
Reference in New Issue
Block a user