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
+121
View File
@@ -0,0 +1,121 @@
<?php
/**
* Buddy — a friendly pet for your WordPress dashboard
*
* Plugin Name: Buddy
* Plugin URI: https://icanhelp.ie/buddy
* Description: Adopt a small companion that lives in your WordPress dashboard. Its mood reflects your site's health — published posts feed it, outdated plugins make it sick, clearing spam makes it happy. Gamifies WordPress maintenance with a bit of charm.
* Version: 0.1.0
* Requires at least: 5.0
* Requires PHP: 7.4
* Author: David Keane
* Author URI: https://rangersmyth.xyz/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: buddy
*
* @package Buddy
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
// Plugin coordinates.
if ( ! defined( 'BUDDY_VERSION' ) ) { define( 'BUDDY_VERSION', '0.1.0' ); }
if ( ! defined( 'BUDDY_FILE' ) ) { define( 'BUDDY_FILE', __FILE__ ); }
if ( ! defined( 'BUDDY_PATH' ) ) { define( 'BUDDY_PATH', plugin_dir_path( __FILE__ ) ); }
if ( ! defined( 'BUDDY_URL' ) ) { define( 'BUDDY_URL', plugin_dir_url( __FILE__ ) ); }
if ( ! defined( 'BUDDY_BASENAME' ) ) { define( 'BUDDY_BASENAME', plugin_basename( __FILE__ ) ); }
// Includes — each file owns one concern.
require_once BUDDY_PATH . 'inc/state.php'; // user_meta storage + stat helpers
require_once BUDDY_PATH . 'inc/sprite.php'; // inline-SVG character renderer
require_once BUDDY_PATH . 'inc/dashboard-widget.php'; // the pet on WP Dashboard
require_once BUDDY_PATH . 'inc/admin-page.php'; // dedicated Buddy admin page
require_once BUDDY_PATH . 'inc/about.php'; // About page
require_once BUDDY_PATH . 'inc/settings.php'; // Settings page
require_once BUDDY_PATH . 'inc/updater.php'; // self-hosted update checker against Gitea
/**
* Admin menu registration. Buddy gets its own top-level menu — the pet
* is a discrete enough thing to deserve a sidebar entry rather than
* being buried under Tools or Settings. Icon is dashicons-pets for the
* literal-match-to-purpose vibe (paw print).
*/
add_action( 'admin_menu', 'buddy_register_admin_menu' );
function buddy_register_admin_menu() {
add_menu_page(
__( 'Buddy', 'buddy' ),
__( 'Buddy', 'buddy' ),
'read', // any logged-in user with read access can see their own pet
'buddy',
'buddy_render_main_page',
'dashicons-pets',
72 // sits below Comments, above plugin entries
);
// "My Buddy" — main landing submenu. Same slug as parent so clicking
// either entry lands on the same page. Empty callback so only the
// parent's renderer fires (lesson learned from Logbook's duplicate-
// form bug).
add_submenu_page(
'buddy',
__( 'My Buddy', 'buddy' ),
__( 'My Buddy', 'buddy' ),
'read',
'buddy',
''
);
add_submenu_page(
'buddy',
__( 'Settings', 'buddy' ),
__( 'Settings', 'buddy' ),
'manage_options',
'buddy-settings',
'buddy_render_settings_page'
);
add_submenu_page(
'buddy',
__( 'About', 'buddy' ),
__( 'About', 'buddy' ),
'read',
'buddy-about',
'buddy_render_about_page'
);
}
/**
* Enqueue Buddy's CSS + JS on its own admin pages and on the main
* dashboard (where the widget lives).
*/
add_action( 'admin_enqueue_scripts', 'buddy_enqueue_admin_assets' );
function buddy_enqueue_admin_assets( $hook ) {
$buddy_hooks = array(
'index.php', // WP Dashboard (the widget lives here)
'toplevel_page_buddy', // Buddy main page
'buddy_page_buddy-settings', // Settings
'buddy_page_buddy-about', // About
);
if ( ! in_array( $hook, $buddy_hooks, true ) ) { return; }
wp_enqueue_style(
'buddy-admin',
BUDDY_URL . 'assets/css/buddy.css',
array(),
BUDDY_VERSION
);
}
/**
* Activation hook: ensure the version option is set so the updater can
* track it.
*/
register_activation_hook( __FILE__, 'buddy_on_activate' );
function buddy_on_activate() {
if ( false === get_option( 'buddy_version' ) ) {
add_option( 'buddy_version', BUDDY_VERSION );
} else {
update_option( 'buddy_version', BUDDY_VERSION );
}
}