From 6d1fa852b5a652df8fcf26e954302622a4c4cbd7 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Thu, 12 Feb 2026 15:27:00 +0100 Subject: [PATCH 1/2] fix: import `Database` from scaffolding lib and remove instances from .env.ini (#1) This PR fixes instancing issues with `Database` due to not being able to locate its parent class from the scaffolding library. This is definitely kind of strange and should probably be investigated further. It might be because we're not autoloading these files from the library itself. We also remove loading of Database credentials from `.env.ini` as that does not make any sense for a bundled library. Database credentials are now provided to the constructor of the `Database` class. Reviewed-on: https://codeberg.org/vlw/wp/pulls/1 --- .env.example.ini | 4 ---- .gitignore | 2 -- src/Database.php | 35 +++++++++++++++++++++++++++-------- 3 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 .env.example.ini diff --git a/.env.example.ini b/.env.example.ini deleted file mode 100644 index 77e81ba..0000000 --- a/.env.example.ini +++ /dev/null @@ -1,4 +0,0 @@ -[mariadb] -host = "" -user = "" -pass = "" diff --git a/.gitignore b/.gitignore index 76bfadb..22d0d82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -.env.ini - vendor diff --git a/src/Database.php b/src/Database.php index dc84268..2e9a007 100644 --- a/src/Database.php +++ b/src/Database.php @@ -5,11 +5,16 @@ use Exception; use vlw\Scaffold\Database as DatabaseFramework; + require_once dirname(__DIR__, 2) . "/scaffold/src/Database/Database.php"; + class Database extends DatabaseFramework { public static string $name = ""; public static string $site_url = ""; private static string $prefix = "wp"; + private static string $hostname = ""; + private static string $username = ""; + private static string $password = ""; /** * Get a prefixed table name from the database @@ -27,7 +32,13 @@ * @return static */ public static function current(): static { - return new static(self::$name, self::$prefix); + return new static( + self::$hostname, + self::$username, + self::$password, + self::$name, + self::$prefix + ); } /** @@ -36,9 +47,17 @@ * @param string $database * @param string|null $table_prefix */ - public function __construct(string $database, ?string $table_prefix = null) { - $env = parse_ini_file(dirname(__DIR__, 1) . "/.env.ini", process_sections: true); - + public function __construct( + string $hostname, + string $username, + string $password, + string $database, + ?string $table_prefix = null + ) { + self::$hostname = $hostname; + self::$username = $username; + self::$password = $password; + self::$password = $password; self::$name = $database; if ($table_prefix) { @@ -46,10 +65,10 @@ } Database::set_credentials( - $env["mariadb"]["host"], - $env["mariadb"]["user"], - $env["mariadb"]["pass"], - self::$name + $hostname, + $username, + $password, + $database ); $this->set_site_url(); From eebe93fc53b6c23f68af103d140014244d3ae7aa Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Sun, 15 Feb 2026 09:51:02 +0100 Subject: [PATCH 2/2] feat: add parsing of WordPress taxonomies and terms (#2) Reviewed-on: https://codeberg.org/vlw/wp/pulls/2 --- src/Posts/Post.php | 22 ++++- src/Posts/PostMeta.php | 19 +++- src/Posts/Taxonomy/Taxonomy.php | 85 +++++++++++++++++ src/Posts/Taxonomy/Term.php | 155 +++++++++++++++++++++++++++++++ src/Shortcode/Shortcode.php | 2 +- src/Tables/PostMeta.php | 2 +- src/Tables/Posts.php | 2 +- src/Tables/Taxonomies.php | 18 ++++ src/Tables/TermRelationships.php | 15 +++ src/Tables/Terms.php | 16 ++++ 10 files changed, 324 insertions(+), 12 deletions(-) create mode 100644 src/Posts/Taxonomy/Taxonomy.php create mode 100644 src/Posts/Taxonomy/Term.php create mode 100644 src/Tables/Taxonomies.php create mode 100644 src/Tables/TermRelationships.php create mode 100644 src/Tables/Terms.php diff --git a/src/Posts/Post.php b/src/Posts/Post.php index e431677..5b7ff07 100644 --- a/src/Posts/Post.php +++ b/src/Posts/Post.php @@ -9,8 +9,11 @@ use vlw\WP\Database; use vlw\WP\Tables\Posts; use vlw\WP\Posts\PostMeta; + use vlw\WP\Posts\Taxonomy\Term; + use vlw\WP\Posts\Type\Attachment; use function vlw\WP\Support\slugify; + require_once "Taxonomy/Term.php"; require_once dirname(__DIR__, 1) . "/Tables/Posts.php"; require_once dirname(__DIR__, 1) . "/Support/Slugify.php"; @@ -21,10 +24,10 @@ * @param string $name * @return static|null */ - public static function from_name(string $name): ?static { + public static function from_name(string $name, bool $slugify = true): ?static { $query = Database::current() - ->from(Database::get_table(Posts::NAME)) - ->where([Posts::POST_NAME->value => slugify($name)]) + ->from(Database::get_table(Posts::TABLE_NAME)) + ->where([Posts::POST_NAME->value => $slugify ? slugify($name) : $name]) ->limit(1) ->select(Posts::ID->value); @@ -70,7 +73,7 @@ Posts::COMMENT_COUNT->value => 0 ]; - if (!parent::create(Database::get_table(Posts::NAME), $values)) { + if (!parent::create(Database::get_table(Posts::TABLE_NAME), $values)) { throw new Exception("Failed to create database entity"); } @@ -79,7 +82,7 @@ public function __construct(public readonly int $id) { parent::__construct( - Database::get_table(Posts::NAME), + Database::get_table(Posts::TABLE_NAME), Posts::values(), [Posts::ID->value => (int) $id] ); @@ -95,6 +98,15 @@ return $key ? PostMeta::get_post_meta($this, $key) : PostMeta::get_all_post_meta($this); } + /** + * Returns an array of all Terms assigned to this Post + * + * @return array + */ + public function terms(): array { + return Term::from_post($this); + } + public int $post_author { get => $this->get(Posts::POST_AUTHOR->value); set (int $post_author) => $this->set(Posts::POST_AUTHOR->value, $post_author); diff --git a/src/Posts/PostMeta.php b/src/Posts/PostMeta.php index 7c14594..750f08d 100644 --- a/src/Posts/PostMeta.php +++ b/src/Posts/PostMeta.php @@ -22,7 +22,7 @@ */ public static function get_post_meta(Post $post, string $key): static|false { $query = Database::current() - ->from(Database::get_table(PostMetaTable::NAME)) + ->from(Database::get_table(PostMetaTable::TABLE_NAME)) ->where([ PostMetaTable::POST_ID->value => $post->id, PostMetaTable::META_KEY->value => $key @@ -41,7 +41,7 @@ */ public static function get_all_post_meta(Post $post): array { $query = Database::current() - ->from(Database::get_table(PostMetaTable::NAME)) + ->from(Database::get_table(PostMetaTable::TABLE_NAME)) ->where([PostMetaTable::POST_ID->value => $post->id]) ->select(PostMetaTable::META_ID->value); @@ -71,7 +71,7 @@ PostMetaTable::META_VALUE->value => $meta_value ]; - if (!parent::create(Database::get_table(PostMetaTable::NAME), $values)) { + if (!parent::create(Database::get_table(PostMetaTable::TABLE_NAME), $values)) { throw new Exception("Failed to create database entity"); } @@ -80,12 +80,23 @@ public function __construct(public readonly int $id) { parent::__construct( - Database::get_table(PostMetaTable::NAME), + Database::get_table(PostMetaTable::TABLE_NAME), PostMetaTable::values(), [PostMetaTable::META_ID->value => (int) $id] ); } + /** + * Delete this post meta field from the database + * + * @return void + */ + public function delete(): void { + $this->db + ->from(PostMetaTable::TABLE_NAME) + ->delete([PostMetaTable::META_ID->value => $this->id]); + } + public Post $post { get => new Post($this->get(PostMetaTable::POST_ID->value)); set (Post $post) => $this->set(PostMetaTable::POST_ID->value, $post->id); diff --git a/src/Posts/Taxonomy/Taxonomy.php b/src/Posts/Taxonomy/Taxonomy.php new file mode 100644 index 0000000..548fac6 --- /dev/null +++ b/src/Posts/Taxonomy/Taxonomy.php @@ -0,0 +1,85 @@ +from(Database::get_table(Taxonomies::TABLE_NAME)) + ->where([Taxonomies::TAXONOMY->value => $taxonomy]) + ->limit(1) + ->select(Taxonomies::TERM_TAXONOMY_ID->value); + + return $query->num_rows === 1 ? new static($query->fetch_assoc()[Taxonomies::TERM_ID->value]) : null; + } + + /** + * Create a new post meta field for a given post + * + * @param string $title Post title + * @param string $type Post type + * @return static + */ + public static function new(string $taxonomy): static { + // Return existing instance of Taxonomy if it exists + if (self::from($taxonomy)) { + return self::from($taxonomy); + } + + $values = [ + Taxonomies::TERM_TAXONOMY_ID->value => null, + Taxonomies::TERM_ID->value => 0, + Taxonomies::DESCRIPTION->value => "", + Taxonomies::PARENT->value => 0, + Taxonomies::COUNT->value => 0 + ]; + + if (!parent::create(Database::get_table(Taxonomies::TABLE_NAME), $values)) { + throw new Exception("Failed to create database entity"); + } + + return self::from($taxonomy); + } + + public function __construct(public readonly int $id) { + parent::__construct( + Database::get_table(Taxonomies::TABLE_NAME), + Taxonomies::values(), + [Taxonomies::TERM_TAXONOMY_ID->value => (int) $id] + ); + } + + public Term $term { + get => new Term($this->get(Taxonomies::TERM_ID->value)); + set (Term $term) => $this->set(Taxonomies::TERM_ID->value, $term->id); + } + + public string $taxonomy { + get => $this->get(Taxonomies::TAXONOMY->value); + set (string $taxonomy) => $this->set(Taxonomies::TAXONOMY->value, $taxonomy); + } + + public string $description { + get => $this->get(Taxonomies::DESCRIPTION->value); + set (string $description) => $this->set(Taxonomies::DESCRIPTION->value, $description); + } + + public ?self $parent { + get => $this->get(Taxonomies::PARENT->value) ? new self($this->get(Taxonomies::PARENT->value)) : null; + set (?self $parent) => $this->set(Taxonomies::PARENT->value, $parent->id); + } + } diff --git a/src/Posts/Taxonomy/Term.php b/src/Posts/Taxonomy/Term.php new file mode 100644 index 0000000..2ece00d --- /dev/null +++ b/src/Posts/Taxonomy/Term.php @@ -0,0 +1,155 @@ +from(Database::get_table(Terms::TABLE_NAME)) + ->where([Terms::NAME->value => $name]) + ->limit(1) + ->select(Terms::TERM_ID->value); + + return $query->num_rows === 1 ? new static($query->fetch_assoc()[Terms::TERM_ID->value]) : null; + } + + /** + * Returns an array of all Terms associated with a Post + * + * @param Post $post + * @return array + */ + public static function from_post(Post $post): array { + $query = Database::current() + ->from(Database::get_table(TermRelationships::TABLE_NAME)) + ->where([TermRelationships::OBJECT_ID->value => $post->id]) + ->select(TermRelationships::TERM_TAXONOMY_ID->value); + + return array_map(fn(array $post_meta): static => new static($post_meta[TermRelationships::TERM_TAXONOMY_ID->value]), $query->fetch_all(MYSQLI_ASSOC)); + } + + /** + * Create a new post meta field for a given post + * + * @param string $title Post title + * @param string $type Post type + * @return static + */ + public static function new(string $name, ?string $slug = null): static { + // Update and return meta key for existing id + if (self::from_name($name)) { + $model = self::from_name($name); + $model->slug = $slug; + + return $model; + } + + $values = [ + Terms::TERM_ID->value => null, + Terms::NAME->value => $name, + Terms::SLUG->value => $slug, + Terms::TERM_GROUP->value => 0 + ]; + + if (!parent::create(Database::get_table(Terms::TABLE_NAME), $values)) { + throw new Exception("Failed to create database entity"); + } + + return self::from_name($name); + } + + public function __construct(public readonly int $id) { + parent::__construct( + Database::get_table(Terms::TABLE_NAME), + Terms::values(), + [Terms::TERM_ID->value => $id] + ); + } + + /** + * Returns the corresponding Taxonomy for this Term + * + * @return Taxonomy + */ + public function taxonomy(): Taxonomy { + return new Taxonomy($this->id); + } + + /** + * Add this Term to a target Post + * + * @param Post $post + * @return void + */ + public function add_to_post(Post $post): void { + // Bail out if this term has already been added to the target Post + if (self::from_post($post)) { + return; + } + + $query = Database::current() + ->from(Database::get_table(TermRelationships::TABLE_NAME)) + ->insert([ + TermRelationships::OBJECT_ID->value => $post->id, + TermRelationships::TERM_TAXONOMY_ID->value => $this->id, + TermRelationships::TERM_ORDER->value => 0 + ]); + + if ($query === false) { + throw new Exception("Failed to create database entity"); + } + } + + /** + * Remove this Term from a target Post + * + * @param Post $post + * @return void + */ + public function remove_from_post(Post $post): void { + $query = Database::current() + ->from(Database::get_table(TermRelationships::TABLE_NAME)) + ->delete([ + TermRelationships::OBJECT_ID->value => $post->id, + TermRelationships::TERM_TAXONOMY_ID->value => $this->id + ]); + + if ($query === false) { + throw new Exception("Failed to create database entity"); + } + } + + public string $name { + get => $this->get(Terms::NAME->value); + set (string $name) => $this->set(Terms::NAME->value, $name); + } + + public string $slug { + get => $this->get(Terms::SLUG->value); + set (string $slug) => $this->set(Terms::SLUG->value, $slug); + } + + public int $term_group { + get => $this->get(Terms::TERM_GROUP->value); + set (int $term_group) => $this->set(Terms::TERM_GROUP->value, $term_group); + } + } diff --git a/src/Shortcode/Shortcode.php b/src/Shortcode/Shortcode.php index 257e38e..e3228a6 100644 --- a/src/Shortcode/Shortcode.php +++ b/src/Shortcode/Shortcode.php @@ -17,7 +17,7 @@ * @param string $name * @return array */ - public static function get_shortcodes(string &$source, string $name): array { + public static function get_shortcodes(string $source, string $name): array { $matches = []; preg_match_all("/\[{$name} /", $source, $matches, PREG_OFFSET_CAPTURE); diff --git a/src/Tables/PostMeta.php b/src/Tables/PostMeta.php index 58830da..d4d2613 100644 --- a/src/Tables/PostMeta.php +++ b/src/Tables/PostMeta.php @@ -7,7 +7,7 @@ enum PostMeta: string { use xEnum; - public const NAME = "postmeta"; + public const TABLE_NAME = "postmeta"; case META_ID = "meta_id"; case POST_ID = "post_id"; diff --git a/src/Tables/Posts.php b/src/Tables/Posts.php index d57884f..b9e8e50 100644 --- a/src/Tables/Posts.php +++ b/src/Tables/Posts.php @@ -7,7 +7,7 @@ enum Posts: string { use xEnum; - public const NAME = "posts"; + public const TABLE_NAME = "posts"; case ID = 'ID'; case POST_AUTHOR = 'post_author'; diff --git a/src/Tables/Taxonomies.php b/src/Tables/Taxonomies.php new file mode 100644 index 0000000..7632672 --- /dev/null +++ b/src/Tables/Taxonomies.php @@ -0,0 +1,18 @@ +