chore: initial commit — Buddy v0.1.0 (Phase A complete)

Buddy is born. First commit of a new standalone WordPress plugin —
the spiritual successor to the tamagotchi that once lived inside
A-WP-Notes v1.1.5 (gracefully retired). Rebuilt from scratch with
all the v3-discipline lessons baked in from day one.

PHASE A — pet exists
- Dashboard widget at WP Admin → Dashboard showing SVG character +
  name + mood label + four stats bars.
- Dedicated admin page at WP Admin → Buddy → My Buddy (bigger view).
- About page with side-by-side intro + plain-prose cards (Logbook
  About-page pattern carried forward).
- Settings page with name-rename form + Updates panel.
- Per-user state in user_meta key buddy_state (each WP admin gets
  their own pet, no shared state).
- Inline SVG sprite renderer with three mood tones (happy/neutral/
  sad) and three sizes (sm/md/lg). CSS keyframe animations: bobbing
  + periodic blinking. Zero image files.
- Self-hosted update checker wired up from commit 1, ported from
  Logbook v3.3.5: /releases/latest with /tags?limit=1 fallback,
  12h success cache / 1h negative cache. UI on Settings page.
- dashicons-pets admin-menu icon — literal paw-print, brand match.

ARCHITECTURE LOCKED FROM COMMIT 1
- Single-word brand name "Buddy" — no WP prefix, no future rebrand.
- Public GPL v2+ Gitea repo (ranger/a-buddy).
- Constants prefix BUDDY_*, function prefix buddy_*, text domain
  buddy. Clean naming throughout — none of Logbook's wp-notes-*
  historical-artifact baggage.
- Single H1 per admin page, no nested toggle boxes, no duplicate
  sections — Tier-1 discipline carried forward from Logbook.
- All assets local (inline SVG, plain CSS), no third-party CDN,
  no Gravatar-style external pings.

NOT IN THIS RELEASE (planned)
- Phase B — Feed/Play/Clean/Sleep interactions + cooldown timers.
- Phase C — WP-cron decay + "Buddy is hungry" dismissible notices
  (port the persistent-dismissal pattern from Logbook).
- Phase D — Multiple species (dog, dragon, sprite), per-species
  personality phrases.
- Phase E — Site-health hook: pet stats react to wp_get_site_health()
  results. The killer feature.
- Phase F — Pro tier (€2.99 lifetime) with custom skins + multi-pet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 10:23:57 +01:00
commit 48e97862a6
12 changed files with 1135 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
<?php
/**
* Buddy settings page — placeholder shell for Phase A. Settings will
* grow in later phases:
* Phase B: cooldown timers
* Phase C: decay tick interval
* Phase D: species picker (currently only one available)
* Phase E: site-health integration toggle
*
* For v0.1.0 this page exists to (a) host the Updates panel from the
* Logbook-style update checker, and (b) let the user rename their
* Buddy.
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
/**
* Handle the rename form POST. Capability-gated to anyone who can
* read (every WP user) since each user owns their own Buddy.
*/
add_action( 'admin_init', 'buddy_handle_rename_post' );
function buddy_handle_rename_post() {
if ( empty( $_POST['buddy_rename_submit'] ) ) { return; }
if ( ! current_user_can( 'read' ) ) { return; }
if ( ! isset( $_POST['buddy_rename_nonce'] )
|| ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['buddy_rename_nonce'] ) ), 'buddy_rename' ) ) {
return;
}
$new_name = isset( $_POST['buddy_name'] ) ? sanitize_text_field( wp_unslash( $_POST['buddy_name'] ) ) : '';
if ( $new_name === '' || mb_strlen( $new_name ) > 32 ) { return; }
buddy_update_state( array( 'name' => $new_name ) );
add_action( 'admin_notices', function () {
printf(
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
esc_html__( 'Buddy renamed.', 'buddy' )
);
} );
}
function buddy_render_settings_page() {
if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'buddy' ) );
}
$state = buddy_get_state();
?>
<div class="wrap">
<h1><?php esc_html_e( 'Buddy Settings', 'buddy' ); ?></h1>
<form method="post" style="max-width: 720px; background:#fff; padding:18px 22px; border:1px solid #ccd0d4; border-radius:4px; margin-top: 16px;">
<?php wp_nonce_field( 'buddy_rename', 'buddy_rename_nonce' ); ?>
<h2 style="margin-top:0;"><?php esc_html_e( 'Name', 'buddy' ); ?></h2>
<p>
<label for="buddy_name"><?php esc_html_e( 'What is your Buddy called?', 'buddy' ); ?></label><br>
<input type="text"
name="buddy_name"
id="buddy_name"
value="<?php echo esc_attr( $state['name'] ); ?>"
maxlength="32"
class="regular-text">
</p>
<p>
<button type="submit" name="buddy_rename_submit" class="button button-primary">
<?php esc_html_e( 'Save name', 'buddy' ); ?>
</button>
</p>
</form>
<?php
// Updates panel — defined in inc/updater.php.
if ( function_exists( 'buddy_render_updates_panel' ) ) {
buddy_render_updates_panel();
}
?>
</div>
<?php
}