=Major overhaul of Integrations. Playing around with adding fields to post types through Registrar from an integrations' class file.
| | |
| | | $this->managers['notifications'] = new NotificationManager(); |
| | | $this->routes['notifications'] = new NotificationsRoutes(); |
| | | } |
| | | if (!empty(Registrar::getFeatured('approve_new'))) { |
| | | if (!empty(Registrar::withFeature('approve_new'))) { |
| | | $this->managers['approvals'] = new ApprovalManager(); |
| | | } |
| | | if (Site::has('feed_block') || Site::has('dashboard')) { |
| | |
| | | if ($membership && $membership->has('invitable')) { |
| | | $this->managers['invitations'] = new InvitationsManager(); |
| | | } |
| | | if (!empty(Registrar::getFeatured('has_responses'))) { |
| | | if (!empty(Registrar::withFeature('has_responses'))) { |
| | | $this->routes['comments'] = new ResponseRoutes(); |
| | | } |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | $this->routes['vote'] = new VoteRoutes(); |
| | | } |
| | | if (!empty(Registrar::getFeatured('karma')) |
| | | if (!empty(Registrar::withFeature('karma')) |
| | | || ($membership && $membership->has('member_verified')) || |
| | | ($membership && $membership->has('term_approval'))) { |
| | | $this->routes['approvals'] = new ApprovalRoutes(); |
| | |
| | | |
| | | $role = get_role('administrator'); |
| | | $users = get_users(['role' => 'administrator']); |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) { |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content')) as $slug) { |
| | | error_log('Adding administrative roles to '.$slug); |
| | | $plural = $roleManager->getContentPlural($slug); |
| | | $capabilities = [ |
| | |
| | | $roleManager = new RoleManager(); |
| | | $users = get_users(['role' => 'administrator']); |
| | | |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content', 'term')) as $slug) { |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content', 'term')) as $slug) { |
| | | |
| | | foreach ($users as $user) { |
| | | // These methods should check if post type exists before adding caps |
| | |
| | | this.authenticated = authData.authenticated || false; |
| | | this.user = authData.user || false; |
| | | this.nonces = authData.nonces || {}; |
| | | console.log(this.nonces); |
| | | |
| | | // Session expired — was logged in, now isn't |
| | | if (wasAuthenticated && !this.authenticated) { |
| | |
| | | storeName: 'favourites', |
| | | keyPath: 'id', |
| | | endpoint: 'favourites', |
| | | headers: { |
| | | 'X-Action-Nonce': window.auth.getNonce('favourites') |
| | | }, |
| | | indexes: [ |
| | | {name: 'content', keyPath: 'content'}, |
| | | {name: 'listId', keyPath: 'listId'}, |
| | |
| | | window.auth=new class{constructor(){this.initialized=!1,this.isAuthenticating=!1,this.authenticated=!1,this.user=!1,this.nonces={},this.subscribers=new Set,this.cacheExpiry=3e5,this.init()}async init(){if(!this.isAuthenticating){this.isAuthenticating=!0;try{if("undefined"!=typeof jvbAuth)return this.setAuthData(jvbAuth),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1});await this.fetchAuth()}catch(t){this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}}async refreshNonce(t="wp_rest"){try{return await this.fetchAuth(),this.getNonce(t)}catch(t){return console.error("Failed to refresh nonce:",t),null}}async fetch(t,i={}){const e=async(s=0)=>{const h={...!(i.body instanceof FormData)&&{"Content-Type":"application/json"},...i.headers,"X-WP-Nonce":this.getNonce()},n=await fetch(t,{...i,credentials:"same-origin",headers:h});if((403===n.status||401===n.status)&&0===s){const t=await n.clone().json();if("rest_cookie_invalid_nonce"===t.code||t.message?.includes("Cookie check"))return console.log("Nonce invalid, refreshing auth..."),await this.refresh(),e(s+1)}return n};return e()}async fetchAuth(){const t=await fetch(`${jvbSettings.api}auth/status`,{method:"GET",credentials:"same-origin",headers:{"Content-Type":"application/json"}});if(!t.ok)throw new Error("Auth check failed");const i=await t.json();this.setAuthData(i),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-loaded",{fromCache:!1})}setAuthData(t){const i=this.initialized&&this.authenticated;this.authenticated=t.authenticated||!1,this.user=t.user||!1,this.nonces=t.nonces||{},i&&!this.authenticated&&(window.location.href=`/login?redirect_to=${encodeURIComponent(window.location.href)}`)}clearAuthData(){this.authenticated=!1,this.user=null,this.nonces={}}async refresh(){this.isAuthenticating=!0,this.initialized=!1;try{await this.fetchAuth(),this.notify("auth-refreshed",{})}catch(t){console.error("Failed to refresh auth:",t),this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}getNonce(t="wp_rest"){return this.nonces[t]||""}getUser(){return this.user}isAuthenticated(){return this.authenticated}async handleLogin(t=null){if(t)return this.setAuthData(t),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1,fromLogin:!0});await this.refresh()}handleLogout(){this.clearAuthData(),this.notify("logged-out",{})}subscribe(t){return this.subscribers.add(t),this.initialized&&t("auth-loaded",{fromCache:!1,immediate:!0}),()=>this.subscribers.delete(t)}notify(t,i){this.subscribers.forEach((e=>{try{e(t,i)}catch(t){console.error("Subscriber error:",t)}}))}}; |
| | | window.auth=new class{constructor(){this.initialized=!1,this.isAuthenticating=!1,this.authenticated=!1,this.user=!1,this.nonces={},this.subscribers=new Set,this.cacheExpiry=3e5,this.init()}async init(){if(!this.isAuthenticating){this.isAuthenticating=!0;try{if("undefined"!=typeof jvbAuth)return this.setAuthData(jvbAuth),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1});await this.fetchAuth()}catch(t){this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}}async refreshNonce(t="wp_rest"){try{return await this.fetchAuth(),this.getNonce(t)}catch(t){return console.error("Failed to refresh nonce:",t),null}}async fetch(t,i={}){const e=async(s=0)=>{const n={...!(i.body instanceof FormData)&&{"Content-Type":"application/json"},...i.headers,"X-WP-Nonce":this.getNonce()},h=await fetch(t,{...i,credentials:"same-origin",headers:n});if((403===h.status||401===h.status)&&0===s){const t=await h.clone().json();if("rest_cookie_invalid_nonce"===t.code||t.message?.includes("Cookie check"))return console.log("Nonce invalid, refreshing auth..."),await this.refresh(),e(s+1)}return h};return e()}async fetchAuth(){const t=await fetch(`${jvbSettings.api}auth/status`,{method:"GET",credentials:"same-origin",headers:{"Content-Type":"application/json"}});if(!t.ok)throw new Error("Auth check failed");const i=await t.json();this.setAuthData(i),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-loaded",{fromCache:!1})}setAuthData(t){const i=this.initialized&&this.authenticated;this.authenticated=t.authenticated||!1,this.user=t.user||!1,this.nonces=t.nonces||{},console.log(this.nonces),i&&!this.authenticated&&(window.location.href=`/login?redirect_to=${encodeURIComponent(window.location.href)}`)}clearAuthData(){this.authenticated=!1,this.user=null,this.nonces={}}async refresh(){this.isAuthenticating=!0,this.initialized=!1;try{await this.fetchAuth(),this.notify("auth-refreshed",{})}catch(t){console.error("Failed to refresh auth:",t),this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}getNonce(t="wp_rest"){return this.nonces[t]||""}getUser(){return this.user}isAuthenticated(){return this.authenticated}async handleLogin(t=null){if(t)return this.setAuthData(t),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1,fromLogin:!0});await this.refresh()}handleLogout(){this.clearAuthData(),this.notify("logged-out",{})}subscribe(t){return this.subscribers.add(t),this.initialized&&t("auth-loaded",{fromCache:!1,immediate:!0}),()=>this.subscribers.delete(t)}notify(t,i){this.subscribers.forEach((e=>{try{e(t,i)}catch(t){console.error("Subscriber error:",t)}}))}}; |
| | |
| | | (()=>{class t{constructor(){let t=window.jvbStore.register("favourites",{storeName:"favourites",keyPath:"id",endpoint:"favourites",indexes:[{name:"content",keyPath:"content"},{name:"listId",keyPath:"listId"}],TTL:36e4,showLoading:!1,filters:{user:window.auth.getUser(),content:"all",order:"desc",orderby:"date",page:1,all:!0}});this.store=t.favourites,this.store.subscribe(((t,e)=>{t}))}toggleFavourite(t){if(!window.auth.getUser())return void(window.location.href=jvbSettings.redirect+"&action=register&type=favourites");t.classList.toggle("favourited");const e=t.classList.contains("favourited")?"add":"remove",o=t.classList.contains("favourited")?`Added ${t.dataset.type} to favourites.`:`Removed ${t.dataset.type} from favourites.`;window.jvbA11y.announce(o),t.innerHTML=jvbSettings.icons[t.classList.contains("favourited")?"heart-filled":"heart"],this.store.setItem(t.dataset.id,{target_id:t.dataset.id,action:e,type:t.dataset.type,artist:t.dataset.artist})}isFavourited(t,e){const o=`${this.userId}_${t}_${e}`;return void 0!==this.store.get(o)}}document.addEventListener("DOMContentLoaded",(function(){window.jvbFavourites=!1,window.auth.subscribe((e=>{"auth-loaded"===e&&(window.jvbFavourites=new t)}))})),window.toggleFavourite=function(t){window.jvbFavourites()?window.jvbFavourites.toggleFavourite(t):console.log("No Favourites Loaded")},window.isFavourited=function(t,e){if(window.jvbFavourites())return window.jvbFavourites.isFavourited(t,e);console.log("No Favourites Loaded")}})(); |
| | | (()=>{class t{constructor(){let t=window.jvbStore.register("favourites",{storeName:"favourites",keyPath:"id",endpoint:"favourites",headers:{"X-Action-Nonce":window.auth.getNonce("favourites")},indexes:[{name:"content",keyPath:"content"},{name:"listId",keyPath:"listId"}],TTL:36e4,showLoading:!1,filters:{user:window.auth.getUser(),content:"all",order:"desc",orderby:"date",page:1,all:!0}});this.store=t.favourites,this.store.subscribe(((t,e)=>{t}))}toggleFavourite(t){if(!window.auth.getUser())return void(window.location.href=jvbSettings.redirect+"&action=register&type=favourites");t.classList.toggle("favourited");const e=t.classList.contains("favourited")?"add":"remove",o=t.classList.contains("favourited")?`Added ${t.dataset.type} to favourites.`:`Removed ${t.dataset.type} from favourites.`;window.jvbA11y.announce(o),t.innerHTML=jvbSettings.icons[t.classList.contains("favourited")?"heart-filled":"heart"],this.store.setItem(t.dataset.id,{target_id:t.dataset.id,action:e,type:t.dataset.type,artist:t.dataset.artist})}isFavourited(t,e){const o=`${this.userId}_${t}_${e}`;return void 0!==this.store.get(o)}}document.addEventListener("DOMContentLoaded",(function(){window.jvbFavourites=!1,window.auth.subscribe((e=>{"auth-loaded"===e&&(window.jvbFavourites=new t)}))})),window.toggleFavourite=function(t){window.jvbFavourites()?window.jvbFavourites.toggleFavourite(t):console.log("No Favourites Loaded")},window.isFavourited=function(t,e){if(window.jvbFavourites())return window.jvbFavourites.isFavourited(t,e);console.log("No Favourites Loaded")}})(); |
| | |
| | | <?php |
| | | namespace JVBase\base; |
| | | |
| | | use JVBase\base\Login; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | | } |
| | |
| | | public static function getInstance():Site { |
| | | if (!isset(self::$instance)) { |
| | | self::$instance = new self(); |
| | | do_action('jvbLoadDefinitions'); |
| | | do_action('jvb_define_site'); |
| | | } |
| | | return self::$instance; |
| | | } |
| | |
| | | |
| | | function jvbUserTypes():array |
| | | { |
| | | return Registrar::getFeatured('profile_link', 'user'); |
| | | return Registrar::withFeature('profile_link', 'user'); |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | public function __construct() |
| | | { |
| | | if (empty(Registrar::getFeatured('is_content', 'term'))){ |
| | | if (empty(Registrar::withFeature('is_content', 'term'))){ |
| | | return; |
| | | } |
| | | add_filter(BASE.'handle_bulk_operation', [ $this, 'processOperation' ], 10, 3); |
| | |
| | | </thead> |
| | | <tbody> |
| | | <?php |
| | | $taxonomies = Registrar::getFeatured('is_content', 'term'); |
| | | $taxonomies = Registrar::withFeature('is_content', 'term'); |
| | | foreach ($taxonomies as $slug): |
| | | $registrar = Registrar::getInstance($slug); |
| | | $taxonomy = BASE . $slug; |
| | |
| | | add_action('init', 'jvb_maybe_setup_content_taxonomy', 1); |
| | | function jvb_maybe_setup_content_taxonomy(): void |
| | | { |
| | | if (!empty(Registrar::getFeatured('is_content', 'term'))) { |
| | | if (!empty(Registrar::withFeature('is_content', 'term'))) { |
| | | require(JVB_DIR . '/inc/admin/ContentTaxonomy.php'); |
| | | } |
| | | } |
| | |
| | | ); |
| | | |
| | | |
| | | $faq = array_values(Registrar::getFeatured('is_faq','post')); |
| | | $faq = array_values(Registrar::withFeature('is_faq','post')); |
| | | $registrar = Registrar::getInstance($faq[0]); |
| | | $this->section = array_map('jvbCheckBase', $registrar->registrar->taxonomies)[0]; |
| | | $this->postType = $registrar->getBased(); |
| | |
| | | require(JVB_DIR . '/build/summary/render.php'); |
| | | require(JVB_DIR . '/build/forms/render.php'); |
| | | require(JVB_DIR . '/build/menu/render.php'); |
| | | if (!empty(Registrar::getFeatured('is_glossary'))) { |
| | | if (!empty(Registrar::withFeature('is_glossary'))) { |
| | | error_log('Has Glossary Type'); |
| | | require(JVB_DIR . '/build/glossary/render.php'); |
| | | } |
| | |
| | | // ] |
| | | // ); |
| | | // } |
| | | if (!empty(Registrar::getFeatured('show_directory'))) { |
| | | if (!empty(Registrar::withFeature('show_directory'))) { |
| | | register_block_type( |
| | | JVB_DIR . '/build/list', |
| | | [ |
| | |
| | | new JVBase\blocks\MenuBlock(); |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('is_faq'))) { |
| | | if (!empty(Registrar::withFeature('is_faq'))) { |
| | | require('FAQBlock.php'); |
| | | new JVBase\blocks\FAQBlock(); |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('is_glossary'))) { |
| | | if (!empty(Registrar::withFeature('is_glossary'))) { |
| | | require('GlossaryBlock.php'); |
| | | new JVBase\blocks\GlossaryBlock(); |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('is_timeline'))) { |
| | | if (!empty(Registrar::withFeature('is_timeline'))) { |
| | | require('TimelineBlock.php'); |
| | | new JVBase\blocks\TimelineBlock(); |
| | | } |
| | |
| | | // ] |
| | | // ); |
| | | // } |
| | | // if (!empty(Registrar::getFeatured('show_directory'))) { |
| | | // if (!empty(Registrar::withFeature('show_directory'))) { |
| | | // error_log('Registering Directory List Block'); |
| | | // register_block_type( |
| | | // JVB_DIR . '/build/list', |
| | |
| | | array_map(function ($role) { |
| | | return BASE.$role; |
| | | }, |
| | | Registrar::getFeatured('has_dashboard', 'user')) |
| | | Registrar::withFeature('has_dashboard', 'user')) |
| | | ) |
| | | )>0; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | $types = Registrar::getFeatured('show_feed'); |
| | | $types = Registrar::withFeature('show_feed'); |
| | | $types = array_filter($temp, function ($type) use ($types) { |
| | | return in_array($type, $types); |
| | | }); |
| | |
| | | class Facebook extends Integrations |
| | | { |
| | | // Facebook-specific properties |
| | | protected array $allowedContent = [ |
| | | 'post', |
| | | 'photo', |
| | | 'video', |
| | | 'event', |
| | | 'offer', |
| | | 'note', |
| | | 'milestone' |
| | | ]; |
| | | private string $page_id = ''; |
| | | private string $page_access_token = ''; |
| | | private array $permissions = []; |
| | |
| | | return true; |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('is_content', 'term')) && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) { |
| | | if (!empty(Registrar::withFeature('is_content', 'term')) && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) { |
| | | return true; |
| | | } |
| | | |
| | |
| | | |
| | | class GoogleMyBusiness extends Integrations |
| | | { |
| | | protected array $allowedContent = [ |
| | | 'menu_item', |
| | | 'post', |
| | | 'event', |
| | | ]; |
| | | private ?string $access_token = null; |
| | | protected string $readMask = 'name,title,storefrontAddress,metadata,openInfo,storeCode,categories,phoneNumbers,labels,specialHours'; |
| | | private ?string $location = null; |
| | |
| | | |
| | | class Instagram extends Integrations |
| | | { |
| | | protected array $allowedContent = [ |
| | | 'post' |
| | | ]; |
| | | private string $ig_user_id = ''; |
| | | private string $page_id = ''; |
| | | private string $page_access_token = ''; |
| | |
| | | abstract class Integrations |
| | | { |
| | | /** |
| | | * Queue types |
| | | * These types match with IntegrationExecutor |
| | | */ |
| | | protected static string $syncTo = 'sync_to'; |
| | | protected static string $deleteFrom = 'delete_from'; |
| | | protected static string $syncFrom = 'sync_from'; |
| | | protected static string $syncCustomer = 'sync_customer'; |
| | | protected static string $import = 'import'; |
| | | /** |
| | | * API Configuration |
| | | * These properties define how the integration connects to external services |
| | | */ |
| | |
| | | if (!$taxonomies) { |
| | | // Combine both content and taxonomy filtering |
| | | $taxonomies = []; |
| | | foreach (Registrar::getFeatured('is_content', 'term') as $type) { |
| | | foreach (Registrar::withFeature('is_content', 'term') as $type) { |
| | | $registrar = Registrar::getInstance($type); |
| | | if ($registrar->hasIntegration($this->service_name)) { |
| | | $taxonomies[] = $registrar->getSlug(); |
| | |
| | | */ |
| | | class Square extends Integrations |
| | | { |
| | | protected array $allowedContent = [ |
| | | 'REGULAR', |
| | | 'FOOD_AND_BEV', |
| | | 'APPOINTMENTS_SERVICE', |
| | | 'DIGITAL', |
| | | 'EVENT', |
| | | 'DONATION' |
| | | ]; |
| | | /** |
| | | * Square API Configuration |
| | | */ |
| | |
| | | * OAuth Configuration |
| | | */ |
| | | protected bool $isOAuthService = true; |
| | | |
| | | protected string $orderPostType = '_sq_order'; |
| | | protected array $newOrder = []; |
| | | protected array $oauth = [ |
| | | 'authorize' => '', |
| | | 'token' => '', |
| | |
| | | |
| | | $this->refresh_interval = 7 * DAY_IN_SECONDS; |
| | | |
| | | $this->newOrder = [ |
| | | 'post_type' => $this->orderPostType, |
| | | 'post_status' => 'PROPOSED', |
| | | ]; |
| | | |
| | | // Define credential fields |
| | | $this->fields = [ |
| | | 'environment' => [ |
| | |
| | | 'sync_to_square' => 'Sync Site to Square', |
| | | ] |
| | | ); |
| | | |
| | | add_action('init', [$this, 'registerSquarePostTypes']); |
| | | add_action('init', [$this, 'registerSquarePostTypes'], 5); |
| | | } |
| | | |
| | | /** |
| | |
| | | 'square_order_id' => [ |
| | | 'type' => 'text', |
| | | 'label' => 'Square Order ID', |
| | | 'readonly' => true |
| | | ], |
| | | 'square_payment_id' => [ |
| | | 'type' => 'text', |
| | | 'label' => 'Square Payment ID', |
| | | 'readonly' => true |
| | | ], |
| | | 'square_customer_id' => [ |
| | | 'type' => 'text', |
| | | 'label' => 'Square Customer ID', |
| | | 'readonly' => true |
| | | ], |
| | | 'amount' => [ |
| | | 'type' => 'number', |
| | | 'label' => 'Total Amount (cents)', |
| | | 'readonly' => true |
| | | ], |
| | | 'status' => [ |
| | | 'post_status' => [ |
| | | 'type' => 'select', |
| | | 'label' => 'Order Status', |
| | | 'options' => [ |
| | |
| | | 'COMPLETED' => 'Completed', |
| | | 'CANCELED' => 'Canceled' |
| | | ], |
| | | 'readonly' => true |
| | | ], |
| | | 'fulfillment_status' => [ |
| | | 'type' => 'select', |
| | |
| | | 'CANCELED' => 'Canceled', |
| | | 'FAILED' => 'Failed' |
| | | ], |
| | | 'readonly' => true |
| | | ], |
| | | 'pickup_time' => [ |
| | | 'type' => 'datetime', |
| | |
| | | 'customer_email' => [ |
| | | 'type' => 'email', |
| | | 'label' => 'Customer Email', |
| | | 'readonly' => true |
| | | ], |
| | | 'customer_name' => [ |
| | | 'type' => 'text', |
| | | 'label' => 'Customer Name', |
| | | 'readonly' => true |
| | | ], |
| | | 'customer_phone' => [ |
| | | 'type' => 'tel', |
| | | 'type' => 'phone', |
| | | 'label' => 'Customer Phone', |
| | | 'readonly' => true |
| | | ], |
| | | 'special_instructions' => [ |
| | | 'type' => 'textarea', |
| | | 'label' => 'Special Instructions', |
| | | 'readonly' => true |
| | | ], |
| | | 'items' => [ |
| | | 'type' => 'repeater', |
| | | 'label' => 'Order Items', |
| | | 'readonly' => true, |
| | | 'fields' => [ |
| | | 'name' => ['type' => 'text', 'label' => 'Item Name'], |
| | | 'quantity' => ['type' => 'number', 'label' => 'Quantity'], |
| | |
| | | 'receipt_url' => [ |
| | | 'type' => 'url', |
| | | 'label' => 'Receipt URL', |
| | | 'readonly' => true |
| | | ], |
| | | 'created_at' => [ |
| | | 'type' => 'datetime', |
| | | 'label' => 'Created At', |
| | | 'readonly' => true |
| | | ], |
| | | 'updated_at' => [ |
| | | 'type' => 'datetime', |
| | | 'label' => 'Last Updated', |
| | | 'readonly' => true |
| | | ] |
| | | ]; |
| | | } |
| | |
| | | { |
| | | $orders = Registrar::forPost('_sq_orders', 'Square Order', 'Square Orders'); |
| | | $orders->make([ |
| | | 'public' => false |
| | | ] |
| | | ); |
| | | 'public' => true |
| | | ]); |
| | | $orders->setAll(['system']); |
| | | |
| | | $fields = $orders->fields(); |
| | | foreach ($this->getOrderFields() as $fieldName => $config) { |
| | | $fields->addField($fieldName, $config); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | add_action('wp_login', [$this, 'trackUserLogin'], 10, 2); |
| | | add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']); |
| | | |
| | | // Shared checkout UI (replaces outputCheckout) |
| | | add_filter('jvbAdditionalActions', [Checkout::class, 'render']); |
| | | |
| | | // Square-specific checkout description |
| | | |
| | | add_filter('jvb_checkout_description', function (string $desc, string $provider) { |
| | | if ($provider === 'square') { |
| | | return 'Securely checkout with your name, email, and payments processed by Square.'; |
| | |
| | | $queue = JVB()->queue(); |
| | | $executor = new IntegrationExecutor(); |
| | | |
| | | $queue->registry()->register('square_sync_to', new TypeConfig( |
| | | $queue->registry()->register(self::$syncTo, new TypeConfig( |
| | | executor: $executor, |
| | | chunkKey: 'items', |
| | | chunkSize: 50, |
| | | maxRetries: 3 |
| | | )); |
| | | |
| | | $queue->registry()->register('square_delete_from', new TypeConfig( |
| | | $queue->registry()->register(self::$deleteFrom, new TypeConfig( |
| | | executor: $executor, |
| | | chunkKey: 'external_ids', |
| | | chunkSize: 200, |
| | | maxRetries: 2 |
| | | )); |
| | | |
| | | $queue->registry()->register('square_sync_from', new TypeConfig( |
| | | $queue->registry()->register(self::$syncFrom, new TypeConfig( |
| | | executor: $executor, |
| | | maxRetries: 3 |
| | | )); |
| | | |
| | | $queue->registry()->register('square_sync_customer', new TypeConfig( |
| | | $queue->registry()->register(self::$syncCustomer, new TypeConfig( |
| | | executor: $executor, |
| | | maxRetries: 2 |
| | | )); |
| | | |
| | | $queue->registry()->register('square_import', new TypeConfig( |
| | | $queue->registry()->register(self::$import, new TypeConfig( |
| | | executor: $executor, |
| | | maxRetries: 3 |
| | | )); |
| | |
| | | */ |
| | | protected function handleTheSavePost(int $postID, \WP_Post $post, bool $update, array $settings): void |
| | | { |
| | | $this->queueOperation('sync_to', [ |
| | | $this->queueOperation(self::$syncTo, [ |
| | | 'items' => [$postID], |
| | | 'user_id' => $this->userID, |
| | | ], [ |
| | |
| | | $square_id = get_post_meta($postID, BASE . '_square_catalog_id', true); |
| | | |
| | | if ($square_id) { |
| | | $this->queueOperation('delete_from', [ |
| | | $this->queueOperation(self::$deleteFrom, [ |
| | | 'external_ids' => [$square_id], |
| | | 'post_id' => $postID, |
| | | ], [ |
| | |
| | | } |
| | | |
| | | /** |
| | | * @deprecated IntegrationExecutor handles new operations via registerQueueTypes(). |
| | | * Kept for legacy-typed operations ('square_sync_to_square') already queued. |
| | | * Safe to remove once all legacy operations have been processed. |
| | | */ |
| | | public function processOperation(WP_Error|array $result, object $operation, array $data): WP_Error|array |
| | | { |
| | | $base = strtolower($this->service_name) . '_'; |
| | | $square = array_key_exists('user', $data) ? new self((int) $data['user']) : $this; |
| | | |
| | | return match ($operation->type) { |
| | | $base . 'sync_to_square' => $square->processSyncToSquare($data), |
| | | $base . 'delete_from_square' => $square->processDeleteFromSquare($data), |
| | | $base . 'sync_from_square' => $square->processSyncFromSquare($data), |
| | | $base . 'sync_customer' => $square->processSyncCustomer($data), |
| | | default => $result, |
| | | }; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Process sync to Square |
| | | */ |
| | | private function processSyncToSquare(array $data): array |
| | |
| | | return []; |
| | | } |
| | | $array = $this->setBaseFields(); |
| | | return array_combine( |
| | | $return = array_combine( |
| | | array_map(fn($k) => 'sq_' . $k, array_keys($array)), |
| | | $array |
| | | ); |
| | | |
| | | return $return; |
| | | } |
| | | protected function setBaseFields():array |
| | | { |
| | | return [ |
| | | 'price' => [ |
| | | 'type' => 'number', |
| | | 'bulkEdit' => true, |
| | | 'label' => 'Price', |
| | | 'step' => 0.01, |
| | | 'max' => 99999, |
| | |
| | | |
| | | protected function defineTables():void |
| | | { |
| | | $types = Registrar::getFeatured('approve_new'); |
| | | $types = Registrar::withFeature('approve_new'); |
| | | foreach ($types as $type) { |
| | | $requests = CustomTable::for("approval_{$type}_requests"); |
| | | $registrar = Registrar::getInstance($type); |
| | |
| | | // Fields and sections |
| | | $this->skeleton->setFields($this->registrar->getFields()); |
| | | |
| | | foreach ($this->registrar->getSections() as $config) { |
| | | jvbDump($this->registrar->getSections()); |
| | | $sections = $this->registrar->getSections(); |
| | | if (count($sections) > 1) { |
| | | foreach ($sections as $config) { |
| | | jvbDump($config); |
| | | $this->skeleton->addSection($config['id'], $config); |
| | | } |
| | | } |
| | | |
| | | // Taxonomies |
| | | $this->initTaxonomies(); |
| | |
| | | } |
| | | |
| | | } |
| | | return $icon; |
| | | return match($icon) { |
| | | 'favourites' => 'heart', |
| | | default => $icon |
| | | }; |
| | | }); |
| | | } |
| | | protected function getSlug(string $slug, string $page):string |
| | |
| | | //content types |
| | | $all = array_merge( |
| | | Registrar::getRegistered('post'), |
| | | Registrar::getFeatured('is_content', 'term') |
| | | Registrar::withFeature('is_content', 'term') |
| | | ); |
| | | $availableContent = array_filter($pages, function($page, $key) use($all) { |
| | | return !is_numeric($key) && in_array($key, $all) && JVB()->roles()->checkRole($this->user, $key); |
| | |
| | | <?php |
| | | $i=1; |
| | | $content = Registrar::getRegistered('post'); |
| | | $contentTax = Registrar::getFeatured('is_content', 'term'); |
| | | $contentTax = Registrar::withFeature('is_content', 'term'); |
| | | $taxonomies = Registrar::getRegistered('term'); |
| | | foreach($contentTax as $index => $tax) { |
| | | unset($taxonomies[$index]); |
| | |
| | | $pages[] = 'Favourites'; |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | $pages[] = 'Karmic Score'; |
| | | } |
| | | |
| | |
| | | foreach ($roles as $role) { |
| | | $contents = Registrar::getInstance($role)?->getCreatable(); |
| | | if (!empty($contents)) { |
| | | $hasKarma = Registrar::getFeatured('karma'); |
| | | $hasKarma = Registrar::withFeature('karma'); |
| | | $remove = empty(array_intersect($contents, $hasKarma)); |
| | | } |
| | | } |
| | |
| | | */ |
| | | protected function getRolesWithDashboard():array |
| | | { |
| | | return Registrar::getFeatured('has_dashboard', 'user'); |
| | | return Registrar::withFeature('has_dashboard', 'user'); |
| | | } |
| | | |
| | | /** |
| | |
| | | $directories = []; |
| | | //content |
| | | |
| | | $content = Registrar::getFeatured('show_directory', 'post'); |
| | | $content = Registrar::withFeature('show_directory', 'post'); |
| | | if(!empty($content)) { |
| | | foreach ($content as $key) { |
| | | $directories[$key] = 'content'; |
| | | } |
| | | } |
| | | |
| | | $taxonomies = Registrar::getFeatured('show_directory', 'term'); |
| | | $taxonomies = Registrar::withFeature('show_directory', 'term'); |
| | | if(!empty($taxonomies)) { |
| | | foreach ($taxonomies as $key) { |
| | | $directories[$key] = 'taxonomy'; |
| | | } |
| | | } |
| | | |
| | | $users = Registrar::getFeatured('show_directory', 'user'); |
| | | $users = Registrar::withFeature('show_directory', 'user'); |
| | | if(!empty($users)) { |
| | | foreach ($users as $key) { |
| | | $directories[$key] = 'user'; |
| | |
| | | |
| | | public function defineTable():void |
| | | { |
| | | $terms = Registrar::getFeatured('invitable', 'term'); |
| | | $terms = Registrar::withFeature('invitable', 'term'); |
| | | $membership = Site::membership(); |
| | | $roles = ($membership) ? Site::membership()->has('can_invite') :[]; |
| | | if (empty($terms) && empty($roles)) { |
| | |
| | | } |
| | | |
| | | // Term invitations from invitable content taxonomies |
| | | $invitable = Registrar::getFeatured('invitable', 'term'); |
| | | $content = Registrar::getFeatured('is_content', 'term'); |
| | | $ownable = Registrar::getFeatured('is_ownable', 'term'); |
| | | $invitable = Registrar::withFeature('invitable', 'term'); |
| | | $content = Registrar::withFeature('is_content', 'term'); |
| | | $ownable = Registrar::withFeature('is_ownable', 'term'); |
| | | $taxonomies = array_intersect($invitable, $content, $ownable); |
| | | if (!empty($taxonomies)) { |
| | | $users = Registrar::getRegistered('user'); |
| | |
| | | 'hint' => 'Have a referral code? Paste it here!' |
| | | ]; |
| | | } |
| | | $canRegister = Registrar::getFeatured('can_register', 'user'); |
| | | $canRegister = Registrar::withFeature('can_register', 'user'); |
| | | if (!empty($canRegister)) { |
| | | foreach ($canRegister as $role) { |
| | | $registrar = Registrar::getInstance($role); |
| | |
| | | protected function customStyles():void |
| | | { |
| | | $logo = get_theme_mod('custom_logo'); |
| | | $small = $large = ''; |
| | | if ($logo) { |
| | | $small = wp_get_attachment_image_src($logo, 'medium')[0]??''; |
| | | $large = wp_get_attachment_image_src($logo, 'large')[0]??''; |
| | |
| | | protected function registerUserIndex():void |
| | | { |
| | | $table = CustomTable::for('user_notification_email_digest'); |
| | | // $types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::getFeatured('favouritable'))); |
| | | // $types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::withFeature('favouritable'))); |
| | | $table->setColumns([ |
| | | 'id' => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT', |
| | | 'user_id' => "{$table->getUserIDType()} NOT NULL", |
| | |
| | | protected function registerTermIndex():void |
| | | { |
| | | $table = CustomTable::for('user_notification_email_digest'); |
| | | $types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::getFeatured('favouritable', 'term'))); |
| | | $types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::withFeature('favouritable', 'term'))); |
| | | $table->setColumns([ |
| | | 'id' => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT', |
| | | 'term_id' => "{$table->getTermIDType()} NOT NULL", |
| | |
| | | $content = ''; |
| | | foreach ($subscription as $item) { |
| | | $temp = match ($item['item_type']) { |
| | | array_merge(['user'], Registrar::getFeatured('favouritable', 'user')) => $this->getUserUpdates($item['item_id'], $frequency), |
| | | Registrar::getFeatured('favouritable', 'term') => $this->getTermUpdates($item['item_id'], $item['item_type'], $frequency), |
| | | array_merge(['user'], Registrar::withFeature('favouritable', 'user')) => $this->getUserUpdates($item['item_id'], $frequency), |
| | | Registrar::withFeature('favouritable', 'term') => $this->getTermUpdates($item['item_id'], $item['item_type'], $frequency), |
| | | default => false, |
| | | }; |
| | | if ($temp) { |
| | |
| | | ] |
| | | ]); |
| | | } |
| | | $contentTax = Registrar::getFeatured('is_content', 'term'); |
| | | $verifyEntry = Registrar::getFeatured('verify_entry', 'term'); |
| | | $contentTax = Registrar::withFeature('is_content', 'term'); |
| | | $verifyEntry = Registrar::withFeature('verify_entry', 'term'); |
| | | if (!empty(array_intersect($contentTax, $verifyEntry))) { |
| | | $types = array_merge($types, [ |
| | | 'entry_requested' => [ |
| | |
| | | ] |
| | | ]); |
| | | } |
| | | $invitable = Registrar::getFeatured('invitable'); |
| | | $invitable = Registrar::withFeature('invitable'); |
| | | if (!empty($invitable)) { |
| | | $types = array_merge($types, [ |
| | | 'invitation_requested' => [ |
| | |
| | | ]); |
| | | } |
| | | |
| | | $approvals = Registrar::getFeatured('approve_new'); |
| | | $approvals = Registrar::withFeature('approve_new'); |
| | | if (!empty($approvals)) { |
| | | $tmp = ['user', 'term', 'post']; |
| | | $app = []; |
| | | foreach ($tmp as $t) { |
| | | $approvals = Registrar::getFeatured('approve_new', $t); |
| | | $approvals = Registrar::withFeature('approve_new', $t); |
| | | if (!empty($approvals)) { |
| | | $app = array_merge($app, [ |
| | | $t.'_new' => [ |
| | |
| | | return strtolower(str_replace(' ', '_', $registrar->getPlural()??$registrar->getSingular().'s')); |
| | | },array_merge( |
| | | Registrar::getRegistered('post'), |
| | | Registrar::getFeatured('is_content', 'term') |
| | | Registrar::withFeature('is_content', 'term') |
| | | )); |
| | | add_action('set_user_role', [$this, 'updateRoles'], 10, 3); |
| | | |
| | |
| | | protected function addAdminCaps():void |
| | | { |
| | | $users = get_users(['role' => 'administrator']); |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) { |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content')) as $slug) { |
| | | $this->grantRoleCapabilities('administrator', $slug); |
| | | $this->grantRoleOthersCapabilities('administrator', $slug); |
| | | |
| | |
| | | if ($ownable === null) { |
| | | $ownable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::getFeatured('is_ownable', 'term')); |
| | | }, Registrar::withFeature('is_ownable', 'term')); |
| | | } |
| | | |
| | | return $ownable; |
| | |
| | | if ($invitable === null) { |
| | | $invitable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::getFeatured('invitable', 'term')); |
| | | }, Registrar::withFeature('invitable', 'term')); |
| | | } |
| | | |
| | | return $invitable; |
| | |
| | | } |
| | | $isContent = array_values(array_filter(array_map(function($item) { |
| | | return intval(get_option(BASE.$item.'_archive', false)); |
| | | },Registrar::getFeatured('is_content', 'term')))); |
| | | },Registrar::withFeature('is_content', 'term')))); |
| | | |
| | | if (!empty($isContent) && is_page($isContent)){ |
| | | $type = get_post_meta(get_the_id(), BASE.'for_type', true); |
| | |
| | | namespace JVBase\managers\SEO\render\Thing\Product; |
| | | |
| | | |
| | | use JVBase\managers\SEO\render\Thing\Thing; |
| | | use JVBase\managers\SEO\render\Traits\_Properties\additionalPropertyTrait; |
| | | use JVBase\managers\SEO\render\Traits\_Properties\aggregateRatingTrait; |
| | | use JVBase\managers\SEO\render\Traits\_Properties\audienceTrait; |
| | |
| | | use JVBase\managers\SEO\render\Traits\_Properties\sloganTrait; |
| | | use JVBase\managers\SEO\render\Traits\_Properties\weightTrait; |
| | | use JVBase\managers\SEO\render\Traits\_Properties\widthTrait; |
| | | use JVBase\managers\SEO\render\Traits\ThingSchema; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | | } |
| | | |
| | | class Product { |
| | | use ThingSchema, |
| | | additionalPropertyTrait, aggregateRatingTrait, audienceTrait, |
| | | class Product extends Thing { |
| | | use additionalPropertyTrait, aggregateRatingTrait, audienceTrait, |
| | | awardTrait, brandTrait, categoryTrait, colorTrait, countryOfAssemblyTrait, |
| | | countryOfOriginTrait, depthTrait, displayLocationTrait, hasAdultConsiderationTrait, |
| | | hasCertificationTrait, hasMeasurementTrait, hasMerchantReturnPolicyTrait, |
| | |
| | | |
| | | protected function defineTables():void |
| | | { |
| | | $types = implode(',', array_map(function($item) { return "`{$item}`"; },Registrar::getFeatured('verify_entry'))); |
| | | $types = implode(',', array_map(function($item) { return "`{$item}`"; },Registrar::withFeature('verify_entry'))); |
| | | |
| | | $table = CustomTable::for('verify_entry'); |
| | | |
| | |
| | | require(JVB_DIR . '/inc/managers/UserTermsManager.php'); |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('approve_new'))) { |
| | | if (!empty(Registrar::withFeature('approve_new'))) { |
| | | require(JVB_DIR . '/inc/managers/ApprovalManager.php'); |
| | | } |
| | | |
| | |
| | | require(JVB_DIR . '/inc/managers/Notifications/Preferences.php'); |
| | | require(JVB_DIR . '/inc/managers/NotificationManager.php'); |
| | | } |
| | | if ($membership->has('forum') && !empty(Registrar::getFeatured('is_content', 'term'))) { |
| | | if ($membership->has('forum') && !empty(Registrar::withFeature('is_content', 'term'))) { |
| | | require(JVB_DIR . '/inc/managers/NewsRelationships.php'); |
| | | } |
| | | if ($membership->has('invitable')) { |
| | |
| | | require(JVB_DIR . '/inc/managers/ReferralManager.php'); |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | require(JVB_DIR . '/inc/managers/KarmaManager.php'); |
| | | } |
| | | // if (Site::has('favourites') && !empty(Registrar::getFeatured('favouritable'))) { |
| | | // if (Site::has('favourites') && !empty(Registrar::withFeature('favouritable'))) { |
| | | if (Site::has('favourites')) { |
| | | require(JVB_DIR . '/inc/managers/FavouritesManager.php'); |
| | | } |
| | |
| | | |
| | | class Fields { |
| | | protected array $fields; |
| | | protected Registrar $registrar; |
| | | private Registrar $registrar; |
| | | |
| | | public function __construct(?string $type = null, ?Registrar $registrar = null) { |
| | | $this->registrar = $registrar; |
| | |
| | | { |
| | | return $this->integrationConfigs; |
| | | } |
| | | public function hasIntegration(string $integration) { |
| | | public function hasIntegration(string $integration):bool |
| | | { |
| | | return array_key_exists($integration, $this->integrationConfigs); |
| | | } |
| | | public function hasAnyIntegrations(array $integrations = []):bool |
| | |
| | | } |
| | | return $this; |
| | | } |
| | | public function unsetAll(array $flags):self |
| | | { |
| | | $flags = array_filter($flags, function($flag) { |
| | | return in_array($flag, static::$allFlags); |
| | | }); |
| | | foreach ($flags as $flag) { |
| | | $this->$flag = false; |
| | | switch ($flag) { |
| | | case 'is_content': |
| | | remove_action('init', [$this, 'setupContent'], 20); |
| | | break; |
| | | case 'is_glossary': |
| | | $this->hide_single = false; |
| | | break; |
| | | } |
| | | } |
| | | return $this; |
| | | } |
| | | public function prefixWith(string $prefix):self |
| | | { |
| | | $this->prefix_with = sanitize_title($prefix); |
| | |
| | | protected function getBreadcrumbs():Breadcrumbs |
| | | { |
| | | if (!isset($this->breadcrumbs)) { |
| | | $this->breadcrumbs = new Breadcrumbs($this->slug, $this); |
| | | $this->breadcrumbs = new Breadcrumbs($this->slug); |
| | | } |
| | | |
| | | return $this->breadcrumbs; |
| | |
| | | protected function getDashboard():Dashboard |
| | | { |
| | | if (!isset($this->dashboard)) { |
| | | $this->dashboard = new Dashboard($this->plural, $this); |
| | | $this->dashboard = new Dashboard($this->plural); |
| | | } |
| | | |
| | | return $this->dashboard; |
| | |
| | | } |
| | | public function addSection(string $title):Section |
| | | { |
| | | $slug = sanitize_title($title); |
| | | if (!array_key_exists($slug, $this->sections)) { |
| | | $section = new Section($title, $this); |
| | | $this->sections[] = $section; |
| | | return $section; |
| | | $this->sections[$slug] = $section; |
| | | } |
| | | |
| | | return $this->sections[$slug]; |
| | | } |
| | | |
| | | public static function maybeBuildSections():void |
| | | { |
| | | foreach (self::$instances as $inst) { |
| | | $inst->buildSections(); |
| | | } |
| | | } |
| | | protected function buildSections():void |
| | | { |
| | | $fields = $this->getFields(); |
| | | $sections = array_unique(array_values(array_map(function ($f) { |
| | | return array_key_exists('section', $f) && !is_null($f['section']) ? $f['section'] : 'main'; |
| | | }, $fields))); |
| | | |
| | | foreach ($sections as $s) { |
| | | $section = new Section($s, $this); |
| | | $section->setTitle(ucwords(implode(' ', explode('-', $s)))); |
| | | $sectionFields = array_map(function ($f) { |
| | | return $f['name']; |
| | | }, array_filter($fields, function ($f) use ($s) { |
| | | $tmp = array_key_exists('section', $f) && !is_null($f['section']) ? $f['section'] : 'main'; |
| | | return $s === $tmp; |
| | | })); |
| | | $section->setFields($sectionFields); |
| | | $this->sections[$s] = $section; |
| | | } |
| | | } |
| | | |
| | | public function setSectionOrder(array $sections):self |
| | |
| | | $this->hideSingleHandler = new HideSingle($this->slug, $this); |
| | | } |
| | | if ($this->is_timeline) { |
| | | $this->isTimelineHandler = new MakeTimelineType($this->slug, $this); |
| | | $this->isTimelineHandler = new MakeTimelineType($this->slug); |
| | | $this->registrar->hierarchical = true; |
| | | } |
| | | if ($this->is_calendar) { |
| | |
| | | public static function ensureInstanced():void |
| | | { |
| | | if (empty(self::$instances)) { |
| | | do_action('jvbDefineRegistrar'); |
| | | do_action('jvbDefineRegistrarFields'); |
| | | do_action('jvb_define_registrar'); |
| | | do_action('jvb_define_fields'); |
| | | } |
| | | } |
| | | |
| | |
| | | $this->service_name = $service; |
| | | } |
| | | |
| | | |
| | | public function getService_name():string |
| | | { |
| | | return $this->service_name; |
| | |
| | | */ |
| | | public function setContentType(string $content):self |
| | | { |
| | | $allowed = JVB()->connect($this->service_name)->getAllowedContent(); |
| | | $connection = JVB()->connect($this->service_name); |
| | | if (!$connection){ |
| | | error_log('[Integration]::setContentType Service is not setup. '.$this->service_name); |
| | | return $this; |
| | | } |
| | | $allowed = $connection->getAllowedContent(); |
| | | if (!in_array($content, $allowed)) { |
| | | error_log($this->service_name.' Connection does not support this content: '.$content); |
| | | return $this; |
| | |
| | | protected string $description = ''; |
| | | protected string $icon = ''; |
| | | protected array $fields = []; |
| | | protected Registrar $registrar; |
| | | private Registrar $registrar; |
| | | |
| | | public function __construct(string $title, Registrar $registrar) { |
| | | $this->title = $title; |
| | | $this->slug = sanitize_title($title); |
| | | public function __construct(string $slug, Registrar $registrar) { |
| | | $this->slug = sanitize_title($slug); |
| | | $this->registrar = $registrar; |
| | | } |
| | | |
| | |
| | | } |
| | | public function getTitle():string |
| | | { |
| | | return $this->title; |
| | | return $this->title ?? ucwords(implode(' ', explode('-', $this->slug))); |
| | | } |
| | | |
| | | public function setDescription(string $description):self |
| | |
| | | $this->icon = $icon; |
| | | return $this; |
| | | } |
| | | public function getIcon():string |
| | | { |
| | | return $this->icon; |
| | | } |
| | | |
| | | protected function checkFields(string|array $fields):string|array |
| | | { |
| | |
| | | protected int $maxLength; // of characters |
| | | protected int $min; |
| | | protected int $max; |
| | | /** |
| | | * @var float $step For number fields. Indicates the amount the number increases/decreases with the plus/minus buttons |
| | | */ |
| | | protected float $step; |
| | | protected string $subtype; |
| | | protected array $condition; |
| | | protected array $allowedSubtype = ['text', 'url','number','tel','email','number']; |
| | |
| | | } |
| | | } |
| | | |
| | | public function getName():string |
| | | { |
| | | return $this->name; |
| | | } |
| | | |
| | | public function setDescription(string $description):void |
| | | { |
| | | $this->description = $description; |
| | |
| | | { |
| | | return $this->max??null; |
| | | } |
| | | public function setStep(float $step):void |
| | | { |
| | | $this->step = $step; |
| | | } |
| | | public function getStep():?float |
| | | { |
| | | return $this->step??null; |
| | | } |
| | | public function setMaxLength(int $maxLength):void |
| | | { |
| | | $this->maxLength = $maxLength; |
| | |
| | | |
| | | class AddIntegrationFields { |
| | | protected string $service_name; |
| | | protected Registrar $registrar; |
| | | private Registrar $registrar; |
| | | protected Integration $config; |
| | | protected array $allowed; |
| | | |
| | | public function __construct(string $service_name, ?Registrar $registrar = null) { |
| | | $this->initAllowed(); |
| | | if (!in_array($service_name, $this->allowed)) { |
| | | if (!array_key_exists($service_name, $this->allowed)) { |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | $this->config = $registrar->getIntegration($service_name); |
| | | |
| | | add_action('jvb_define_integrations', [$this, 'addIntegrationFields'],20); |
| | | } |
| | | protected function initAllowed():void |
| | | { |
| | |
| | | public function addIntegrationFields():void |
| | | { |
| | | $fields = $this->getIntegrationFields(); |
| | | // error_log('[AddIntegrationFields] adding fields for '.$this->service_name.': '.print_r($fields, true)); |
| | | foreach ($fields as $fieldName => $fieldConfig) { |
| | | $this->registrar->fields()->addField($fieldName, $fieldConfig); |
| | | } |
| | |
| | | class HideSingle { |
| | | protected string $slug; |
| | | protected string $postType; |
| | | protected Registrar $registrar; |
| | | public function __construct(string $slug, Registrar $registrar) { |
| | | $this->slug = $slug; |
| | | $this->postType = jvbCheckBase($slug); |
| | | $this->registrar = $registrar; |
| | | |
| | | if ($this->registrar->hasFeature('hide_single')) { |
| | | |
| | | if ($registrar->hasFeature('hide_single')) { |
| | | add_filter('is_post_type_viewable', [$this, 'hideFromPublic']); |
| | | if ($this->registrar->hasFeature('redirect_to_author')) { |
| | | if ($registrar->hasFeature('redirect_to_author')) { |
| | | add_filter('post_type_link', [$this, 'redirectSingleToAuthor'], 15, 2); |
| | | add_action('template_redirect', [$this, 'actuallyRedirectToAuthor']); |
| | | } else { |
| | |
| | | class MakeCalendarType { |
| | | protected string $slug; |
| | | protected string $postType; |
| | | protected Registrar $registrar; |
| | | private Registrar $registrar; |
| | | public function __construct(string $slug, Registrar $registrar) { |
| | | $this->slug = $slug; |
| | | $this->postType = jvbCheckBase($slug); |
| | |
| | | add_action('init', [$this, 'addCalendarRewrites']); |
| | | } |
| | | |
| | | |
| | | public function __debugInfo() { |
| | | $vars = get_object_vars($this); |
| | | unset($vars['registrar']); |
| | | return $vars; |
| | | } |
| | | |
| | | protected function addCalendarFields():void |
| | | { |
| | | |
| | |
| | | class MakeTimelineType { |
| | | protected string $slug; |
| | | protected string $postType; |
| | | protected Registrar $registrar; |
| | | public function __construct(string $slug, Registrar $registrar) { |
| | | public function __construct(string $slug) { |
| | | $this->slug = $slug; |
| | | $this->postType = jvbCheckBase($slug); |
| | | $this->registrar = $registrar; |
| | | |
| | | add_action('template_redirect', [$this, 'redirectChildToParent']); |
| | | } |
| | |
| | | |
| | | // Keep existing author filtering logic |
| | | $authorQuery = []; |
| | | foreach (Registrar::getFeatured('can_create', 'user') as $type) { |
| | | foreach (Registrar::withFeature('can_create', 'user') as $type) { |
| | | if (array_key_exists($type, $data)) { |
| | | $artist_ids = array_map( |
| | | 'absint', |
| | |
| | | return false; |
| | | } |
| | | $post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']]; |
| | | $hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::getFeatured('is_timeline', 'post')); |
| | | $hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::withFeature('is_timeline', 'post')); |
| | | return !empty(array_intersect($post_types, $hasTimeline)); |
| | | } |
| | | // ========================================================================= |
| | |
| | | |
| | | // Keep existing author filtering logic |
| | | $authorQuery = []; |
| | | foreach (Registrar::getFeatured('can_create', 'user') as $type) { |
| | | foreach (Registrar::withFeature('can_create', 'user') as $type) { |
| | | if (array_key_exists($type, $data)) { |
| | | $artist_ids = array_map( |
| | | 'absint', |
| | |
| | | protected function isTimeline($args, $data):bool |
| | | { |
| | | $post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']]; |
| | | $areTimeline = array_map(function($type) { return BASE.$type; },Registrar::getFeatured('is_timeline', 'post')); |
| | | $areTimeline = array_map(function($type) { return BASE.$type; },Registrar::withFeature('is_timeline', 'post')); |
| | | return !empty(array_intersect($post_types, $areTimeline)); |
| | | } |
| | | |
| | |
| | | //if (Site::has('referrals')) { |
| | | require(JVB_DIR . '/inc/rest/routes/ReferralRoutes.php'); |
| | | //} |
| | | //if (!empty(Registrar::getFeatured('has_responses'))) { |
| | | //if (!empty(Registrar::withFeature('has_responses'))) { |
| | | require(JVB_DIR . '/inc/rest/routes/ResponseRoutes.php'); |
| | | //} |
| | | |
| | | //if (!empty(Registrar::getFeatured('karma'))) { |
| | | //if (!empty(Registrar::withFeature('karma'))) { |
| | | require(JVB_DIR . '/inc/rest/routes/VoteRoutes.php'); |
| | | //} |
| | | |
| | |
| | | $this->termTypes = []; |
| | | $this->allTypes = []; |
| | | if ($this->hasMemberApproval) { |
| | | $this->userTypes = Registrar::getFeatured('approve_new', 'user'); |
| | | $this->userTypes = Registrar::withFeature('approve_new', 'user'); |
| | | $this->allTypes = $this->userTypes; |
| | | } |
| | | if (Site::has('term_approval')) { |
| | | $this->termTypes = Registrar::getFeatured('approve_new', 'term'); |
| | | $this->termTypes = Registrar::withFeature('approve_new', 'term'); |
| | | $this->allTypes[] = 'term'; |
| | | } |
| | | } |
| | |
| | | { |
| | | $registry = JVB()->queue()->registry(); |
| | | $executor = new ContentTermExecutor(); |
| | | $taxonomies = Registrar::getFeatured('is_content', 'term'); |
| | | $taxonomies = Registrar::withFeature('is_content', 'term'); |
| | | |
| | | foreach($taxonomies as $taxonomy) { |
| | | $registry->register("{$taxonomy}_update", new TypeConfig( |
| | |
| | | : explode(',', $args['post_type']); |
| | | |
| | | // Check if filtering global feed content |
| | | if (in_array(jvbNoBase($context['type']), Registrar::getFeatured('is_content', 'term'))) { |
| | | if (in_array(jvbNoBase($context['type']), Registrar::withFeature('is_content', 'term'))) { |
| | | // Global: show posts from any content type with this taxonomy |
| | | $for_content = Registrar::getInstance($context['type'])->registrar->for ?? []; |
| | | |
| | |
| | | $post_types = array_map(fn($type) => jvbCheckBase($type), $for_content); |
| | | |
| | | // Filter to only show_feed content types |
| | | $show_feed_types = Registrar::getFeatured('show_feed', 'post'); |
| | | $show_feed_types = Registrar::withFeature('show_feed', 'post'); |
| | | $args['post_type'] = array_intersect( |
| | | $post_types, |
| | | array_map(fn($type) => jvbCheckBase($type), $show_feed_types) |
| | |
| | | $config = []; |
| | | |
| | | // Get content types with show_feed |
| | | $contentTypes = Registrar::getFeatured('show_feed', 'post'); |
| | | $contentTypes = Registrar::withFeature('show_feed', 'post'); |
| | | foreach ($contentTypes as $slug) { |
| | | $this->cache->tag('content:'.$slug); |
| | | $registrar = Registrar::getInstance($slug); |
| | |
| | | } |
| | | |
| | | // Get taxonomies with show_feed (content taxonomies) |
| | | $taxonomies = Registrar::getFeatured('show_feed', 'term'); |
| | | $taxonomies = Registrar::withFeature('show_feed', 'term'); |
| | | foreach ($taxonomies as $slug) { |
| | | $registrar = Registrar::getInstance($slug); |
| | | if (!$registrar || !($registrar->hasFeature('is_content') ?? false)) { |
| | |
| | | */ |
| | | public function handleLogin(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | error_log('Handling login...'); |
| | | $email = sanitize_email($request->get_param('user_email')); |
| | | $password = $request->get_param('user_password'); |
| | | $remember = (bool) $request->get_param('remember_me'); |
| | | $redirect_to = $request->get_param('redirect_to'); |
| | | |
| | | // Verify Turnstile |
| | | |
| | | if (!$this->verifyTurnstile($request->get_param('cf-turnstile-response') ?? '')) { |
| | | error_log('[handleLogin]Turnstile failed'); |
| | | return $this->error( |
| | | 'Security verification failed. Please try again.', |
| | | 'turnstile_failed', |
| | | 403 |
| | | ); |
| | | } else { |
| | | error_log('[handleLogin]Turnstile succeeded'); |
| | | } |
| | | |
| | | // Attempt authentication |
| | |
| | | protected function buildAuth(?int $user = null): array |
| | | { |
| | | $userId = $user ?? (is_user_logged_in() ? get_current_user_id() : 0); |
| | | $cacheKey = $userId ?: 'guest'; |
| | | |
| | | return Cache::for('auth', 300)->remember($cacheKey, function() use ($userId) { |
| | | if ($userId) { |
| | | return [ |
| | | 'authenticated' => true, |
| | |
| | | 'nonces' => $this->getUserNonces($userId), |
| | | ]; |
| | | } |
| | | |
| | | return [ |
| | | 'authenticated' => false, |
| | | 'user' => false, |
| | | 'nonces' => ['wp_rest' => wp_create_nonce('wp_rest')], |
| | | ]; |
| | | }); |
| | | } |
| | | protected function getUserNonces(int $userID):array { |
| | | $nonces = [ |
| | |
| | | if (Site::has('favourites')) { |
| | | $nonces['favourites'] = wp_create_nonce('favourites-'.$userID); |
| | | } |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | $nonces['votes'] = wp_create_nonce('votes-'.$userID); |
| | | } |
| | | if (Site::has('notifications')) { |
| | |
| | | $statusCondition = $wpdb->prepare("a.status = %s", $status); |
| | | } |
| | | |
| | | $approvals = Registrar::getFeatured('approve_new'); |
| | | $approvals = Registrar::withFeature('approve_new'); |
| | | foreach ($approvals as $type => $config) { |
| | | $table = $wpdb->prefix . BASE . 'approval_' . $type . 'requests'; |
| | | $votes = $wpdb->prefix . BASE . 'approval_' . $type . 'votes'; |
| | |
| | | Plugin URI: https://jakevan.ca |
| | | Description: The Base Plugin for JakeVan clients |
| | | Author: Jake Vanderwerf |
| | | Version: 1.0.0 |
| | | Version: 1.1.0 |
| | | Author URI: https://jakevan.ca/ |
| | | Textdomain: jvb |
| | | */ |
| | |
| | | }, 10, 3); |
| | | |
| | | |
| | | |
| | | function jvbIgnoredPostTypes():array |
| | | { |
| | | return [BASE.'directory', BASE.'dash', 'attachment', 'revision', 'nav_menu_item']; |
| | |
| | | require(JVB_DIR . '/inc/admin/_setup.php'); |
| | | |
| | | require(JVB_DIR . '/JVBase.php'); |
| | | |
| | | /** |
| | | * After moving to the Registrar::based registration, we need to carefully time |
| | | * when Site gets defined, as well as Registrar initial definitions, field definitions, |
| | | * and integration config |
| | | * These custom actions should simplify the timing for us. |
| | | */ |
| | | add_action('plugins_loaded', 'jvb_site_definitions',1); |
| | | add_action('plugins_loaded', 'jvb_registrar_definitions',2); |
| | | add_action('plugins_loaded', 'jvb_field_definitions', 3); |
| | | add_action('init', 'jvbLoadBase', 1); |
| | | add_action('init', 'jvb_integration_definitions',3); |
| | | add_action('init', 'jvb_field_section_definitions', 5); |
| | | /** |
| | | * Can define the Site settings |
| | | * @return void |
| | | */ |
| | | function jvb_site_definitions():void |
| | | { |
| | | do_action('jvb_define_site'); |
| | | } |
| | | function jvb_registrar_definitions():void |
| | | { |
| | | do_action('jvb_define_registrar'); |
| | | } |
| | | function jvb_field_definitions():void |
| | | { |
| | | do_action('jvb_define_fields'); |
| | | } |
| | | |
| | | |
| | | function jvbLoadBase():void |
| | | { |
| | | JVB::getInstance(); |
| | | } |
| | | |
| | | function jvb_integration_definitions():void |
| | | { |
| | | do_action('jvb_define_integrations'); |
| | | } |
| | | |
| | | function jvb_field_section_definitions():void |
| | | { |
| | | do_action('jvb_define_field_sections'); |
| | | Registrar::maybeBuildSections(); |
| | | } |
| | | |
| | | |
| | | function JVB(): JVB |
| | | { |
| | | return JVB::getInstance(); |
| | |
| | | if (Site::has('favourites')) { |
| | | $interactions[] = 'favourites'; |
| | | } |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | $interactions[] = 'karma'; |
| | | } |
| | | if (Site::has('notifications')) { |
| | |
| | | }'; |
| | | } |
| | | |
| | | if (!empty(Registrar::getFeatured('karma'))) { |
| | | if (!empty(Registrar::withFeature('karma'))) { |
| | | wp_enqueue_script('jvb-votes'); |
| | | $initUserSettings .= '// Fetch user votes |
| | | try { |