6 Commits

Author SHA1 Message Date
ranger c5d8a34296 feat: Active/Completed tabs on My Log page (v3.4.0)
Replaces the two stacked sections (Active above, Completed below)
on the main Logbook page with a single-pane WP-admin tabbed view
using the native subsubsub pattern (same as Posts/Comments/Plugins).

- Two tabs: Active (N) | Completed (M) with live counts
- URL-driven state via ?tab=active|completed; bookmarkable,
  refresh-stable, back-button works, invalid values fall back to
  Active server-side via whitelist + sanitize_key
- No JavaScript — each tab is a hyperlink built with add_query_arg
- WP-admin core CSS handles .subsubsub + .current; only a small
  margin block added in wp-notes-styles.php
- Single-pane render: only the selected tab's section is in the
  DOM, so no flash-of-wrong-content
- "Add a Note" form stays visible on both tabs for UI consistency

Flagged in the 2026-05-25 UX audit as the highest-payoff next move
(Tier 3 item #7). When the v4 timer/time_logged field ships, the
structure can extend to 3 tabs (TODO/IN PROGRESS/Completed) in
the same place; without it, an IN PROGRESS tab would always be
empty, so v3.4.0 ships the 2-tab version matching the current
data model.

Storage model unchanged — Active and Completed remain in their
separate options (wp_notes, wp_done_notes). The
wp_notes_display_notes($type) function is unchanged.

MINOR bump: new feature, no breaking changes.
2026-05-26 09:00:15 +01:00
ranger bd8c5f2340 ux: replace generic cog admin-menu icon with closed-book (v3.3.5)
The WordPress admin sidebar showed "Logbook" with the generic
cog wheel icon (dashicons-admin-generic) — fine for a settings
page, off-brand for a plugin whose entire identity is "logbook".

Swapped to dashicons-book-alt (closed book) — the most literal
possible match in the Dashicons set, and visually reinforces the
brand at the first place users see the plugin every day.

Alternatives also viable (commented in the changelog for future
reference): dashicons-edit (pencil), dashicons-clipboard,
dashicons-welcome-write-blog, dashicons-format-aside.

VERSION
- wp-notes.php header 3.3.4 → 3.3.5
- WP_NOTES_VERSION constant 3.3.4 → 3.3.5
- About page version-history leads with v3.3.5; v3.3.4 demoted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:09:49 +01:00
ranger ead5bbcd2c release: 3.3.3 → 3.3.4 — rename Gitea repo a-wp-notes-v3 → a-logbook
The repo's old name was a holdover from the v3-of-A-WP-Notes
archival era. With the plugin firmly identifying as "Logbook" now,
the repo and the local working folder should match.

CHANGES IN-CODE
- inc/wp-notes-updater.php: WP_NOTES_GITEA_REPO constant
  a-wp-notes-v3 → a-logbook. Update checker now hits
  https://git.davidtkeane.com/api/v1/repos/ranger/a-logbook/...
  on every check. Override-able via define() in wp-config.php if
  the repo ever moves again.
- inc/wp-notes-about.php: "View the full CHANGELOG.md →" link on
  the version-history card now points at the new repo path.
- Local working folder on M3 renamed
  /Users/ranger/scripts/Gitea/a-wp-notes-v3-archive → a-logbook.
  .git/config survived; remote URL will be updated separately.

UNCHANGED (zero-migration commitment continues)
- Plugin slug 'wp-notes'.
- Plugin text domain 'a-wp-notes'.
- All wp_notes_* function names, WP_NOTES_* constants, DB option
  keys, user_meta keys, file names inside the plugin folder.
- Historical CHANGELOG references to a-wp-notes-v3 stay as
  truthful history of the v3.2.0 era.

VERSION BUMP
- wp-notes.php header Version: 3.3.3 → 3.3.4
- WP_NOTES_VERSION constant: 3.3.3 → 3.3.4
- About page version-history leads with v3.3.4; v3.3.3 demoted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:54:27 +01:00
ranger e51b087545 release: 3.3.2 → 3.3.3 — verification bump to test the "Check now" flow end-to-end
Pure version increment with no functional changes. Lets David's
Local install (currently on v3.3.2) hit the "Check now" button in
Settings → Updates and verify the panel correctly reports a real
version delta — should render "v3.3.3 available — Download .zip"
with a working download link to the source archive on Gitea.

After the test passes, `git pull` brings the local install to
v3.3.3 and the same panel should flip back to "You are up to date
(v3.3.3)".

VERSION
- wp-notes.php header 3.3.2 → 3.3.3
- WP_NOTES_VERSION constant 3.3.2 → 3.3.3
- About page version-history leads with v3.3.3 as latest (with a
  cheeky "if you can see this line, you successfully pulled the
  test release" note); v3.3.2 demoted to previous entry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:47:25 +01:00
ranger 1c93c82ef5 fix: update checker — fall back to /tags when no formal Gitea Release exists (v3.3.2)
The v3.3.0 update checker only queried Gitea's /releases/latest
endpoint, which requires a formal Release object (created via the
Gitea web UI with optional notes + zip assets attached). A plain
"git tag v3.3.x && git push --tags" from the terminal does NOT
create that Release object — so the checker kept returning "No
releases tagged on the Gitea repo yet" even when tags existed.

wp_notes_fetch_latest_release() now falls back to the
/tags?limit=1 endpoint when /releases/latest returns 404 (or any
non-200). It synthesises a release-like payload from the newest
tag — tag_name, html_url pointing at the tag view, tag message as
the body, empty assets[] so the existing download-URL logic falls
through to Gitea's source-archive URL pattern (/archive/<tag>.zip).

Net effect: the "Check now" button now finds the latest version
whether David creates formal Gitea Releases OR just pushes tags
with "git push --tags". No workflow change required.

Discovered while diagnosing why "Check now" wasn't seeing today's
v3.1.0/v3.2.0/v3.3.0/v3.3.1 tags (just pushed in this session)
— the tags were there, the formal Release objects were not.

KNOWN LIMITATION (not a bug — flagged)
The Gitea repo ranger/a-wp-notes-v3 is currently private. Anonymous
API requests get a 404 (Gitea's standard behaviour for private
repos). The updater code is correct but can't actually reach the
API on a private repo without authentication. Fix: change the
repo visibility to public on Gitea — appropriate anyway for a
GPL-licensed plugin headed for the WordPress.org marketplace.

VERSION BUMP
- wp-notes.php header 3.3.1 → 3.3.2
- WP_NOTES_VERSION constant 3.3.1 → 3.3.2
- About page version-history leads with v3.3.2; v3.3.1 demoted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:29:33 +01:00
ranger 3667b7a154 release: 3.3.0 → 3.3.1 — drop "WP" prefix, plugin is now just "Logbook"
David's call after a short discussion about WordPress.org marketplace
considerations. WP.org's trademark policy historically discourages
plugins implying official endorsement via a "WP" prefix and has been
known to request rename during submission review. Dropping it now
makes the name cleaner AND sidesteps that future hurdle if/when the
plugin lands on the marketplace.

CHANGES
All user-facing brand mentions: WP Logbook → Logbook across:
- Plugin header (Plugin Name + docblock)
- Admin menu top-level
- Admin sidebar submenu label still "My Log" (already prefix-free)
- Admin bar count menu
- Dashboard widget title
- Settings page H1
- Main page H1
- About page intro card + "What Logbook does" card heading
- Email feedback subject + body intro
- Legacy feedback.php subject lines
- error_log() prefix [WP Logbook] → [Logbook]
- Updater panel description text
- styles.php docblock

VERSION
- wp-notes.php header Version: 3.3.0 → 3.3.1
- WP_NOTES_VERSION constant: 3.3.0 → 3.3.1
- About page version-history card gets new top entry for v3.3.1
  with green "latest" pill; v3.3.0 demoted to previous entry
- CHANGELOG header line tracks the full naming lineage now:
  A-WP-Notes (≤v3.1.0) → WP Logbook (v3.2.0-v3.3.0) → Logbook
  (v3.3.1+)

NOTABLY NOT CHANGED
- Historical CHANGELOG entries for v3.2.0 still say "WP Logbook" —
  that was the correct name at the time, rewriting would be
  revisionist.
- Same zero-migration commitment: internal function names,
  constants, DB option keys, user_meta keys, file paths, plugin
  slug 'wp-notes', and text domain 'a-wp-notes' all unchanged.
- Pure user-facing string change. No data migration, no behaviour
  change. Existing installs see "Logbook" appear on next page
  refresh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:13:51 +01:00
7 changed files with 301 additions and 56 deletions
+168 -1
View File
@@ -1,6 +1,6 @@
# Changelog # Changelog
All notable changes to **WP Logbook** (formerly **A-WP-Notes** through v3.1.0) are documented here. All notable changes to **Logbook** (formerly **A-WP-Notes** through v3.1.0, then **WP Logbook** in v3.2.0v3.3.0) are documented here.
Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versioning: [SemVer](https://semver.org/). Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versioning: [SemVer](https://semver.org/).
--- ---
@@ -9,6 +9,173 @@ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versi
--- ---
## [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
### Changed — Admin-menu icon
The WordPress admin sidebar icon for Logbook is now
**`dashicons-book-alt`** (a closed book) instead of the generic
cog wheel (`dashicons-admin-generic`). The closed-book glyph is the
most literal possible match for the word "logbook" in the Dashicons
set — reinforces the brand identity at the first place users see
the plugin every day.
If you'd prefer a different icon, the line lives in
`wp-notes.php → wp_notes_admin_menu()` as the 7th arg to
`add_menu_page()`. Alternatives worth considering:
`dashicons-edit` (pencil), `dashicons-clipboard` (clipboard),
`dashicons-welcome-write-blog` (pencil over paper),
`dashicons-format-aside` (notes glyph). Full list at
https://developer.wordpress.org/resource/dashicons/
### Version bump
- wp-notes.php header 3.3.4 → 3.3.5
- WP_NOTES_VERSION constant 3.3.4 → 3.3.5
- About page version-history leads with v3.3.5; v3.3.4 demoted.
---
## [3.3.4] — 2026-05-25
**Repo renamed on Gitea: `a-wp-notes-v3` → `a-logbook`.** Also the
local working folder on M3: `/Users/ranger/scripts/Gitea/a-logbook`
(was `a-wp-notes-v3-archive`). The old repo name was a holdover
from the v3-of-A-WP-Notes archival era; with the plugin firmly
identifying as Logbook now, the repo and folder names should match.
### Changed
- **`inc/wp-notes-updater.php`** — `WP_NOTES_GITEA_REPO` constant
updated from `a-wp-notes-v3` to `a-logbook`. The update checker
now hits `https://git.davidtkeane.com/api/v1/repos/ranger/a-logbook/...`
on every check. (The constant remains override-able via
`define()` in `wp-config.php` if the repo ever moves again.)
- **`inc/wp-notes-about.php`** — "View the full CHANGELOG.md →"
link on the version-history card updated to the new repo path.
- **Local working folder on M3** renamed to `a-logbook` to match
the Gitea repo name. `.git/config` survived the move intact;
remote URL updated separately.
### Unchanged (zero-migration commitment continues)
- Plugin slug (`wp-notes`).
- Plugin text domain (`a-wp-notes`).
- All internal function names, constants (`WP_NOTES_*`), DB option
keys, user_meta keys, file names inside the plugin
(`wp-notes.php`, `inc/wp-notes-*.php`).
- Historical CHANGELOG references to `a-wp-notes-v3` (e.g. in the
v3.2.0 entry) stay as historical truth.
---
## [3.3.3] — 2026-05-25
**Verification bump.** Pure version increment to test the end-to-end
"Check now" flow against the now-publicly-hosted Gitea repo. No
functional changes. David's Local install (running v3.3.2) should
now see *"v3.3.3 available — Download .zip"* in the Settings →
Updates panel once "Check now" is clicked, confirming the update
mechanism works against a real version delta. After the test, he
can `git pull` to land on v3.3.3 and watch the same panel flip back
to *"You are up to date (v3.3.3)"*.
---
## [3.3.2] — 2026-05-25
### Fixed — update checker now works with tag-only workflows
The v3.3.0 update checker only queried Gitea's `/releases/latest`
endpoint, which requires a **formal Release object** (created via
the Gitea web UI with optional notes + zip assets). A plain
`git tag v3.3.x && git push --tags` from the terminal doesn't
create that Release object — so the checker kept returning *"No
releases tagged on the Gitea repo yet"* even when tags clearly
existed.
`wp_notes_fetch_latest_release()` now falls back to the
`/tags?limit=1` endpoint when `/releases/latest` returns 404 (or
any non-200). It synthesises a release-like payload from the
newest tag — `tag_name`, an `html_url` pointing at the tag view,
the tag message as the body, and an empty `assets[]` array so the
existing download-URL logic falls through to Gitea's source-archive
URL pattern (`/archive/<tag>.zip`).
**Net effect:** the "Check now" button now finds the latest version
whether David creates formal Gitea Releases OR just pushes tags
with `git push --tags`. No workflow change required.
### Known limitation (not a bug — flagged for awareness)
The Gitea repo `ranger/a-wp-notes-v3` is currently **private**.
Anonymous API requests get a 404 (Gitea's standard behaviour to
avoid leaking the existence of private repos). The updater code is
correct, but it can't actually reach the API on a private repo
without authentication. **Fix:** change the repo visibility to
public on Gitea (Settings → Visibility) — appropriate anyway for a
GPL-licensed plugin headed for the WordPress.org marketplace.
---
## [3.3.1] — 2026-05-25
**Naming: dropped the `WP` prefix. The plugin is now just `Logbook`.**
David's call after a short discussion about WordPress.org marketplace
considerations — WP.org's trademark policy historically discourages
plugins implying official endorsement via a `WP` prefix and has been
known to request a rename during submission review. Dropping it now
makes the name cleaner *and* sidesteps that future hurdle if/when
the plugin lands on the marketplace.
### Changed
- All user-facing brand mentions: `WP Logbook``Logbook` across
plugin header, admin menu, admin bar, dashboard widget, settings
H1, main page H1, About page intro, About page card heading,
feedback email subjects/body, error_log prefix, updater panel
copy, and styles docblock.
- About page version-history card gets a new top entry for v3.3.1
with the green "latest" pill; v3.3.0 demoted to the previous slot.
- CHANGELOG header line updated to track the full naming lineage:
*A-WP-Notes (≤v3.1.0) → WP Logbook (v3.2.0v3.3.0) → Logbook
(v3.3.1+)*.
### Notably NOT changed
- Historical CHANGELOG entries for v3.2.0 (the original "WP
Logbook" rebrand) still say "WP Logbook" — that was the correct
name at the time and rewriting it would be revisionist.
- Same zero-migration commitment as the v3.2.0 rebrand: internal
function names, constants, DB option keys, user_meta keys, file
paths, plugin slug, and text domain all unchanged. Pure
user-facing string change.
---
## [3.3.0] — 2026-05-25 ## [3.3.0] — 2026-05-25
**New feature: self-hosted update checker.** WP Logbook is hosted on **New feature: self-hosted update checker.** WP Logbook is hosted on
+2 -2
View File
@@ -40,10 +40,10 @@ function wp_notes_admin_bar_menu($wp_admin_bar) {
$notes = get_option('wp_notes', array()); $notes = get_option('wp_notes', array());
$count = count($notes); $count = count($notes);
// Main WP Logbook menu item // Main Logbook menu item
$wp_admin_bar->add_node(array( $wp_admin_bar->add_node(array(
'id' => 'wp-notes', 'id' => 'wp-notes',
'title' => sprintf('WP Logbook <span class="count">%d</span>', $count), 'title' => sprintf('Logbook <span class="count">%d</span>', $count),
'href' => admin_url('admin.php?page=wp-notes'), 'href' => admin_url('admin.php?page=wp-notes'),
)); ));
+29 -9
View File
@@ -2,7 +2,7 @@
// wp-notes-about.php // wp-notes-about.php
/** /**
* Function to display the "About" page for WP Logbook plugin. * Function to display the "About" page for Logbook plugin.
*/ */
function wp_notes_about_page() { function wp_notes_about_page() {
?> ?>
@@ -53,11 +53,11 @@ function wp_notes_about_page() {
<div class="wp-notes-about-intro"> <div class="wp-notes-about-intro">
<div class="wp-notes-about-intro__img"> <div class="wp-notes-about-intro__img">
<img src="<?php echo esc_url(WP_NOTES_URL); ?>assets/wp-notes-banner.jpg" <img src="<?php echo esc_url(WP_NOTES_URL); ?>assets/wp-notes-banner.jpg"
alt="WP Logbook banner"> alt="Logbook banner">
</div> </div>
<div class="wp-notes-about-intro__body"> <div class="wp-notes-about-intro__body">
<h2>WP Logbook <span style="color:#646970; font-weight:400;">v<?php echo esc_html(WP_NOTES_VERSION); ?></span></h2> <h2>Logbook <span style="color:#646970; font-weight:400;">v<?php echo esc_html(WP_NOTES_VERSION); ?></span></h2>
<p>WP Logbook is a lightweight task &amp; logbook plugin for WordPress. Log your daily work, mark tasks as done, and keep a tidy record right inside the dashboard &mdash; perfect for freelancers showing clients what's been delivered.</p> <p>Logbook is a lightweight task &amp; logbook plugin for WordPress. Log your daily work, mark tasks as done, and keep a tidy record right inside the dashboard &mdash; perfect for freelancers showing clients what's been delivered.</p>
<p style="margin-bottom:0;"> <p style="margin-bottom:0;">
<a href="<?php echo esc_url(admin_url('admin.php?page=wp-notes')); ?>" class="button button-primary">Go to My Log →</a> <a href="<?php echo esc_url(admin_url('admin.php?page=wp-notes')); ?>" class="button button-primary">Go to My Log →</a>
</p> </p>
@@ -101,10 +101,10 @@ function wp_notes_about_page() {
} }
</style> </style>
<!-- What WP Logbook does --> <!-- What Logbook does -->
<div class="wp-notes-about-card"> <div class="wp-notes-about-card">
<h2>What WP Logbook does</h2> <h2>What Logbook does</h2>
<p>WP Logbook is a lightweight task &amp; logbook plugin that lives entirely inside the WordPress admin. Type a note, format it with colour / size / font / emoji, mark it done when the work is finished, restore it later if you need to revisit. Everything is stored in the site's own database &mdash; nothing leaves your server.</p> <p>Logbook is a lightweight task &amp; logbook plugin that lives entirely inside the WordPress admin. Type a note, format it with colour / size / font / emoji, mark it done when the work is finished, restore it later if you need to revisit. Everything is stored in the site's own database &mdash; nothing leaves your server.</p>
<p>I built it for my own client work as a transparent &ldquo;here's what I did this week&rdquo; logbook, so customers can see clearly what they're paying for. It turned out to be just as useful for any small team or single user who wants notes attached to the WordPress dashboard rather than a separate app.</p> <p>I built it for my own client work as a transparent &ldquo;here's what I did this week&rdquo; logbook, so customers can see clearly what they're paying for. It turned out to be just as useful for any small team or single user who wants notes attached to the WordPress dashboard rather than a separate app.</p>
</div> </div>
@@ -125,7 +125,27 @@ function wp_notes_about_page() {
<h2>Version history</h2> <h2>Version history</h2>
<ul> <ul>
<li> <li>
<span class="ver">v3.3.0</span> &mdash; 25 May 2026 <span class="latest">latest</span><br> <span class="ver">v3.3.5</span> &mdash; 25 May 2026 <span class="latest">latest</span><br>
New admin-menu icon: closed-book (<code>dashicons-book-alt</code>) replaces the generic cog wheel. Visually reinforces the &ldquo;Logbook&rdquo; identity in the WP sidebar.
</li>
<li>
<span class="ver">v3.3.4</span> &mdash; 25 May 2026<br>
Repo renamed on Gitea: <code>a-wp-notes-v3</code> &rarr; <code>a-logbook</code>. The plugin&rsquo;s update checker and the &ldquo;View on Gitea&rdquo; / &ldquo;View all releases&rdquo; / &ldquo;View full CHANGELOG&rdquo; links now point at the new path. Local folder also renamed to <code>a-logbook</code>. The plugin&rsquo;s internal storage and slugs are unchanged &mdash; no data migration.
</li>
<li>
<span class="ver">v3.3.3</span> &mdash; 25 May 2026<br>
Pure version bump to verify the end-to-end &ldquo;Check now&rdquo; flow against a publicly-hosted Gitea repo. No functional changes. If you can see this line, you successfully pulled the test release.
</li>
<li>
<span class="ver">v3.3.2</span> &mdash; 25 May 2026<br>
Update checker now falls back to Gitea's <code>/tags</code> endpoint when no formal Release object exists for the latest tag. Means a plain <code>git tag &amp;&amp; git push --tags</code> is enough to make the &ldquo;Check now&rdquo; button report a new version &mdash; no need to manually create a Release in the Gitea web UI.
</li>
<li>
<span class="ver">v3.3.1</span> &mdash; 25 May 2026<br>
Dropped the <code>WP</code> prefix &mdash; the plugin is now just <strong>Logbook</strong>. Cleaner name, also clears a potential WordPress.org trademark-policy hurdle if/when the plugin ever lands on the marketplace.
</li>
<li>
<span class="ver">v3.3.0</span> &mdash; 25 May 2026<br>
Self-hosted update checker. Settings &rarr; Updates panel polls the Gitea repo via its JSON API, compares against the running version, and shows a download link when a new release is tagged. Includes &ldquo;View on Gitea&rdquo; and &ldquo;View all releases&rdquo; quick links. No auto-install &mdash; manual download keeps things safe. Self-hosted update checker. Settings &rarr; Updates panel polls the Gitea repo via its JSON API, compares against the running version, and shows a download link when a new release is tagged. Includes &ldquo;View on Gitea&rdquo; and &ldquo;View all releases&rdquo; quick links. No auto-install &mdash; manual download keeps things safe.
</li> </li>
<li> <li>
@@ -149,7 +169,7 @@ function wp_notes_about_page() {
Basic note functionality with the dashboard widget and styling options. Basic note functionality with the dashboard widget and styling options.
</li> </li>
</ul> </ul>
<a class="wp-notes-about-changelog-link" href="https://git.davidtkeane.com/ranger/a-wp-notes-v3/src/branch/main/CHANGELOG.md" target="_blank" rel="noopener">View the full CHANGELOG.md →</a> <a class="wp-notes-about-changelog-link" href="https://git.davidtkeane.com/ranger/a-logbook/src/branch/main/CHANGELOG.md" target="_blank" rel="noopener">View the full CHANGELOG.md →</a>
</div> </div>
</div> </div>
+3 -3
View File
@@ -1,6 +1,6 @@
<?php <?php
/** /**
* Feedback Form for WP Logbook Plugin * Feedback Form for Logbook Plugin
* *
* This file contains the HTML and AJAX handling for the feedback form. * This file contains the HTML and AJAX handling for the feedback form.
*/ */
@@ -95,7 +95,7 @@ function wp_notes_submit_feedback() {
// Example: Send feedback via email // Example: Send feedback via email
$to = 'david@icanhelp.ie'; $to = 'david@icanhelp.ie';
$subject = 'WP Logbook Feedback'; $subject = 'Logbook Feedback';
$body = "Name: $name\nEmail: $email\nMessage: $message"; $body = "Name: $name\nEmail: $email\nMessage: $message";
$headers = array('Content-Type: text/plain; charset=UTF-8'); $headers = array('Content-Type: text/plain; charset=UTF-8');
@@ -148,7 +148,7 @@ function wp_notes_submit_help() {
// Example: Send help request via email // Example: Send help request via email
$to = 'david@icanhelp.ie'; $to = 'david@icanhelp.ie';
$subject = 'WP Logbook Help Request'; $subject = 'Logbook Help Request';
$body = "Name: $name\nEmail: $email\nMessage: $message"; $body = "Name: $name\nEmail: $email\nMessage: $message";
$headers = array('Content-Type: text/plain; charset=UTF-8'); $headers = array('Content-Type: text/plain; charset=UTF-8');
+9 -1
View File
@@ -6,7 +6,7 @@ if (!defined('ABSPATH')) {
} }
/** /**
* Add required styles for WP Logbook * Add required styles for Logbook
*/ */
function wp_notes_admin_styles() { function wp_notes_admin_styles() {
?> ?>
@@ -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 {
+34 -13
View File
@@ -1,6 +1,6 @@
<?php <?php
/** /**
* WP Logbook — self-hosted update checker against the Gitea repo. * Logbook — self-hosted update checker against the Gitea repo.
* *
* Polls the Gitea Releases API for the latest tagged release and * Polls the Gitea Releases API for the latest tagged release and
* compares its tag (e.g. "v3.3.0") against WP_NOTES_VERSION. * compares its tag (e.g. "v3.3.0") against WP_NOTES_VERSION.
@@ -18,7 +18,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
// Gitea repo coordinates — change here if the repo ever moves. // Gitea repo coordinates — change here if the repo ever moves.
if ( ! defined( 'WP_NOTES_GITEA_HOST' ) ) { define( 'WP_NOTES_GITEA_HOST', 'https://git.davidtkeane.com' ); } if ( ! defined( 'WP_NOTES_GITEA_HOST' ) ) { define( 'WP_NOTES_GITEA_HOST', 'https://git.davidtkeane.com' ); }
if ( ! defined( 'WP_NOTES_GITEA_OWNER' ) ) { define( 'WP_NOTES_GITEA_OWNER', 'ranger' ); } if ( ! defined( 'WP_NOTES_GITEA_OWNER' ) ) { define( 'WP_NOTES_GITEA_OWNER', 'ranger' ); }
if ( ! defined( 'WP_NOTES_GITEA_REPO' ) ) { define( 'WP_NOTES_GITEA_REPO', 'a-wp-notes-v3' ); } if ( ! defined( 'WP_NOTES_GITEA_REPO' ) ) { define( 'WP_NOTES_GITEA_REPO', 'a-logbook' ); }
/** /**
* Convenience: full web URL of the repo / its releases page. * Convenience: full web URL of the repo / its releases page.
@@ -48,18 +48,44 @@ function wp_notes_fetch_latest_release( $force_refresh = false ) {
if ( is_array( $cached ) ) { return $cached; } if ( is_array( $cached ) ) { return $cached; }
} }
$api_url = WP_NOTES_GITEA_HOST . '/api/v1/repos/' . WP_NOTES_GITEA_OWNER . '/' . WP_NOTES_GITEA_REPO . '/releases/latest'; $base_api = WP_NOTES_GITEA_HOST . '/api/v1/repos/' . WP_NOTES_GITEA_OWNER . '/' . WP_NOTES_GITEA_REPO;
$response = wp_remote_get( $api_url, array( 'timeout' => 8 ) );
// Try /releases/latest first — that's the canonical endpoint when David
// has published a formal Gitea Release via the web UI (with notes + zip
// assets attached).
$response = wp_remote_get( $base_api . '/releases/latest', array( 'timeout' => 8 ) );
if ( is_wp_error( $response ) ) { if ( is_wp_error( $response ) ) {
return null; return null;
} }
$code = (int) wp_remote_retrieve_response_code( $response ); $code = (int) wp_remote_retrieve_response_code( $response );
$body = ( $code === 200 ) ? json_decode( wp_remote_retrieve_body( $response ), true ) : null;
// 404 = repo has no releases yet, OR private. Cache briefly and surface // Fallback: if no formal Release exists (typical for tag-only workflows
// a friendly status to the UI. // where you `git tag v3.3.1 && git push --tags` without using the web
if ( $code !== 200 ) { // UI), hit /tags instead and synthesise a release-like payload from the
// newest tag. Gitea's /tags endpoint sorts by creation order, so [0] is
// the most recent.
if ( $code !== 200 || ! is_array( $body ) || empty( $body['tag_name'] ) ) {
$tags_response = wp_remote_get( $base_api . '/tags?limit=1', array( 'timeout' => 8 ) );
if ( ! is_wp_error( $tags_response )
&& (int) wp_remote_retrieve_response_code( $tags_response ) === 200 ) {
$tags = json_decode( wp_remote_retrieve_body( $tags_response ), true );
if ( is_array( $tags ) && ! empty( $tags[0]['name'] ) ) {
$body = array(
'tag_name' => $tags[0]['name'],
'html_url' => wp_notes_gitea_repo_url() . '/src/tag/' . rawurlencode( $tags[0]['name'] ),
'body' => isset( $tags[0]['message'] ) ? $tags[0]['message'] : '',
'published_at' => isset( $tags[0]['commit']['created'] ) ? $tags[0]['commit']['created'] : null,
'assets' => array(),
);
$code = 200;
}
}
}
// Still nothing usable? Surface a friendly status and short-cache.
if ( $code !== 200 || ! is_array( $body ) || empty( $body['tag_name'] ) ) {
$info = array( $info = array(
'version' => null, 'version' => null,
'html_url' => wp_notes_gitea_releases_url(), 'html_url' => wp_notes_gitea_releases_url(),
@@ -72,11 +98,6 @@ function wp_notes_fetch_latest_release( $force_refresh = false ) {
return $info; return $info;
} }
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $body ) || empty( $body['tag_name'] ) ) {
return null;
}
// "v3.3.0" → "3.3.0" so version_compare() against WP_NOTES_VERSION works cleanly. // "v3.3.0" → "3.3.0" so version_compare() against WP_NOTES_VERSION works cleanly.
$version = ltrim( (string) $body['tag_name'], 'vV' ); $version = ltrim( (string) $body['tag_name'], 'vV' );
@@ -180,7 +201,7 @@ function wp_notes_render_updates_panel() {
<div class="wp-notes-updates" style="max-width:720px; margin-top:24px; padding:18px 20px; background:#fff; border:1px solid #ccd0d4; border-radius:4px;"> <div class="wp-notes-updates" style="max-width:720px; margin-top:24px; padding:18px 20px; background:#fff; border:1px solid #ccd0d4; border-radius:4px;">
<h2 style="margin-top:0;">Updates</h2> <h2 style="margin-top:0;">Updates</h2>
<p style="margin:0 0 12px;"> <p style="margin:0 0 12px;">
WP Logbook is self-hosted on Gitea. Click <strong>Check now</strong> to ask the repo whether there's a newer release than the one you're running. Logbook is self-hosted on Gitea. Click <strong>Check now</strong> to ask the repo whether there's a newer release than the one you're running.
</p> </p>
<p id="wp-notes-update-status" style="margin:0 0 12px;"> <p id="wp-notes-update-status" style="margin:0 0 12px;">
+51 -22
View File
@@ -1,11 +1,11 @@
<?php <?php
/** /**
* WP Logbook — WordPress work-logbook plugin * Logbook — WordPress work-logbook plugin
* *
* Plugin Name: WP Logbook * Plugin Name: Logbook
* Plugin URI: https://icanhelp.ie/wp-notes * Plugin URI: https://icanhelp.ie/wp-notes
* Description: A lightweight task &amp; 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 &amp; 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.0 * Version: 3.4.0
* 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.0'); if (!defined('WP_NOTES_VERSION')) define('WP_NOTES_VERSION', '3.4.0');
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__));
@@ -44,7 +44,7 @@ if (!isset($wp_notes_init)) {
if (!function_exists('wp_notes_log_error')) { if (!function_exists('wp_notes_log_error')) {
function wp_notes_log_error($message) { function wp_notes_log_error($message) {
if (defined('WP_DEBUG') && WP_DEBUG === true) { if (defined('WP_DEBUG') && WP_DEBUG === true) {
error_log('[WP Logbook] ' . $message); error_log('[Logbook] ' . $message);
} }
} }
} }
@@ -169,17 +169,17 @@ if (defined('WP_NOTES_PATH')) {
// Admin Menu // Admin Menu
function wp_notes_admin_menu() { function wp_notes_admin_menu() {
add_menu_page( add_menu_page(
'WP Logbook', 'Logbook',
'WP Logbook', 'Logbook',
'manage_options', 'manage_options',
'wp-notes', 'wp-notes',
'wp_notes_page_callback', 'wp_notes_page_callback',
'dashicons-admin-generic', 'dashicons-book-alt', // closed book — reinforces the "logbook" identity
3 3
); );
// "My Log" — the main landing submenu. Same slug as the parent // "My Log" — the main landing submenu. Same slug as the parent
// menu so clicking either WP Logbook or My Log lands on the same // menu so clicking either Logbook or My Log lands on the same
// central dashboard (the parent's wp_notes_page_callback already // central dashboard (the parent's wp_notes_page_callback already
// renders form + active list + completed list). // renders form + active list + completed list).
// //
@@ -218,7 +218,7 @@ function wp_notes_admin_menu() {
'wp_notes_import_export_page' 'wp_notes_import_export_page'
); );
// About submenu — the WP Logbook brand is already carried by the // About submenu — the Logbook brand is already carried by the
// parent menu, so the submenu can be plain-spoken. // parent menu, so the submenu can be plain-spoken.
add_submenu_page( add_submenu_page(
'wp-notes', 'wp-notes',
@@ -291,7 +291,7 @@ function wp_notes_settings_page() {
settings_errors('wp_notes_settings'); settings_errors('wp_notes_settings');
?> ?>
<div class="wrap"> <div class="wrap">
<h1>WP Logbook Settings</h1> <h1>Logbook Settings</h1>
<form method="post" action="options.php"> <form method="post" action="options.php">
<?php <?php
settings_fields('wp_notes_settings'); settings_fields('wp_notes_settings');
@@ -313,7 +313,7 @@ function wp_notes_settings_page() {
// Settings section callback // Settings section callback
function wp_notes_section_callback() { function wp_notes_section_callback() {
echo '<p>Configure default settings for WP Logbook.</p>'; echo '<p>Configure default settings for Logbook.</p>';
} }
// Font setting callback // Font setting callback
@@ -705,8 +705,8 @@ function wp_notes_ajax_submit_feedback() {
]; ];
$topics_pretty = array_map(function ($t) use ($topic_labels) { return $topic_labels[$t] ?? $t; }, $topics); $topics_pretty = array_map(function ($t) use ($topic_labels) { return $topic_labels[$t] ?? $t; }, $topics);
$subject = sprintf('[%s] WP Logbook feedback from %s', $site, $user->display_name ?: $user->user_login); $subject = sprintf('[%s] Logbook feedback from %s', $site, $user->display_name ?: $user->user_login);
$body = "Feedback received via WP Logbook → About page\n"; $body = "Feedback received via Logbook → About page\n";
$body .= str_repeat('-', 48) . "\n\n"; $body .= str_repeat('-', 48) . "\n\n";
$body .= 'From: ' . ($user->display_name ?: $user->user_login) . ' <' . $user->user_email . ">\n"; $body .= 'From: ' . ($user->display_name ?: $user->user_login) . ' <' . $user->user_email . ">\n";
$body .= 'Site: ' . home_url() . "\n"; $body .= 'Site: ' . home_url() . "\n";
@@ -820,7 +820,7 @@ function wp_notes_save_edit() {
} }
/** /**
* Main WP Logbook page — central hub for note management * Main Logbook page — central hub for note management
*/ */
function wp_notes_page_callback() { function wp_notes_page_callback() {
if (!current_user_can('edit_posts')) { if (!current_user_can('edit_posts')) {
@@ -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',
@@ -840,7 +848,7 @@ function wp_notes_page_callback() {
?> ?>
<div class="wrap"> <div class="wrap">
<!-- Header Section with WordPress Admin Styling --> <!-- Header Section with WordPress Admin Styling -->
<h1 class="wp-heading-inline">WP Logbook</h1> <h1 class="wp-heading-inline">Logbook</h1>
<span class="page-title-action">v<?php echo esc_html(WP_NOTES_VERSION); ?></span> <span class="page-title-action">v<?php echo esc_html(WP_NOTES_VERSION); ?></span>
<hr class="wp-header-end"> <hr class="wp-header-end">
@@ -1005,15 +1013,36 @@ function wp_notes_page_callback() {
<!-- Notes List --> <!-- Notes List -->
<h2>Log entries</h2> <h2>Log entries</h2>
<!-- Active Notes List -->
<!-- v3.4.0 — WP-native subsubsub tab strip. Single-pane: only the
selected tab's section is rendered below. URL-driven state
(?tab=active|completed) so it's bookmarkable + refresh-stable.
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"> <div class="wp-notes-active" id="active-notes">
<?php wp_notes_display_notes('active'); ?> <?php wp_notes_display_notes('active'); ?>
</div> </div>
<?php else : ?>
<!-- Completed Notes List -->
<div class="wp-notes-completed" id="completed-notes"> <div class="wp-notes-completed" id="completed-notes">
<?php wp_notes_display_notes('completed'); ?> <?php wp_notes_display_notes('completed'); ?>
</div> </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">
@@ -1396,7 +1425,7 @@ function wp_notes_dashboard_widget() {
function wp_notes_add_dashboard_widgets() { function wp_notes_add_dashboard_widgets() {
wp_add_dashboard_widget( wp_add_dashboard_widget(
'wp_notes_dashboard_widget', 'wp_notes_dashboard_widget',
'WP Logbook', 'Logbook',
'wp_notes_dashboard_widget' 'wp_notes_dashboard_widget'
); );
} }
@@ -1407,7 +1436,7 @@ function wp_notes_register_cpt() {
$labels = array( $labels = array(
'name' => __('Notes', 'a-wp-notes'), 'name' => __('Notes', 'a-wp-notes'),
'singular_name' => __('Note', 'a-wp-notes'), 'singular_name' => __('Note', 'a-wp-notes'),
'menu_name' => __('WP Logbook', 'a-wp-notes'), 'menu_name' => __('Logbook', 'a-wp-notes'),
'add_new' => __('Add New', 'a-wp-notes'), 'add_new' => __('Add New', 'a-wp-notes'),
'add_new_item' => __('Add New Note', 'a-wp-notes'), 'add_new_item' => __('Add New Note', 'a-wp-notes'),
'edit_item' => __('Edit Note', 'a-wp-notes'), 'edit_item' => __('Edit Note', 'a-wp-notes'),
@@ -1640,7 +1669,7 @@ function wp_notes_migration_notice() {
?> ?>
<div class="notice notice-info is-dismissible"> <div class="notice notice-info is-dismissible">
<p> <p>
<?php _e('WP Logbook needs to migrate your existing notes to the new storage system.', 'a-wp-notes'); ?> <?php _e('Logbook needs to migrate your existing notes to the new storage system.', 'a-wp-notes'); ?>
<a href="<?php echo esc_url(admin_url('admin.php?page=wp-notes-settings&action=migrate')); ?>" class="button button-primary"> <a href="<?php echo esc_url(admin_url('admin.php?page=wp-notes-settings&action=migrate')); ?>" class="button button-primary">
<?php _e('Start Migration', 'a-wp-notes'); ?> <?php _e('Start Migration', 'a-wp-notes'); ?>
</a> </a>