From 75a097a018a0090f5902758353c578fce4aa2a25 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sat, 23 May 2026 18:43:42 +0000
Subject: [PATCH] =CustomBlocks.php overhaul relatively complete. Also refactored the gallery in gallery.min.js and the jvbRenderGallery.
---
inc/managers/TaxonomyRelationships.php | 380 ++++++++++++++++++++----------------------------------
1 files changed, 141 insertions(+), 239 deletions(-)
diff --git a/inc/managers/TaxonomyRelationships.php b/inc/managers/TaxonomyRelationships.php
index c9cf044..1f919bd 100644
--- a/inc/managers/TaxonomyRelationships.php
+++ b/inc/managers/TaxonomyRelationships.php
@@ -1,9 +1,10 @@
<?php
namespace JVBase\managers;
-use JVBase\JVB;
-use JVBase\managers\CacheManager;
+use Exception;
use WP_Error;
+use WP_Post;
+use WP_Query;
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
@@ -11,15 +12,15 @@
class TaxonomyRelationships
{
- private string $table_name;
- protected object $cache;
-
+ protected Cache $cache;
+ protected CustomTable $relationships;
public function __construct()
{
- global $wpdb;
- $this->table_name = $wpdb->prefix . BASE.'taxonomy_relationships';
- $this->cache = new CacheManager('term_relationship', 86400);
+ $this->defineTables();
+
+ $this->cache = Cache::for('term_relationship', WEEK_IN_SECONDS);
+ $this->cache->connect('terms');
// Ensure the table exists
// $this->create_table_if_not_exists();
@@ -28,13 +29,41 @@
add_action('init', [$this, 'init']);
}
- /**
- * @return string
- */
- public function getTableName():string
- {
- return $this->table_name;
- }
+ protected function defineTables():void
+ {
+ $relationships = CustomTable::for('taxonomy_relationships');
+
+ $relationships->setColumns([
+ 'id' => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
+ 'term_id' => "{$relationships->getTermIDType()} NOT NULL",
+ 'related_term_id' => "{$relationships->getTermIDType()} NOT NULL",
+ 'taxonomy' => 'varchar(32) NOT NULL',
+ 'related_taxonomy' => 'varchar(32) NOT NULL',
+ 'post_count' => 'int(11) NOT NULL DEFAULT 0',
+ 'is_direct' => 'tinyint(1) NOT NULL DEFAULT 1',
+ 'is_hierarchical' => 'tinyint(1) NOT NULL DEFAULT 0',
+ 'last_updated' => 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
+ ]);
+
+ $relationships->setKeys([
+ ['key'=>'PRIMARY', 'value' => '(`id`)'],
+ ['key'=>'UNIQUE', 'value' => '`relation` (`term_id`, `related_term_id`, `taxonomy`, `related_taxonomy`)'],
+ '`term_id` (`term_id`)',
+ '`related_term_id` (`related_term_id`)',
+ '`taxonomy` (`taxonomy`)',
+ '`related_taxonomy` (`related_taxonomy`)'
+ ]);
+ $base = BASE;
+ $relationships->setConstraints([
+ "CONSTRAINT {$base}tax_rel_term_id FOREIGN KEY (`term_id`)
+ REFERENCES `{$relationships->getTermTable()}` (`term_id`) ON DELETE CASCADE",
+ "CONSTRAINT `{$base}tax_rel_related_id` FOREIGN KEY (`related_term_id`)
+ REFERENCES `{$relationships->getTermTable()}` (`term_id`) ON DELETE CASCADE"
+ ]);
+ $relationships->defineTable();
+
+ $this->relationships = $relationships;
+ }
/**
* Hook into term and post saves
@@ -42,8 +71,8 @@
*/
public function init():void
{
- add_action('save_post', [$this, 'updatePostRelationships']);
- add_action('before_delete_post', [$this, 'updatePostRelationships']);
+ add_action('save_post', [$this, 'updatePostRelationships'], 10, 2);
+ add_action('before_delete_post', [$this, 'updatePostRelationships'], 10, 2);
add_action('delete_term', [$this, 'deleteTermRelationships']);
add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
@@ -57,11 +86,14 @@
*
* @return void
*/
- public function updatePostRelationships(int $post_id):void
+ public function updatePostRelationships(int $post_id, WP_Post $post):void
{
- $this->cache->invalidateGroup('term_relationships');
- $post_type = get_post_type($post_id);
- if (in_array($post_type, [BASE.'directory', BASE.'dash'])) {
+ // Skip autosaves and revisions
+ if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
+ return;
+ }
+ $post_type = $post->post_type;
+ if (in_array($post_type, jvbIgnoredPostTypes())) {
return;
}
// Get all taxonomies for this post type
@@ -120,8 +152,6 @@
*/
public function updateRelationship(int $term_id, int $related_term_id, string $taxonomy, string $related_taxonomy):bool
{
- global $wpdb;
-
// Make sure both terms exist
$term = get_term($term_id, $taxonomy);
$related_term = get_term($related_term_id, $related_taxonomy);
@@ -131,61 +161,27 @@
return false;
}
- // Ensure term_id and related_term_id are integers
- $term_id = (int)$term_id;
- $related_term_id = (int)$related_term_id;
+ // Check if term is parent of related term
+ $is_hierarchical = 0;
+ if ($taxonomy === $related_taxonomy) {
+ $ancestors = get_ancestors($related_term_id, $taxonomy, 'taxonomy');
+ if (in_array($term_id, $ancestors)) {
+ $is_hierarchical = 1;
+ }
+ }
+ // Calculate number of shared posts
+ $shared_posts_count = $this->countSharedPosts($term_id, $related_term_id, $taxonomy, $related_taxonomy);
+ $updated = $this->relationships->findOrCreate([
+ 'term_id' => $term_id,
+ 'related_term_id' => $related_term_id,
+ 'taxonomy' => $taxonomy,
+ 'related_taxonomy' => $related_taxonomy
+ ],[
+ 'is_hierarchical' => $is_hierarchical,
+ 'post_count' => $shared_posts_count
+ ]);
- // Check if relationship exists
- $existing = $wpdb->get_row($wpdb->prepare(
- "SELECT id, post_count FROM {$this->table_name}
- WHERE term_id = %d AND related_term_id = %d
- AND taxonomy = %s AND related_taxonomy = %s",
- $term_id,
- $related_term_id,
- $taxonomy,
- $related_taxonomy
- ));
-
- // Calculate number of shared posts
- $shared_posts_count = $this->countSharedPosts($term_id, $related_term_id, $taxonomy, $related_taxonomy);
-
- // Check if term is parent of related term
- $is_hierarchical = 0;
- if ($taxonomy === $related_taxonomy) {
- $ancestors = get_ancestors($related_term_id, $taxonomy, 'taxonomy');
- if (in_array($term_id, $ancestors)) {
- $is_hierarchical = 1;
- }
- }
-
- if ($existing) {
- // Update existing relationship
- $wpdb->update(
- $this->table_name,
- [
- 'post_count' => $shared_posts_count,
- 'is_hierarchical' => $is_hierarchical
- ],
- [
- 'id' => $existing->id
- ]
- );
- } else {
- // Insert new relationship
- $wpdb->insert(
- $this->table_name,
- [
- 'term_id' => $term_id,
- 'related_term_id' => $related_term_id,
- 'taxonomy' => $taxonomy,
- 'related_taxonomy' => $related_taxonomy,
- 'post_count' => $shared_posts_count,
- 'is_hierarchical' => $is_hierarchical
- ]
- );
- }
-
- return true;
+ return (bool)$updated;
}
/**
@@ -198,23 +194,35 @@
*/
private function countSharedPosts(int $term_id, int $related_term_id, string $taxonomy, string $related_taxonomy):int
{
- global $wpdb;
- $term_posts = $wpdb->get_col($wpdb->prepare(
- "SELECT object_id FROM {$wpdb->term_relationships} tr
+ $term_posts = $this->cache->remember(
+ $this->cache->generateKey(['term' => $term_id, 'taxonomy' => $taxonomy]),
+ function () use ($term_id, $taxonomy) {
+ global $wpdb;
+ return $wpdb->get_col($wpdb->prepare(
+ "SELECT object_id FROM {$wpdb->term_relationships} tr
JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
WHERE tt.term_id = %d AND tt.taxonomy = %s",
- $term_id,
- $taxonomy
- ));
+ $term_id,
+ $taxonomy
+ ));
+ }
+ );
- $related_term_posts = $wpdb->get_col($wpdb->prepare(
- "SELECT object_id FROM {$wpdb->term_relationships} tr
+
+ $related_term_posts = $this->cache->remember(
+ $this->cache->generateKey(['term' => $related_term_id, 'taxonomy' => $related_taxonomy]),
+ function () use($related_term_id, $related_taxonomy) {
+ global $wpdb;
+ return $wpdb->get_col($wpdb->prepare(
+ "SELECT object_id FROM {$wpdb->term_relationships} tr
JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
WHERE tt.term_id = %d AND tt.taxonomy = %s",
- $related_term_id,
- $related_taxonomy
- ));
+ $related_term_id,
+ $related_taxonomy
+ ));
+ });
+
return count(array_intersect($term_posts, $related_term_posts));
}
@@ -231,48 +239,14 @@
public function getRelatedTerms(int $term_id, string $desired_taxonomy, bool $include_hierarchical = true):array
{
- $key = sprintf(
- '%d_to_%s',
- $term_id,
- $desired_taxonomy
- );
- if ($include_hierarchical) {
- $key.='_hierarchy';
- }
- $cache = $this->cache->get($key);
- if ($cache) {
- return $cache;
- }
-
- global $wpdb;
-
- $term = get_term($term_id);
- if (is_wp_error($term) || empty($term)) {
- return [];
- }
-
- $query = $wpdb->prepare(
- "SELECT related_term_id
- FROM {$this->table_name}
- WHERE term_id = %d
- AND related_taxonomy = %s",
- $term_id,
- $desired_taxonomy
- );
-
- // Optionally include hierarchical relationships
- if (!$include_hierarchical) {
- $query .= " AND is_hierarchical = 0";
- }
-
- // Order by post count for popularity
- $query .= " ORDER BY post_count DESC";
-
- $related_term_ids = $wpdb->get_col($query);
-
- $this->cache->set($key, $related_term_ids);
-
- return $related_term_ids;
+ $where = [
+ 'term_id' => $term_id,
+ 'related_taxonomy' => $desired_taxonomy
+ ];
+ if (!$include_hierarchical) {
+ $where['is_hierarchical'] = 0;
+ }
+ return $this->relationships->pluck('related_term_id', $where, 'post_count', 'DESC');
}
// Get all related terms based on multiple source terms (for "any" match)
@@ -285,50 +259,9 @@
*/
public function getAnyRelatedTerms(array $term_ids, string $taxonomy):array
{
- if (empty($term_ids)) {
- return [];
- }
+ $term_ids = array_filter(array_map('absint', $term_ids));
+ return array_unique($this->relationships->pluck('related_term_id', ['term_id' => ['IN' => $term_ids], 'related_taxonomy' => $taxonomy], 'post_count', 'DESC'));
- $related_term_ids = [];
- foreach ($term_ids as $term_id) {
- $related = $this->getRelatedTerms($term_id, $taxonomy);
- $related_term_ids = array_merge($related_term_ids, $related);
- }
-
- return array_unique($related_term_ids);
- }
-
- // Get related terms that are common to all source terms (for "all" match)
-
- /**
- * @param array $term_ids
- * @param string $taxonomy
- *
- * @return array
- */
- public function getAllRelatedTerms(array $term_ids, string $taxonomy):array
- {
- if (empty($term_ids)) {
- return [];
- }
-
- $related_sets = [];
- foreach ($term_ids as $term_id) {
- $related = $this->getRelatedTerms($term_id, $taxonomy);
- if (!empty($related)) {
- $related_sets[] = $related;
- }
- }
-
- if (count($related_sets) === 1) {
- return $related_sets[0];
- } elseif (count($related_sets) > 1) {
- // Find intersection of all sets
- $result = array_intersect(...$related_sets);
- return array_values($result);
- }
-
- return [];
}
// Rebuild all relationships (useful for initial setup)
@@ -338,39 +271,42 @@
*/
public function rebuildAllRelationships():bool
{
- $this->cache->invalidateGroup('term_relationships');
+ $this->cache->flush();
global $wpdb;
// Clear existing relationships
- $wpdb->query("TRUNCATE TABLE {$this->table_name}");
- $total_posts = $wpdb->get_var("SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish'");
+ $wpdb->query("TRUNCATE TABLE {$this->relationships->getFullTableName()}");
- // Calculate number of batches needed (50 posts per batch)
- $batch_size = 50;
- $total_batches = ceil($total_posts / $batch_size);
+ $posts = new WP_Query([
+ 'post_status' => 'publish',
+ 'posts_per_page'=> -1,
+ 'fields' => 'ids'
+ ]);
+ if (!$posts->have_posts()) {
+ wp_reset_postdata();
+ return true;
+ }
+
+ $ids = $posts->posts;
+ wp_reset_postdata();
+
// Queue the operation
$queue = JVB()->queue();
- $operation_id = 'taxonomy_rebuild_' . uniqid();
$queue->queueOperation(
'taxonomy_relationships',
1,
[
- 'action' => 'rebuild_all',
- 'offset' => 0,
- 'limit' => $batch_size,
- 'total_posts' => $total_posts,
- 'total_batches' => $total_batches
+ 'posts' => $ids,
],
[
- 'operation_id' => $operation_id,
- 'count' => $total_batches,
- 'priority' => 'normal',
+ 'chunk_key' => 'posts',
+ 'chunk_size' => 50
]
);
- $this->cache->invalidateGroup('term_relationships');
+ $this->cache->flush();
return true;
}
@@ -388,47 +324,20 @@
return $result;
}
- if (isset($data['action']) && $data['action'] === 'rebuild_all') {
- // Clear existing relationships
- global $wpdb;
-
- // Get batch of posts to process
- $offset = isset($data['offset']) ? $data['offset'] : 0;
- $limit = isset($data['limit']) ? $data['limit'] : 50; // Process in batches
-
- $posts = $wpdb->get_col($wpdb->prepare(
- "SELECT ID FROM {$wpdb->posts}
- WHERE post_status = 'publish'
- ORDER BY ID
- LIMIT %d OFFSET %d",
- $limit,
- $offset
- ));
-
- // Process each post
- foreach ($posts as $post_id) {
- $this->updatePostRelationships($post_id);
- }
-
- // Get total number of posts
- $total_posts = $wpdb->get_var("SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish'");
-
- // Return progress information
- return [
- 'success' => true,
- 'result' => [
- 'processed' => count($posts),
- 'offset' => $offset,
- 'next_offset' => $offset + $limit,
- 'total' => $total_posts,
- 'completed' => ($offset + $limit >= $total_posts)
- ]
- ];
- }
- return [
- 'success' => false,
- 'message' => __('Hmmm.', 'jvb')
- ];
+ try {
+ foreach ($data['posts'] as $postID) {
+ $post = get_post($postID);
+ $this->updatePostRelationships($postID, $post);
+ }
+ } catch (Exception $e) {
+ return [
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ];
+ }
+ return [
+ 'success' => true
+ ];
}
// Hook this to term deletion
@@ -440,14 +349,7 @@
*/
public function deleteTermRelationships(int $term_id):void
{
- global $wpdb;
-
- $wpdb->query($wpdb->prepare(
- "DELETE FROM {$this->table_name}
- WHERE term_id = %d OR related_term_id = %d",
- $term_id,
- $term_id
- ));
- $this->cache->invalidateGroup('term_relationships');
+ $termIDs = $this->relationships->delete(['term_id' => $term_id]);
+ $related = $this->relationships->delete(['related_term_id' => $term_id]);
}
}
--
Gitblit v1.10.0