From f4be611c51473359e6d41780f0313c446079e9d3 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 09 Jun 2026 15:19:24 +0000
Subject: [PATCH] =Switched the /base/options.php to the same pattern as Site.php: a class based approached rather than a filter. Updated Meta.php to play along with the defined fields from there in Meta::forOptions. Had to change openingHoursSpecificationsTrait.php to not use the translater functions __('text','textdomain') for now, as we load before init.
---
inc/managers/FavouritesManager.php | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)
diff --git a/inc/managers/FavouritesManager.php b/inc/managers/FavouritesManager.php
index 125c75a..c2f2c05 100644
--- a/inc/managers/FavouritesManager.php
+++ b/inc/managers/FavouritesManager.php
@@ -1,6 +1,7 @@
<?php
namespace JVBase\managers;
+use Exception;
use JVBase\registrar\Registrar;
if (!defined('ABSPATH')) {
@@ -18,8 +19,16 @@
public function __construct()
{
$this->defineTables();
+ $this->registerHooks();
}
+ protected function registerHooks():void
+ {
+ add_action('before_delete_post', [$this, 'cleanupPostFavourites']);
+ add_action('delete_term', [$this, 'cleanupTermFavourites'], 10, 3);
+ add_action('jvbUserRegistered', [$this, 'maybeAcceptListInvite'], 10, 3);
+ add_action('jvb_cleanupOrphanedFavourites', [$this, 'cleanupOrphanedFavourites']);
+ }
protected function defineTables():void
{
$this->defineFavouriteTable();
@@ -126,6 +135,7 @@
'list_id' => 'bigint(20) unsigned NOT NULL',
'user_id' => "{$table->getUserIDType()} NOT NULL",
'email' => 'varchar(255) NOT NULL',
+ 'invite_token' => 'varchar(255) NOT NULL',
'permission' => "ENUM('view', 'edit') NOT NULL DEFAULT 'view'",
'status' => "ENUM('pending', 'accepted', 'rejected', 'revoked') NOT NULL DEFAULT 'pending'",
'created_at' => 'datetime NOT NULL DEFAULT CURRENT_TIMESTAMP',
@@ -372,6 +382,7 @@
} elseif ($newUser) {
$email = sanitize_email($newUser['email']);
$name = sanitize_text_field($newUser['name']);
+ $args['invite_token'] = wp_generate_password(32, false);
$args['email'] = $email;
//TODO: Magic Link setup
}
@@ -570,6 +581,59 @@
'shared_users' => $sharedWith
];
}
+
+ public function getFavouriteCounts(int $user_id): array
+ {
+ $results = $this->favourites->queryResults(
+ "SELECT type, COUNT(*) as count FROM {table} WHERE user_id = %d GROUP BY type",
+ [$user_id]
+ );
+
+ $counts = [];
+ foreach ($results as $row) {
+ $type = str_replace(BASE, '', $row->type);
+ $counts[$type] = (int) $row->count;
+ }
+ $defaults = array_fill_keys(
+ array_map(fn($t) => str_replace(BASE, '', $t), Registrar::withFeature('favouritable')),
+ 0
+ );
+ return array_merge($defaults, $counts);
+ }
+
+ public function cleanupOrphanedFavourites(): bool
+ {
+ global $wpdb;
+
+ // Posts - no FK possible since target_id is generic
+ $this->favourites->query(
+ "DELETE f FROM {table} f
+ LEFT JOIN {$wpdb->posts} p ON f.target_id = p.ID
+ WHERE f.type IN (
+ SELECT CONCAT('" . BASE . "', post_type)
+ FROM {$wpdb->posts} GROUP BY post_type
+ )
+ AND p.ID IS NULL"
+ );
+
+ // Terms - same reason
+ $this->favourites->query(
+ "DELETE f FROM {table} f
+ LEFT JOIN {$wpdb->term_taxonomy} tt ON f.target_id = tt.term_id
+ AND f.type = CONCAT('" . BASE . "', tt.taxonomy)
+ WHERE tt.term_id IS NULL
+ AND f.type != CONCAT('" . BASE . "', 'user')"
+ );
+
+ $this->listItems->query(
+ "DELETE li FROM {table} li
+ LEFT JOIN {$wpdb->posts} p ON li.target_id = p.ID
+ LEFT JOIN {$wpdb->term_taxonomy} tt ON li.target_id = tt.term_id
+ WHERE p.ID IS NULL AND tt.term_id IS NULL"
+ );
+
+ return true;
+ }
/***************************************************************
* UTILITY METHODS
**************************************************************/
@@ -682,4 +746,50 @@
unset($notes[$index]);
return array_values($notes); //reindexed array
}
+
+ public function cleanupPostFavourites(int $post_id):void
+ {
+ try {
+ $type = get_post_type($post_id);
+ if (!$type) return;
+
+ $this->favourites->where([
+ 'type' => $type,
+ 'target_id' => $post_id
+ ])->deleteResults();
+
+ $this->listItems->where([
+ 'item_type' => $type,
+ 'item_id' => $post_id
+ ])->deleteResults();
+ } catch (Exception $e) {
+ JVB()->error()->log('cleanupPostFavourites', $e->getMessage(), [
+ 'post_id' => $post_id
+ ]);
+ }
+ }
+
+ public function cleanupTermFavourites(int $term_id, int $tt_id, string $taxonomy):void
+ {
+ try {
+ $registrar = Registrar::getInstance($taxonomy);
+ if (!$registrar || !$registrar->hasFeature('favouritable')) {
+ return;
+ }
+ $this->favourites->where([
+ 'type' => $taxonomy,
+ 'target_id' => $term_id,
+ ])->deleteResults();
+
+ $this->listItems->where([
+ 'item_type' => $taxonomy,
+ 'item_id' => $term_id
+ ])->deleteResults();
+ } catch (Exception $e) {
+ JVB()->error()->log('cleanupTermFavourites', $e->getMessage(), [
+ 'term_id' => $term_id,
+ 'taxonomy'=> $taxonomy
+ ]);
+ }
+ }
}
--
Gitblit v1.10.0