Jake Vanderwerf
2026-05-01 48721c85ebcfa973ee81719d2467ca80e4253dc9
inc/managers/RoleManager.php
@@ -13,6 +13,7 @@
{
    private array $roles;
   private array $content;
   private array $subTypes = [];
    public function __construct()
    {
@@ -26,6 +27,21 @@
         Registrar::getFeatured('is_content', 'term')
      ));
      add_action('set_user_role', [$this, 'updateRoles'], 10, 3);
      $this->checkRoleSubTypes();
    }
   public function checkRoleSubTypes():void
   {
      foreach ($this->roles as $role) {
         $registrar = Registrar::getInstance($role);
         if ($registrar->getUserSubtype()){
            $this->subTypes[jvbCheckBase($registrar->getUserSubtype())] = $registrar->getCreatable();
         }
      }
      if (!empty($this->subTypes)) {
         add_action('set_object_terms', [$this, 'maybeSwitchPermissions'],10, 6);
      }
    }
   public function updateRoles(int $userID, string $role, array $oldRoles):void
@@ -93,7 +109,6 @@
      $roles = array_keys($user->roles);
      foreach ($roles as $role) {
         $role = jvbNoBase($role);
         $registrar = Registrar::getInstance($role);
         if (!$registrar) {
            return false;
@@ -217,7 +232,7 @@
        if (!in_array($type, $this->roles)) {
            return false;
        }
        $link = get_user_meta($user->ID, BASE.'link', true);
        $link = get_user_meta($user->ID, BASE.'profile_link', true);
        if ($link === '') {
            $type = BASE.$type;
            $name = $user->display_name;
@@ -230,8 +245,8 @@
                'post_author'   => $user->ID,
            ]);
         if ($link) {
            update_user_meta($user->ID, BASE.'link', $link);
            update_post_meta($link, BASE.'link', $user->ID);
            update_user_meta($user->ID, BASE.'profile_link', $link);
            update_post_meta($link, BASE.'profile_link', $user->ID);
         }
        }
        return $link;
@@ -259,8 +274,8 @@
      if ($registrar->hasFeature('has_dashboard') ?? false) {
         $admin_role = get_role('administrator');
         if ($admin_role) {
            $admin_role->add_cap("manage_{$role_name}s", true);
            $admin_role->add_cap("edit_{$role_name}_settings", true);
            $admin_role->add_cap("manage_{$role_name}s");
            $admin_role->add_cap("edit_{$role_name}_settings");
         }
      }
   }
@@ -392,12 +407,15 @@
      return [
         "edit_{$content}",
         "edit_published_{$content}",
         "read_{$content}",
         "delete_{$content}",
         "delete_published_{$content}",
         "edit_{$plural}",
         "edit_others_{$plural}",
         "publish_{$plural}",
         "read_private_{$plural}",
         "edit_private_{$plural}",
         "delete_private_{$plural}",
      ];
   }
   protected function getOthersCapabilities(string $content):array
@@ -410,9 +428,6 @@
      return [
         "edit_others_{$plural}",
         "delete_others_{$plural}",
         "read_private_{$plural}",
         "edit_private_{$plural}",
         "delete_private_{$plural}",
      ];
   }
@@ -431,10 +446,58 @@
      return str_replace(' ', '_', $content.'s');
   }
   public function activate(): void
   public static function activate(): void
   {
      error_log('[RoleManager]::activate');
      error_log('Registering roles...');
      $instance = new self;
      foreach (Registrar::getRegistered('user') as $role) {
         $this->registerRole($role);
         $instance->registerRole($role);
      }
      error_log('Roles registered!');
      error_log('Removing unneeded roles...');
      remove_role('contributor');
      remove_role('author');
      remove_role('editor');
      error_log('Roles removed!');
      error_log('Adding Admin Capabilities');
      $instance->addAdminCaps();
      error_log('Ensuring Existing User\'s Roles...');
      $instance->ensureRoleCaps();
      error_log('Roles activated!');
   }
      protected function addAdminCaps():void
      {
         $users = get_users(['role' => 'administrator']);
         foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) {
            $this->grantRoleCapabilities('administrator', $slug);
            $this->grantRoleOthersCapabilities('administrator', $slug);
            foreach ($users as $user) {
               $this->grantContent($user, $slug);
               $this->grantOthersContent($user, $slug);
            }
         }
      }
      protected function ensureRoleCaps():void
      {
         $roles = Registrar::getRegistered('user');
         foreach ($roles as $role) {
            $registrar = Registrar::getInstance($role);
            $creatable = $registrar->getCreatable();
            $manageable = $registrar->getManageOthers();
            if (!empty($creatable) || !empty($manageable)) {
               $users = get_users(['role' => jvbCheckBase($role)]);
               foreach ($users as $user) {
                  foreach ($creatable as $slug) {
                     $this->grantContent($user, $slug);
                  }
                  foreach ($manageable as $slug) {
                     $this->grantOthersContent($user, $slug);
                  }
               }
            }
      }
   }
@@ -758,4 +821,91 @@
      }
      return null;
   }
   public function maybeSwitchPermissions(int $object_id, array $terms, array $tt_ids, string $taxonomy, bool $append, array $old_tt_ids):void
   {
      //This shouldn't happen, but whatever
      if (empty($this->subTypes)) {
         return;
      }
      if (!in_array($taxonomy, array_keys($this->subTypes))) {
         return;
      }
      $new = array_diff($tt_ids, $old_tt_ids);
      $old = array_diff($old_tt_ids, $tt_ids);
      $userID = (int)get_post_meta($object_id, BASE.'profile_link',true);
      if ($userID === 0) {
         return;
      }
      $user = get_userdata($userID);
      if (!$user) {
         return;
      }
      //Revoke old first
      if (!empty($old)) {
         $old = array_filter(array_map(function ($id) use ($taxonomy) {
            $termID = $this->getTermIDFromTTID($id);
            return $this->getRootTermSlug($termID, $taxonomy);
         }, $old));
         foreach ($old as $slug) {
            if (!array_key_exists($slug, $this->subTypes[$taxonomy])) {
               error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug);
               continue;
            }
            foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) {
               $this->grantContent($user, $s, false);
            }
         }
      }
      if (!empty($new)) {
         $new = array_filter(array_map(function ($id) use ($taxonomy){
            $termID = $this->getTermIDFromTTID($id);
            return $this->getRootTermSlug($termID, $taxonomy);
         }, $new));
         foreach ($new as $slug) {
            if (!array_key_exists($slug, $this->subTypes[$taxonomy])) {
               error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug);
               continue;
            }
            foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) {
               $this->grantContent($user, $s);
            }
         }
      }
   }
   /**
    * Helper function to get term_id from term_taxonomy_id
    * @param int $tt_id
    *
    * @return int
    */
   private function getTermIDFromTTID(int $tt_id):int
   {
      global $wpdb;
      return $wpdb->get_var($wpdb->prepare(
         "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = %d",
         $tt_id
      ));
   }
   private function getRootTermSlug(int $termID, string $taxonomy): string|false
   {
      $term = get_term($termID, $taxonomy);
      if (!$term || is_wp_error($term)) {
         return false;
      }
      while ($term->parent !== 0) {
         $term = get_term($term->parent, $taxonomy);
         if (!$term || is_wp_error($term)) {
            return false;
         }
      }
      return $term->slug;
   }
}