Jake Vanderwerf
2026-08-25 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a
inc/managers/Favourites.php
File was renamed from inc/managers/FavouritesManager.php
@@ -2,22 +2,27 @@
namespace JVBase\managers;
use Exception;
use JVBase\Instance;
use JVBase\registrar\Registrar;
use JVBase\rest\Rest;
use JVBase\rest\routes\FavouritesRoutes;
if (!defined('ABSPATH')) {
   exit; // Exit if accessed directly
}
class FavouritesManager
class Favourites
{
   private Cache $cache;
   use Instance;
   protected CustomTable $favourites;
   protected CustomTable $lists;
   protected CustomTable $listItems;
   protected CustomTable $listShares;
   protected Rest $route;
   public function __construct()
   {
      $this->route = FavouritesRoutes::getInstance();
      $this->defineTables();
      $this->registerHooks();
   }
@@ -28,6 +33,11 @@
      add_action('delete_term', [$this, 'cleanupTermFavourites'], 10, 3);
      add_action('jvbUserRegistered', [$this, 'maybeAcceptListInvite'], 10, 3);
      add_action('jvb_cleanupOrphanedFavourites', [$this, 'cleanupOrphanedFavourites']);
      //adds favourite ordering to wp_query/tax_query
      add_filter('posts_join', [$this, 'maybeJoinFavouriteOrderby'], 10, 2);
      add_filter('posts_orderby', [$this, 'maybeApplyFavouriteOrderby'], 10, 2);
      add_filter('terms_clauses', [$this, 'maybeApplyFavouriteTermOrderby'], 10, 3);
   }
   protected function defineTables():void
   {
@@ -210,7 +220,7 @@
         );
         if ($owner) {
            JVB()->notification()->addNotification(
            NotificationManager::getInstance()->addNotification(
               $owner,
               'new_favourite',
               $user_id,
@@ -229,10 +239,10 @@
         ]);
         if (in_array($registerType, ['term', 'user'])) {
            JVB()->notification()->deleteUserPreference($user_id, $target_id, $type);
            NotificationManager::getInstance()->deleteUserPreference($user_id, $target_id, $type);
         }
         if ($owner) {
            JVB()->notification()->removeNotification(
            NotificationManager::getInstance()->removeNotification(
               $owner,
               [
                  'from_user' => $user_id,
@@ -254,6 +264,45 @@
         return $this->toggleFavourite(false, $user_id, $target_id, $type);
      }
      public function hasFavourited(int $user_id, int $target_id, string $type):bool
      {
         return (bool) $this->favourites->get([
            'user_id'   => $user_id,
            'target_id' => $target_id,
            'type'      => $type
         ]);
      }
      public function batchToggleFavourites(int $user_id, array $items):array
      {
         $items = array_filter($items, function ($item) {
            $keys = ['target_id', 'type', 'action'];
            foreach ($keys as $key) {
               if (!array_key_exists($key, $item)) {
                  return false;
               }
               if (empty($item[$key])) {
                  return false;
               }
            }
            if (!in_array($item['action'], ['add', 'remove'])) {
               return false;
            }
            return true;
         });
         if (empty($items)) {
            return [];
         }
         $results = [];
         foreach ($items as $item) {
            $results[$item['target_id']] =$this->toggleFavourite($item['action'] === 'add', $user_id, $item['target_id'], $item['type']);
         }
         return $results;
      }
      public function addNoteFromTarget(int $user_id, int $target_id, string $type, string $note):bool
      {
         $favourite = $this->favourites->get([
@@ -378,7 +427,7 @@
         $args = [];
         if ($shareWithUser) {
            $args['user_id'] = $shareWithUser;
            JVB()->notification()->addNotification($shareWithUser, 'list_shared', $user_id, '', $listId);
            NotificationManager::getInstance()->addNotification($shareWithUser, 'list_shared', $user_id, '', $listId);
         } elseif ($newUser) {
            $email = sanitize_email($newUser['email']);
            $name = sanitize_text_field($newUser['name']);
@@ -408,7 +457,7 @@
         if (is_int($userIDorEmail)) {
            $where['user_id'] = $userIDorEmail;
            $notification = JVB()->notification()->table();
            $notification = NotificationManager::getInstance()->table();
            $n = $notification->get([
               'for_user' => $userIDorEmail,
               'from_user' => $user_id,
@@ -455,7 +504,7 @@
               $message = $accept ? 'accepted' : 'rejected';
               $message = $user->first_name . ' ' . $message . ' your list share invitation.';
               JVB()->notification()->addNotification($list->user_id, 'list_share_status', $userIDorEmail, $message);
               NotificationManager::getInstance()->addNotification($list->user_id, 'list_share_status', $userIDorEmail, $message);
            }
         }else if (is_email($userIDorEmail)) {
            $args['email'] = sanitize_email($userIDorEmail);
@@ -517,7 +566,7 @@
         public function getListDetails(int $list_id, int $user_id, int $page = 1):array
         {
            $list = JVB()->favourites()->getLists(['id' => $list_id, 'user_id' => $user_id]);
            $list = Favourites::getInstance()->getLists(['id' => $list_id, 'user_id' => $user_id]);
            if (!$list) {
               return [];
            }
@@ -792,4 +841,55 @@
         ]);
      }
   }
   /**
    * Join favourite counts for WP_Query when orderby => 'favourite_count'
    */
   public function maybeJoinFavouriteOrderby(string $join, \WP_Query $query): string
   {
      if ($query->get('orderby') !== 'favourites_count') {
         return $join;
      }
      global $wpdb;
      $table = $this->favourites->getFullTableName();
      $type = $query->get('post_type') ?: 'post';
      $join .= $wpdb->prepare(
         " LEFT JOIN (SELECT target_id, COUNT(*) as fav_count FROM {$table} WHERE type = %s GROUP BY target_id) jvb_fav_counts ON jvb_fav_counts.target_id = {$wpdb->posts}.ID",
         $type
      );
      return $join;
   }
   public function maybeApplyFavouriteOrderby(string $orderby, \WP_Query $query): string
   {
      if ($query->get('orderby') !== 'favourites_count') {
         return $orderby;
      }
      $order = strtoupper($query->get('order')) === 'ASC' ? 'ASC' : 'DESC';
      return "COALESCE(jvb_fav_counts.fav_count, 0) {$order}";
   }
   /**
    * Join + order for WP_Term_Query when orderby => 'favourite_count'
    */
   public function maybeApplyFavouriteTermOrderby(array $clauses, array $taxonomies, array $args): array
   {
      if (($args['orderby'] ?? '') !== 'favourites_count') {
         return $clauses;
      }
      global $wpdb;
      $table = $this->favourites->getFullTableName();
      $type = jvbCheckBase($taxonomies[0] ?? '');
      $clauses['join'] .= $wpdb->prepare(
         " LEFT JOIN (SELECT target_id, COUNT(*) as fav_count FROM {$table} WHERE type = %s GROUP BY target_id) jvb_fav_counts ON jvb_fav_counts.target_id = t.term_id",
         $type
      );
      $order = strtoupper($args['order'] ?? 'DESC') === 'ASC' ? 'ASC' : 'DESC';
      $clauses['orderby'] = "ORDER BY COALESCE(jvb_fav_counts.fav_count, 0)";
      $clauses['order'] = $order;
      return $clauses;
   }
}