From c19264ac916707096fe294d996a1b7fb85206b34 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 08 Mar 2026 19:55:31 +0000
Subject: [PATCH] =Furthering along the complete refactor. Added some basic setup for is_content taxonomies, including a page for an archive of the terms.
---
inc/managers/CustomTable.php | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 225 insertions(+), 1 deletions(-)
diff --git a/inc/managers/CustomTable.php b/inc/managers/CustomTable.php
index 893e5ad..4299b71 100644
--- a/inc/managers/CustomTable.php
+++ b/inc/managers/CustomTable.php
@@ -21,11 +21,21 @@
{
protected \wpdb $wpdb;
protected string $tableName;
+ protected string $definition;
protected string $fullTableName;
protected bool $useTransactions;
+ protected array $columns;
+ protected array $keys = [];
+ protected array $constraints =[];
/** @var array<string, self> Instance cache for fluent interface */
protected static array $instances = [];
+ protected static string $charsetCollate;
+
+ protected static string $userTable;
+ protected static string $userIDType;
+ protected static string $termIDType;
+ protected static string $postIDType;
/**
* Fluent factory method
@@ -41,9 +51,167 @@
self::$instances[$tableName] = new self($tableName);
}
+
return self::$instances[$tableName];
}
+ public function ensureDefined() {
+ $this->ensureUserTable();
+ $this->ensureUserIDType();
+ $this->ensureTermIDType();
+ $this->ensurePostIDType();
+ }
+ protected function ensureUserTable():void
+ {
+ if (!isset(static::$userTable)) {
+ static::$userTable = is_multisite() ? $this->getMultisiteUsersTable() : $this->wpdb->users;
+ }
+ }
+ protected function getMultisiteUsersTable():string
+ {
+ $siteUsersTable = $this->wpdb->prefix . 'users';
+ $siteExists = $this->wpdb->get_var(
+ $this->wpdb->prepare("SHOW TABLES LIKE %s", $siteUsersTable)
+ );
+ if ($siteExists) {
+ return $siteUsersTable;
+ }
+ //fallback to main one
+ return $this->wpdb->users;
+ }
+ protected function ensureUserIDType():void
+ {
+ if (!isset(static::$userIDType)) {
+ $this->ensureUserTable();
+ static::$userIDType = $this->getColumnType(static::$userTable, 'ID');
+ }
+ }
+
+ protected function ensureTermIDType():void
+ {
+ if (!isset(static::$termIDType)) {
+ static::$termIDType = $this->getColumnType($this->wpdb->terms, 'term_id');
+ }
+ }
+
+ protected function ensurePostIDType():void
+ {
+ if (!isset(static::$postIDType)) {
+ static::$postIDType = $this->getColumnType($this->wpdb->posts, 'ID');
+ }
+ }
+
+ /**
+ *
+ * @param array $columns An array of $columnName => $columnDefinition
+ * @return $this
+ */
+ public function setColumns(array $columns):self
+ {
+ $this->columns = $columns;
+ return $this;
+ }
+
+ /**
+ * @param array $keys An array of {string} $keys. If a $key is an array, you can define a custom $key => $value, example: 'UNIQUE' => $value, or 'PRIMARY' => $value
+ * @return $this
+ */
+ public function setKeys(array $keys):self
+ {
+ $this->keys = $keys;
+ return $this;
+ }
+
+ /**
+ * @param array $constraints an array of arrays, each value a $constraint => $references
+ * @return $this
+ */
+ public function setConstraints(array $constraints):self
+ {
+ $this->constraints = $constraints;
+ return $this;
+ }
+
+ public function defineTable(): self
+ {
+ if (empty($this->columns)) {
+ error_log('[CustomTable] No columns defined for ' . $this->tableName);
+ return $this;
+ }
+
+ $parts = [];
+
+ // Columns
+ foreach ($this->columns as $name => $type) {
+ $parts[] = "`{$name}` {$type}";
+ }
+
+ // Keys
+ if (empty($this->keys)) {
+ $parts[] = 'PRIMARY KEY (`' . array_key_first($this->columns) . '`)';
+ } else {
+ foreach ($this->keys as $key) {
+ if (is_array($key)) {
+ $value = $key['value'];
+ // Ensure value is wrapped in parentheses
+ if (!str_starts_with(trim($value), '(')) {
+ $value = '(`' . $value . '`)';
+ }
+ $parts[] = $key['key'] . ' KEY ' . $value;
+ } else {
+ $parts[] = 'KEY ' . $key;
+ }
+ }
+ }
+
+ // Constraints
+ foreach ($this->constraints as $constraint => $references) {
+ $parts[] = "CONSTRAINT {$constraint} REFERENCES {$references}";
+ }
+
+ $this->definition = "(\n " . implode(",\n ", $parts) . "\n)";
+ return $this;
+ }
+
+ public static function ensureTables():void
+ {
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+
+ foreach (self::$instances as $instance) {
+ if (!$instance->wpdb->get_var("SHOW TABLES LIKE '{$instance->fullTableName}'")) {
+ $instance->createTable();
+ }
+ }
+ }
+
+ protected function createTable():void
+ {
+ if (!$this->definition && empty($this->definition)) {
+ error_log('[CustomTable]No definition set for '.$this->tableName);
+ return;
+ }
+ $charset = self::$charsetCollate;
+ $schema = "CREATE TABLE IF NOT EXISTS {$this->fullTableName} {$this->definition} {$charset}";
+ $this->wpdb->flush();
+
+ $hasForeignKey = stripos($schema, 'FOREIGN KEY') !== false;
+ if ($hasForeignKey) {
+ $result = $this->wpdb->query($schema);
+ $success = ($result !== false && !$this->wpdb->last_error);
+ } else {
+ dbDelta($schema.';');
+ $success = !$this->wpdb->last_error;
+ }
+
+ if (!$success) {
+ $error_msg = "SQL Error creating table {$this->tableName}: " . $this->wpdb->last_error;
+ error_log($error_msg);
+ error_log("Failed SQL Query: " . $schema);
+ } elseif ($this->wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")) {
+ error_log("Successfully created table: {$this->fullTableName}");
+ }
+ }
+
/**
* Clear instance cache (useful for testing)
*/
@@ -61,8 +229,13 @@
global $wpdb;
$this->wpdb = $wpdb;
$this->tableName = $tableName;
- $this->fullTableName = $wpdb->prefix . BASE . $tableName;
+ $this->fullTableName = $wpdb->prefix . apply_filters('jvb_base', BASE) . $tableName;
$this->useTransactions = $useTransactions;
+
+ $usersStatus = $this->wpdb->get_row("SHOW TABLE STATUS LIKE '{$this->wpdb->users}'");
+ $parentCollation = $usersStatus->Collation ?? 'utf8mb4_general_ci';
+ self::$charsetCollate = "DEFAULT CHARACTER SET utf8mb4 COLLATE {$parentCollation}";
+
}
// =========================================================================
@@ -678,10 +851,61 @@
return $this->wpdb->rows_affected;
}
+ public function getUserIDType():string
+ {
+ $this->ensureUserIdType();
+ return static::$userIDType;
+ }
+ public function getUserTable():string
+ {
+ $this->ensureUserTable();
+ return static::$userTable;
+ }
+ public function getTermIDType():string
+ {
+ $this->ensureTermIDType();
+ return static::$termIDType;
+ }
+ public function getPostIDType():string
+ {
+ $this->ensurePostIDType();
+ return static::$postIDType;
+ }
+
// =========================================================================
// PRIVATE HELPERS
// =========================================================================
+ private function getColumnType(string $table, string $column):string|false {
+ $tableExists = $this->wpdb->get_var(
+ $this->wpdb->prepare("SHOW TABLES LIKE %s", $table)
+ );
+ if (!$tableExists) {
+ error_log("[CustomTable] Table {$table} does not exist for getColumnType");
+ return 'bigint(20) unsigned'; // safe fallback
+ }
+ $result = $this->wpdb->get_row(
+ $this->wpdb->prepare(
+ "SELECT COLUMN_TYPE
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = %s
+ AND COLUMN_NAME = %s",
+ $table,
+ $column
+ )
+ );
+ if ($result && isset($result->COLUMN_TYPE)) {
+ return $result->COLUMN_TYPE;
+ }
+ error_log("[CustomTable] Could not determine column type for {$table}.{$column}");
+ return 'bigint(20) unsigned';
+ }
+
+ private function tableExists():bool
+ {
+ return !is_null($this->wpdb->get_var($this->wpdb->prepare("SHOW TABLES LIKE %s", $this->fullTableName)));
+ }
/**
* Build WHERE clause from associative array
*/
--
Gitblit v1.10.0