Jake Vanderwerf
2026-06-22 715e26a9eb219808d5c899d418e1d596f9318f61
inc/registrar/Posts.php
@@ -1,6 +1,8 @@
<?php
namespace JVBase\registrar;
use JVBase\forms\TaxonomySelector;
if (!defined('ABSPATH')) {
   exit;
}
@@ -8,6 +10,8 @@
   public string $postType;
   public string $singular;
   public string $plural;
   public bool $baseless = false;
   public bool $modify = false;
   public array $labels;
   /**
    * Whether a post type is intended for use publicly either via the admin interface or by front-end users.
@@ -208,15 +212,19 @@
    * @var string|false
    */
   public string|false $template_lock;
   protected string $unbased;
   protected ?string $taxonomyRewrite = null;
   public function __construct(string $postType, string $singular, string $plural)
   {
      $this->unbased = jvbNoBase($postType);
      $this->postType = jvbCheckBase($postType);
      $this->labels = $this->buildLabels($singular, $plural);
      $this->singular = $singular;
      $this->plural = $plural;
   }
   public function register():void
   {
   protected function buildArgs():array {
      $args = array_filter(get_object_vars($this));
//    error_log('Got Object Vars: '.print_r($args, true));
//    error_log('Filtered: '.print_r(array_filter($args), true));
@@ -312,7 +320,41 @@
      unset ($args['postType']);
//    error_log('Registering PostType '.$this->postType.', with args: '.print_r($args, true));
      $registered = register_post_type($this->postType, $args);
      $registrar = Registrar::getInstance($this->postType);
      $rewrite = $args['rewrite']['slug']??'';
      if ($registrar) {
         $hasSlug = array_key_exists('rewrite', $args) && array_key_exists('slug', $args['rewrite']);
         if ($registrar->rewrite_taxonomy && !str_contains($rewrite, '%')) {
            if (!$hasSlug && !array_key_exists('rewrite', $args)) {
               $args['rewrite'] = [];
            }
            $tax = is_array($registrar->rewrite_taxonomy) ? $registrar->rewrite_taxonomy[array_key_first($registrar->rewrite_taxonomy)] : $registrar->rewrite_taxonomy;
            $args['rewrite']['slug'] = $hasSlug ? $rewrite."/%{$tax}%" : $this->unbased."/%{$tax}%";
         }
         if ($registrar->hasFeature('is_calendar')) {
            if (!$hasSlug && !array_key_exists('rewrite', $args)) {
               $args['rewrite'] = [];
            }
            $args['rewrite']['slug'] = $hasSlug ? $rewrite."/%eyear%/%emonth%/%eday%" : $this->unbased."/%eyear%/%emonth%/%eday%";
         }
      }
      return $args;
   }
   public function register():void
   {
      $args = $this->buildArgs();
      $registered = true;
      if (!$this->modify) {
         $registered = register_post_type($this->postType, $args);
      }
      if (is_wp_error($registered)) {
         JVB()->error()->log('JVBase\registrar\Posts', 'Could not register post type', $registered->get_error_messages());
      }
@@ -337,4 +379,111 @@
         'not_found_in_trash' => "No {$plural} found in Trash.",
      ];
   }
   public function addTaxonomyRewrite(string $taxonomy):void
   {
      $exists = Registrar::getInstance($taxonomy);
      if (!$exists) return;
      $this->taxonomyRewrite = $taxonomy;
      if (!isset($this->rewrite)) {
         $this->rewrite = [];
      }
      if (array_key_exists('slug', $this->rewrite)) {
         if (str_contains($this->rewrite['slug'], '%')) {
            return;
         }
         $this->rewrite['slug'] = $this->rewrite['slug'].'/%'.$taxonomy.'%';
      } else {
         $this->rewrite['slug'] = $this->unbased.'/%'.$taxonomy.'%';
      }
      $this->addTaxonomyRewriteRules();
      add_action('post_type_link', [$this, 'rewriteTaxonomySingle'], 15, 2);
      add_action('post_type_archive_link', [$this, 'rewriteTaxonomyArchive'], 15, 2);
   }
   public function addTaxonomyRewriteRules(): void
   {
      if (!$this->taxonomyRewrite) return;
      $tax = jvbCheckBase($this->taxonomyRewrite);
      // Rule 1: Post type archive - /faq/
      add_rewrite_rule(
         "{$this->unbased}/?$",
         "index.php?post_type={$this->postType}",
         'top'
      );
      // Rule 2: Single posts with taxonomy - /faq/section/post/
      add_rewrite_rule(
         "{$this->unbased}/([^/]+)/([^/]+)/?$",
         "index.php?post_type={$this->postType}&name=\$matches[2]&{$tax}=\$matches[1]",
         'top'
      );
      // Rule 3: Un-sectioned posts - /faq/post/
      // Use 'bottom' priority so taxonomy rules match first
      add_rewrite_rule(
         "{$this->unbased}/([^/]+)/?$",
         "index.php?post_type={$this->postType}&name=\$matches[1]",
         'bottom'
      );
   }
   /**
    * Set $this->rewrite_taxonomy to a valid taxonomy
    * @param string $url
    * @param \WP_Post $post
    * @return string
    */
   public function rewriteTaxonomySingle(string $url, \WP_Post $post): string
   {
      if ($post->post_type === $this->postType && !is_null($this->taxonomyRewrite)) {
         $type = $this->taxonomyRewrite;
         $taxonomy = jvbCheckBase($type);
         $terms = wp_get_post_terms($post->ID, $taxonomy);
         if (!empty($terms) && !is_wp_error($terms)) {
            $path = TaxonomySelector::getTermPath($terms[0], true);
            $path = implode('/', array_map(function($term) {
               return sanitize_title($term);
            }, $path));
            return str_replace("%{$type}%", $path, $url);
         }
         return str_replace("/%{$type}%", '', $url);
      }
      return $url;
   }
   /**
    * Set $this->rewrite_taxonomy to a valid taxonomy
    * @param string $url
    * @param string $post_type
    * @return string
    */
   public function rewriteTaxonomyArchive(string $url, string $post_type):string
   {
      if ($post_type === $this->postType && !is_null($this->taxonomyRewrite)) {
         $url = get_home_url(null, "/{$this->postType}/");
      }
      return $url;
   }
   public function modifyWooCommerce() {
      if ($this->modify) {
         $args = $this->buildArgs();
         unset($args['labels']);;
         $registered = get_post_type_object($this->postType);
         foreach ($args as $key => $value) {
            $registered->$key = $value;
         }
         $labels = $registered->labels;
         foreach ($this->labels as $key => $value) {
            $labels->$key = $value;
         }
      }
   }
}