From 0dfe1d8afafc59c4a5559c498342668d5a58d6ef Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 23 Jul 2026 22:41:41 +0000
Subject: [PATCH] =Still working away at the Integrations overhaul
---
inc/integrations/Integrations.php | 1659 +----------------------------------------------------------
1 files changed, 35 insertions(+), 1,624 deletions(-)
diff --git a/inc/integrations/Integrations.php b/inc/integrations/Integrations.php
index dd8ede2..f055894 100644
--- a/inc/integrations/Integrations.php
+++ b/inc/integrations/Integrations.php
@@ -3,17 +3,9 @@
use Exception;
use JVBase\managers\Cache;
-use JVBase\managers\ErrorHandler;
-use JVBase\managers\queue\executors\IntegrationExecutor;
-use JVBase\managers\queue\mergers\DefaultMerger;
-use JVBase\managers\queue\TypeConfig;
use JVBase\managers\UploadManager;
-use JVBase\meta\Form;
-use JVBase\meta\Meta;
-use JVBase\registrar\helpers\AddIntegrationFields;
use JVBase\registrar\Registrar;
use WP_Error;
-use WP_Post;
if (!defined('ABSPATH')) {
exit;
@@ -32,18 +24,14 @@
{
use _Base;
- //Flag to allow for custom settings (defaults, etc) for an integration in the dashboard
- public bool $hasExtraOptions = false;
- public bool $hasBatchCreate = false;
- public bool $hasBatchUpdate = false;
- public bool $hasBatchDelete = false;
- public bool $canCreateOnUpdate = false;
-
/**
* API Configuration
* These properties define how the integration connects to external services
*/
protected string|array $apiBase = ''; // Base URL(s) for API endpoints. Array format: ['base' => '', 'auth' => '']
+ /**
+ * @var array<APIEndpoint> An array of endpoints objects, with optional create, update, delete, batch<x>, and batchImport
+ */
protected array $apiEndpoints = []; // Valid endpoint paths for this service
protected int $refresh_interval = 0; //seconds before expiry to refresh tokens. 0 to disable
@@ -52,16 +40,11 @@
/**
* Credentials & State
*/
-
- protected string $defaultContent = 'post'; //Default integration content type, is none is set. MUST EXIST as array key in $this->>getContentTypes
-
protected array $allowedContent = [];
/**
* Caching Configuration
*/
- protected ?string $cacheName = null;
- protected Cache $cache;
protected array $cacheStrategy = [
'aggressive' => 3600, // 1 hour for stable data (e.g., profile info)
'moderate' => 300, // 5 minutes for semi-dynamic data (e.g., posts)
@@ -69,26 +52,6 @@
'none' => 0 // No caching for real-time data
];
- /**
- * Post Syncing Capabilities
- * Define what sync operations this integration supports
- */
- protected array $canSync = [
- 'initial' => false, // Can share new posts to the service
- 'update' => false, // Can update already-shared posts
- 'delete' => false, // Can remove posts from the service
- ];
- protected array $syncPostTypes = []; // Post types that can be synced (e.g., ['artwork', 'tattoo']): usually built by Registrar.php if the integration name exists as a key in [ 'integrations' => []]
- protected array $syncTaxonomies = []; // Post types that can be synced (e.g., ['artwork', 'tattoo']): usually built by Registrar.php if the integration name exists as a key in [ 'integrations' => []]
- protected array $contentTypes = []; // Integration's available content types. Set by child classes' getContentTypes
- protected bool $has_content = false; // Whether integration has content that can sync
- /**
- * Error Handling Configuration
- */
- protected array $lastError = [];
- protected array $retryDelays = [1, 2, 5]; // Exponential backoff in seconds
-
-
protected function __construct(?int $userID = null)
{
@@ -98,7 +61,11 @@
$this->getPostTypes();
$this->getTaxonomies();
- $this->setContentTypes();
+ $this->getUsers();
+
+ if (method_exists($this, 'setContentTypes')) {
+ $this->setContentTypes();
+ }
$this->registerHooks();
if (method_exists($this, 'setQueueTypes')) {
@@ -106,193 +73,30 @@
}
$this->initializeRateLimiters();
+
if (method_exists($this, 'initializeActions')) {
$this->initializeActions();
}
if (method_exists($this, 'addOAuthActions')) {
$this->addOAuthActions();
}
-
- add_filter('jvbShouldRenderMeta', [$this, 'checkRenderField'], 10, 4);
- }
- protected function initializeRateLimiters():void
- {
- $key = $this->service_name;
- if (!is_null($this->userID)) {
- $key .= '_'.$this->userID;
- }
-
- if ($this->hasRequests && !isset($this->requestLimiter) && !is_null($this->oauthLimiter)) {
- $this->requestLimiter = new RateLimits($key);
- }
- if ($this->hasOAuth && !isset($this->oauthLimiter) && !is_null($this->oauthLimiter)) {
- $key .= '_oauth';
- $this->oauthLimiter = new RateLimits($key, ['s' => 1,'m' => 10, 'h' => 100]);
- }
- }
-
-
- protected function setContentTypes():void
- {
-
- }
- public function getContentTypes(string $type):array
- {
- return (array_key_exists($type, $this->contentTypes)) ? $this->contentTypes[$type] : $this->contentTypes;
- }
-
- public function checkRenderField($shouldRender, $name, $type, $objectType):bool
- {
- if ($type !== 'form') {
- return $shouldRender;
- }
-
- if (!$this->isSetUp() && str_contains($name, $this->service_name)) {
- return false;
- }
- return $shouldRender;
- }
-
- public function handleOAuthConnect(): array
- {
- if (!$this->hasOAuth) {
- return ['success' => false, 'message' => 'Not an OAuth service'];
- }
-
- // This would typically redirect to OAuth provider
- // Child classes can override for specific behavior
- $auth_url = $this->getOAuthUrl();
-
- if ($auth_url) {
- return [
- 'success' => true,
- 'redirect' => $auth_url,
- ];
- }
-
- return ['success' => false, 'message' => 'Failed to generate OAuth URL'];
- }
-
- /**
- * Check if OAuth token is valid and not expired
- * @return bool
- */
- public function isOAuthValid(): bool
- {
- if (!$this->isOAuthService) {
- return false;
- }
-
- // Check if we have tokens
- if (empty($this->credentials['access_token'])) {
- return false;
- }
-
- // Check token expiry if stored
- if (!empty($this->credentials['expires_at'])) {
- $expires_at = intval($this->credentials['expires_at']);
- if ($expires_at <= time()) {
- return false;
- }
- }
-
- // For services without expiry info, do a test API call
- return true;
-// return $this->testConnection();
- }
-
-
-
- public function getOAuthUrlAction(array $data = []): array
- {
- if (!$this->isOAuthService) {
- return ['success' => false, 'message' => 'Not an OAuth service'];
- }
-
- $return_url = $data['return_url'] ?? null;
- $auth_url = $this->getOAuthUrl($return_url);
-
- if ($auth_url) {
- return [
- 'success' => true,
- 'auth_url' => $auth_url,
- 'popup' => true
- ];
- }
-
- return ['success' => false, 'message' => 'Failed to generate OAuth URL'];
}
protected function getPostTypes(): void
{
- $this->syncPostTypes = Registrar::withIntegration($this->service_name);
+ $this->syncPostTypes = Registrar::withIntegration($this->service_name, 'post');
+ }
+
+ protected function getUsers():void
+ {
+ $this->syncUsers = Registrar::withIntegration($this->service_name, 'user');
}
protected function getTaxonomies():void
{
- $key = BASE . $this->service_name . '_sync_taxonomies';
- $taxonomies = get_option($key, false);
-
- if (!$taxonomies) {
- // Combine both content and taxonomy filtering
- $taxonomies = [];
- foreach (Registrar::withFeature('is_content', 'term') as $type) {
- $registrar = Registrar::getInstance($type);
- if ($registrar->hasIntegration($this->service_name)) {
- $taxonomies[] = $registrar->getSlug();
- }
- }
-
- update_option($key, $taxonomies);
- }
-
- $this->syncTaxonomies = $taxonomies;
+ $this->syncTaxonomies = Registrar::withIntegration($this->service_name, 'term');
}
- protected function getRedirectUri(): string
- {
-// if (!empty($this->oauth['redirect_uri'])) {
-// return $this->oauth['redirect_uri'];
-// }
- if ($this->hasOAuth) {
- return admin_url('admin-ajax.php?action=' . BASE . $this->service_name . '_oauth_callback');
- }
- // Changed from admin-ajax.php to REST endpoint
- return rest_url('jvb/v1/oauth/callback?service=' . $this->service_name);
- }
-
- /**
- * Used by IntegrationsRoutes.php
- * @param string $code
- * @param string $state
- * @return array
- */
- public function handleOAuthCode(string $code, string $state): array
- {
- try {
- $this->loadCredentials();
- $tokens = $this->exchangeOAuthCode($code);
-
- if (!$tokens) {
- return ['success' => false, 'message' => 'Failed to exchange authorization code'];
- }
-
- $credentials = array_merge($this->credentials, $tokens);
- $credentials = $this->addCredentialData($credentials, $tokens);
- $saved = $this->saveCredentials($credentials, false);
-
- if ($saved) {
- return ['success' => true, 'message' => 'Successfully connected'];
- }
-
- return ['success' => false, 'message' => 'Failed to save credentials'];
- } catch (Exception $e) {
- $this->logError('OAuth code exchange failed', ['error' => $e->getMessage()]);
- return ['success' => false, 'message' => 'OAuth error: ' . $e->getMessage()];
- }
- }
-
-
/*********************************************************************
* ABSTRACT METHODS - MUST BE IMPLEMENTED BY CHILD CLASSES
*********************************************************************/
@@ -338,33 +142,20 @@
try {
// Process and validate credentials
if (!$this->validateCredentials($credentials)) {
- $this->logError('Invalid credentials');
- return [
- 'success' => false,
- 'message' => 'Credentials not formatted correctly'
- ];
+ $this->logError('saveCredentials', 'Invalid credentials');
+ return $this->response(false, 'Credentials not formatted correctly');
}
+ //Merge the new credentials with the old ones (new stuff overriding any old stuff)
$old = $this->getCredentials();
$credentials = array_merge($old, $credentials);
- // Temporarily set credentials for testing
- $this->credentials = $credentials;
- $this->initialize();
-
// Test the connection before saving
if ($test) {
if (!$this->testConnection(true)) {
- $this->logError('Connection test failed');
- // Revert to old credentials
- $this->credentials = $old;
- $this->initialize();
+ $this->logError('saveCredentials', 'Connection test failed');
- return [
- 'success' => false,
- 'message' => 'Connection failed. Please check your credentials.',
- 'test_failed' => true
- ];
+ return $this->response(false, 'Connection failed. Please check your credentials');
}
}
@@ -380,17 +171,10 @@
$this->updateLastTestedTime();
$this->clearCache();
- return [
- 'success' => true,
- 'message' => 'Credentials validated and saved successfully',
- 'reload' => true
- ];
+ return $this->response(true, 'Credentials validated and saved successfully');
}
- return [
- 'success' => false,
- 'message' => 'Failed to save credentials to database'
- ];
+ return $this->response(false, 'Failed to save credentials to database');
} catch (\Exception $e) {
// Revert to old credentials on any error
@@ -398,13 +182,7 @@
$this->service_name,
$this->userID
);
- $this->credentials = $old;
- $this->initialize();
-
- return [
- 'success' => false,
- 'message' => 'Validation error: ' . $e->getMessage()
- ];
+ return $this->response(false, 'Validation error: '.print_r($e->getMessage(), true));
}
}
@@ -414,9 +192,7 @@
public function deleteCredentials():array
{
$success = Auth::getInstance()->deleteCredentials($this->service_name, $this->userID);
- return [
- 'success' => $success
- ];
+ return $this->response(true, 'Deleted successfully');
}
/**
* Validate credentials before storing
@@ -543,52 +319,6 @@
/******************************************************************
POST SYNC
******************************************************************/
- /**
- * Handle post save for syncing
- *
- * Override to implement custom sync logic when posts are saved.
- * Check the $settings array for post type specific configuration.
- *
- * @param int $postID The post ID
- * @param WP_Post $post The post object
- * @param bool $update Whether this is an update
- * @param array $settings Post type integration settings
- * @return void
- */
- protected function handleTheSavePost(int $postID, WP_Post $post, bool $update, array $settings): void
- {
- // Override in child classes that support post syncing
- // Example implementation:
- /*
- $fields = $this->getSyncFields($postID, 'post', ['schedule_' . $this->service_name]);
- $options = $fields['schedule_' . $this->service_name] !== ''
- ? ['scheduled' => strtotime($fields['schedule_' . $this->service_name])]
- : [];
-
- $this->queueOperation(
- 'sync_post',
- ['post_id' => $postID, 'is_update' => $update],
- $options
- );
- */
- }
-
- /*********************************************************************
- * API REQUEST METHODS
- *********************************************************************/
-
-
-
-
-
-
-
-
-
-
-
-
-
/*********************************************************************
* SYNC METHODS
@@ -668,7 +398,8 @@
// Let child classes register additional hooks if needed
$this->registerAdditionalHooks();
- if (!empty($this->syncPostTypes) && is_null($this->userID)) {
+
+ if (!empty($this->syncPostTypes)) {
$this->addSavePost();
add_action('transition_post_status', [$this, 'handlePostStatusTransition'], 10, 3);
@@ -676,64 +407,21 @@
add_action('before_delete_post', [$this, 'handleDeletePost'], 10, 1);
}
}
- if (!empty($this->syncTaxonomies) && is_null($this->userID)) {
+ if (!empty($this->syncTaxonomies)) {
add_action('saved_term', [$this, 'handleSaveTerm'], 20, 5);
if ($this->canSync['delete']) {
add_action('pre_delete_term', [$this, 'handleDeleteTerm'], 10, 2);
}
}
- add_action('init', [$this, 'registerQueueTypes'], 10);
+ if (method_exists($this, 'registerQueueTypes')) {
+ add_action('init', [$this, 'registerQueueTypes'], 10);
+ }
}
- public function addSavePost():void
- {
- if (!has_action('save_post', [$this, 'handleSavePost'])) {
- add_action('save_post', [$this, 'handleSavePost'], 20, 3);
- }
- }
- public function removeSavePost():void
- {
- remove_action('save_post', [$this, 'handleSavePost'], 20, 3);
- }
- public function registerQueueTypes():void
- {
- if (empty($this->syncTaxonomies) && empty($this->syncPostTypes)) {
- return;
- }
- $queue = JVB()->queue();
- $executor = new IntegrationExecutor();
- $queue->registry()->register(self::$syncTo, new TypeConfig(
- mergeable: new DefaultMerger('items'),
- executor: $executor,
- chunkKey: 'items',
- chunkSize: 50,
- maxRetries: 3,
- ));
- if ($this->canSync['delete']) {
- $queue->registry()->register(self::$deleteFrom, new TypeConfig(
- mergeable: new DefaultMerger('external_ids'),
- executor: $executor,
- chunkKey: 'external_ids',
- chunkSize: 200,
- maxRetries: 2
- ));
- }
-
- $queue->registry()->register(self::$syncFrom, new TypeConfig(
- executor: $executor,
- maxRetries: 3
- ));
-
- $this->registerAdditionalQueueTypes($executor);
- }
- protected function registerAdditionalQueueTypes(IntegrationExecutor $executor):void
- {
- //Empty. Integration extensions can register additional operation types from here.
- }
/**
* Handle connection setup and credential storage
@@ -755,11 +443,11 @@
}
// Store credentials
- $this->credentials = array_merge($this->credentials ?? [], $sanitized);
- $this->credentials['last_updated'] = time();
+ $credentials = array_merge($this->loadCredentials() ?? [], $sanitized);
+ $credentials['last_updated'] = time();
// Save to database
- $saved = $this->saveCredentials($this->credentials);
+ $saved = $this->saveCredentials($credentials);
if (!$saved) {
return [
@@ -810,6 +498,7 @@
/**
* Ensure service is initialized
+ * TODO: I don't think this is necessary anymore.
*/
protected function ensureInitialized(): void
{
@@ -819,404 +508,6 @@
$this->initialize();
}
-
- /***************************************************************
- ERROR HANDLING
- ***************************************************************/
- /**
- * Handle error responses
- */
- protected function handleApiError(int $code, string $body, string $endpoint): void
- {
- $message = "API Error ({$code}): ";
- $decoded = json_decode($body, true);
-
- // Extract error details
- $error_details = $this->extractErrorDetails($decoded, $body);
- $message .= $error_details['message'];
-
- // Determine error severity based on HTTP code
- $severity = $this->getErrorSeverity($code);
-
- // Build comprehensive error context
- $error_context = [
- 'service' => $this->service_name,
- 'endpoint' => $endpoint,
- 'http_code' => $code,
- 'error_type' => $this->categorizeApiError($code),
- 'error_details' => $error_details,
- 'user_id' => $this->userID,
- 'request_time' => time(),
- 'consecutive_errors' => $this->error_stats['consecutive_errors'],
- 'is_oauth' => $this->isOAuthService,
- 'api_version' => $this->apiVersion,
- 'integration_healthy' => $this->is_healthy
- ];
-
- // Add rate limit information if present
- if ($code === 429) {
- $error_context['rate_limit'] = $this->extractRateLimitInfo($decoded, $body);
- }
-
- // Log to ErrorHandler with proper severity
- $this->logError($message, $error_context, $severity);
-
- // Update error statistics
- $this->updateErrorStats($code, $endpoint);
-
- // Store last error for debugging
- $this->lastError = [
- 'code' => $code,
- 'message' => $message,
- 'endpoint' => $endpoint,
- 'timestamp' => time(),
- 'context' => $error_context
- ];
- }
-
-
- /*****************************************************************
- OAUTH
- *****************************************************************/
-
- /**
- * Get OAuth authorization URL
- */
- public function getOAuthUrl(?string $return_url = null): string
- {
-
- if (!$this->hasOAuth) {
- return '';
- }
-
- if (empty($this->credentials)) {
- $this->ensureInitialized();
- }
-
- if (empty($this->oauth['authorize'])) {
- $this->logError('OAuth authorize URL not configured');
- return '';
- }
-
- // Build base parameters
- $params = [
- 'client_id' => $this->credentials['client_id'] ?? $this->credentials['app_id'] ?? '',
- 'redirect_uri' => $this->getRedirectUri(),
- 'response_type' => 'code',
- 'scope' => implode(' ', $this->oauth['scopes'] ?? [])
- ];
- $state_key = wp_generate_password(32, false);
- $user_id = $this->userID??0;
-
- // Store state data in transient (expires in 10 minutes)
- set_transient(
- 'oauth_state_' . $state_key,
- [
- 'service' => $this->service_name,
- 'user_id' => $user_id,
- 'created' => time()
- ],
- 600
- );
-
- $state_parts = [
- $state_key,
- $user_id
- ];
-
- // Add return URL if provided
- if ($return_url) {
- $state_parts[] = base64_encode($return_url);
- } else {
- $state_parts[] = base64_encode(admin_url('admin.php?page=jvb-integrations'));
- }
-
- $params['state'] = implode('|', $state_parts);
-
- // Allow child classes to modify params (they can override/remove as needed)
- if (method_exists($this, 'addOAuthParams')) {
- $params = $this->addOAuthParams($params);
- }
-
- return $this->oauth['authorize'] . '?' . http_build_query($params);
- }
-
- /**
- * Add service-specific OAuth parameters
- */
- protected function addOAuthParams(array $params): array
- {
- // Override in child classes to add service-specific params
- // e.g., access_type, prompt, etc.
- return $params;
- }
-
-
-
- /**
- * Extract retry-after header from response
- *
- * @param array|WP_Error $response WordPress HTTP response
- * @return int Seconds to wait before retry
- */
- protected function extractRetryAfter($response): int
- {
- if (is_wp_error($response)) {
- return 5;
- }
-
- $headers = wp_remote_retrieve_headers($response);
-
- if (isset($headers['retry-after'])) {
- // Could be seconds or HTTP date
- $retry_after = $headers['retry-after'];
-
- if (is_numeric($retry_after)) {
- return (int) $retry_after;
- }
-
- // Try to parse as date
- $timestamp = strtotime($retry_after);
- if ($timestamp !== false) {
- return max(0, $timestamp - time());
- }
- }
-
- return 5; // Default wait time
- }
-
- /**
- * Exchange OAuth code for tokens
- */
- protected function exchangeOAuthCode(string $code): ?array
- {
- $this->ensureInitialized();
-
- // Build request data
- $request_data = [
- 'client_id' => $this->credentials['client_id'] ?? '',
- 'client_secret' => $this->credentials['client_secret'] ?? '',
- 'code' => $code,
- 'grant_type' => 'authorization_code',
- 'redirect_uri' => $this->getRedirectUri()
- ];
-
- $oauth_endpoint = $this->oauth['token'];
- $response = $this->makeOAuthRequest('POST', $oauth_endpoint, $request_data);
-
- if (is_wp_error($response)) {
- $this->logError('OAuth token exchange failed', [
- 'error' => $response->get_error_message(),
- 'code' => $response->get_error_code()
- ]);
- return null;
- }
-
- // Parse response
- if (isset($response['access_token'])) {
- $expires_in = $response['expires_in'] ?? 2592000; // 30 days default
-
- return [
- 'access_token' => $response['access_token'],
- 'refresh_token' => $response['refresh_token'] ?? '',
- 'expires_in' => $expires_in,
- 'expires_at' => time() + $expires_in, // Calculate expiry timestamp
- 'token_type' => $response['token_type'] ?? 'Bearer',
- 'merchant_id' => $response['merchant_id'] ?? '',
- 'scope' => $response['scope'] ?? ''
- ];
- }
-
- $this->logError('Failed to obtain access token', ['response' => $response]);
- return null;
- }
-
- /**
- * Add service-specific credential data
- */
- protected function addCredentialData(array $credentials, array $tokens): array
- {
- // Override in child classes to add service-specific data
- return $credentials;
- }
-
- /**
- * Check if token should be proactively refreshed
- * Different from isOAuthValid() which checks if token is actually expired
- */
- protected function shouldRefreshToken(): bool
- {
- if (!$this->hasOAuth || $this->refresh_interval === 0) {
- return false;
- }
-
- // If no expiry info, we can't proactively refresh
- if (empty($this->credentials['expires_at'])) {
- return false;
- }
-
- $expires_at = intval($this->credentials['expires_at']);
- $time_until_expiry = $expires_at - time();
-
- // Refresh if we're within the refresh interval window
- return $time_until_expiry > 0 && $time_until_expiry <= $this->refresh_interval;
- }
- /**
- * Get time until token refresh is recommended
- * Useful for displaying in admin UI
- */
- public function getTimeUntilRefresh(): ?int
- {
- if ($this->refresh_interval === 0 || empty($this->credentials['expires_at'])) {
- return null;
- }
-
- $expires_at = intval($this->credentials['expires_at']);
- $refresh_at = $expires_at - $this->refresh_interval;
- $time_until_refresh = $refresh_at - time();
-
- return max(0, $time_until_refresh);
- }
-
- /**
- * Get token freshness status
- * Returns: 'fresh', 'should_refresh', 'expired', or 'no_expiry_info'
- */
- public function getTokenStatus(): string
- {
- if (!$this->hasOAuth) {
- return 'not_oauth';
- }
-
- if (empty($this->credentials['access_token'])) {
- return 'no_token';
- }
-
- if (empty($this->credentials['expires_at'])) {
- return 'no_expiry_info';
- }
-
- $expires_at = intval($this->credentials['expires_at']);
- $now = time();
-
- if ($expires_at <= $now) {
- return 'expired';
- }
-
- if ($this->shouldRefreshToken()) {
- return 'should_refresh';
- }
-
- return 'fresh';
- }
- /**
- * Refresh OAuth token
- */
- protected function refreshOAuthToken(): bool
- {
- if (!$this->hasOAuth || empty($this->credentials['refresh_token'])) {
- return false;
- }
-
- $request_data = [
- 'client_id' => $this->credentials['client_id'],
- 'client_secret' => $this->credentials['client_secret'],
- 'refresh_token' => $this->credentials['refresh_token'],
- 'grant_type' => 'refresh_token'
- ];
-
- $response = $this->makeOAuthRequest('POST', $this->oauth['token'], $request_data);
-
- if (is_wp_error($response)) {
- $error_message = $response->get_error_message();
-
- if (str_contains($error_message, 'invalid_grant')) {
- $this->logError('OAuth refresh token is invalid - user must re-authorize', [
- 'error' => $error_message
- ], 'critical');
-
- // Mark unhealthy immediately
- $this->error_stats['consecutive_errors'] = $this->error_threshold;
- $this->is_healthy = false;
- $this->saveErrorStats();
- }
-
- $this->logError('Failed to refresh OAuth token for '.$this->service_name, [
- 'error' => $error_message
- ]);
- return false;
- }
-
- if (isset($response['access_token'])) {
- $this->credentials['access_token'] = $response['access_token'];
- $this->credentials['expires_at'] = time() + ($response['expires_in'] ?? 2592000); // 30 days
-
- // Note: Some services return the SAME refresh token
- if (isset($response['refresh_token'])) {
- $this->credentials['refresh_token'] = $response['refresh_token'];
- }
-
- $this->saveCredentials($this->credentials);
- return true;
- }
-
- return false;
- }
-
- /**
- * Revoke OAuth access
- */
- public function revokeOAuthAccess(): bool
- {
- if (!$this->hasOAuth || empty($this->oauth['revoke'])) {
- return false;
- }
-
- if (!empty($this->credentials['access_token'])) {
- wp_remote_post($this->oauth['revoke'], [
- 'body' => ['token' => $this->credentials['access_token']]
- ]);
- }
-
- return Auth::getInstance()->deleteCredentials($this->service_name, $this->userID);
-
- }
-
- public function handleOAuthDisconnect(): array
- {
- try {
- // Revoke the token with Square using centralized request
- if (!empty($this->credentials['access_token'])) {
- $revoke_data = [
- 'client_id' => $this->credentials['client_id'] ?? '',
- 'access_token' => $this->credentials['access_token']
- ];
-
- // Make revoke request (ignore response as revoke often returns empty)
- $this->makeOAuthRequest('POST', $this->oauth['revoke'], $revoke_data);
- }
-
- // Clear stored credentials (preserve app credentials)
- $this->credentials = [
- 'client_id' => $this->credentials['client_id'] ?? '',
- 'client_secret' => $this->credentials['client_secret'] ?? '',
- 'environment' => $this->credentials['environment'] ?? 'sandbox'
- ];
-
- $this->saveCredentials($this->credentials);
- $this->clearCache();
-
- return [
- 'success' => true,
- 'message' => 'Successfully disconnected from Square'
- ];
- } catch (Exception $e) {
- return [
- 'success' => false,
- 'message' => 'Failed to disconnect: ' . $e->getMessage()
- ];
- }
- }
/**
* Generate webhook signature key for services that require it
* @return string
@@ -1225,268 +516,6 @@
{
return wp_generate_password(32, false);
}
- /**
- * Generate OAuth state parameter
- */
- protected function generateOAuthState(?int $user_id, ?string $return_url = null): string
- {
- $user_id = $user_id ?? 0;
- $state = wp_create_nonce($this->service_name . '_oauth_' . $user_id) . '|' . $user_id;
-
- if ($return_url) {
- $state .= '|' . base64_encode($return_url);
- }
-
- return $state;
- }
-
- protected function getNonce(): string
- {
- return wp_create_nonce($this->service_name . '_oauth_' . $this->userID);
- }
-
- /**
- * Determine return URL after OAuth
- */
- protected function determineReturnUrl(?int $user_id): string
- {
- if ($user_id > 0) {
- return home_url('/dash/integrations/#' . $this->service_name);
- }
-
- return admin_url('admin.php?page=jvb-integrations');
- }
-
-
- /****************************************************************
- POST SYNC
- ****************************************************************/
- /**
- * Get field mapping for a post type
- */
- protected function getFieldMapping(string $post_type): array
- {
- // Apply filter for custom mapping
- return apply_filters(
- "jvb_{$this->service_name}_field_mapping",
- [],
- $post_type,
- $this
- );
- }
-
-
- /**
- * Map WordPress fields to service fields
- */
- protected function mapFieldsToService(int $postID, array $mapping): array
- {
- $meta_manager = Meta::forPost($postID);
- $service_data = [];
-
- foreach ($mapping as $wp_field => $service_field) {
- $value = $meta_manager->get($wp_field);
-
- if ($value !== null && $value !== '') {
- $this->setNestedValue($service_data, $service_field, $value);
- }
- }
-
- return apply_filters(
- "jvb_{$this->service_name}_mapped_data",
- $service_data,
- $postID,
- $mapping
- );
- }
-
- /**
- * Set nested array value using dot notation
- */
- protected function setNestedValue(array &$array, string $path, $value): void
- {
- $keys = explode('.', $path);
- $current = &$array;
-
- foreach ($keys as $i => $key) {
- if ($i === count($keys) - 1) {
- $current[$key] = $value;
- } else {
- if (!isset($current[$key])) {
- $current[$key] = [];
- }
- $current = &$current[$key];
- }
- }
- }
- /**
- * Handle post save
- */
- public function handleSavePost(int $postID, WP_Post $post, bool $update): void
- {
- if (!is_null($this->userID)) {
- return;
- }
- error_log('=== ['.$this->service_name.']::handleSavePost called');
-
- if (!$postID || $postID === 0) {
- return;
- }
- $postType = jvbNoBase($post->post_type);
-
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
- if (wp_is_post_revision($postID)) return;
-
-
- if (empty($this->syncPostTypes) || !in_array(jvbNoBase($postType), $this->syncPostTypes)) {
- error_log('Not handling save for '.$this->service_name.' because there are no syncPostTypes: '.print_r($this->syncPostTypes, true));
- return;
- }
-
- $registrar = Registrar::getInstance($postType);
- if (!$registrar){
- return;
- }
-
- $settings = $registrar->hasIntegration($this->service_name)??null;
- if (!$settings) {
- error_log('Not handling save for '.$this->service_name.' because of no registrar settings');
- return;
- }
-
- $settings = $registrar->getIntegrationConfig($this->service_name);
- if (!$settings){
- error_log('Not handling save for '.$this->service_name.' because of no integration config '.print_r($settings, true));
- return;
- }
-
-
- $fields = $this->getSyncFields($postID, 'post', ['schedule_'.$this->service_name]);
- if (!$fields['share_to_'.$this->service_name]) {
- error_log('Not handling save for '.$this->service_name.' because of no share_to_'.$this->service_name.' '.print_r($fields, true));
- return;
- }
-
- $isShared = isset($fields["_{$this->service_name}_item_id"]);
- if ($update && $isShared && !$fields['_keep_synced_'.$this->service_name]) {
- error_log('Not handling save for '.$this->service_name.' because it is already shared, and not set to keep synced. ');
- return;
- }
-
- if ($post->post_status !== 'publish' && !$isShared) {
- error_log('Not handling save for '.$this->service_name.' because post status is not publish, and it is not already shared.');
- return;
- }
- error_log('==== Sending to integration\'s handleTheSavePost '.$this->service_name.' ====');
- $this->removeSavePost();
- $this->handleTheSavePost($postID, $post, $update, $settings);
- $this->addSavePost();
- }
-
-
- protected function getSyncFields(int $postID, string $type, array $additional = []):array
- {
- $meta = new Meta($postID, $type);
- $fieldsToCheck = [
- 'share_to_' . $this->service_name,
- '_keep_synced_' . $this->service_name,
- "_{$this->service_name}_item_id",
- "_{$this->service_name}_last_sync",
- "_{$this->service_name}_shared_at",
- "_{$this->service_name}_sync_status",
- ... $additional
- ];
- return $meta->getAll($fieldsToCheck);
- }
-
- /**
- * Handle post status transitions
- */
- public function handlePostStatusTransition(string $new_status, string $old_status, WP_Post $post): void
- {
- if (empty($this->syncPostTypes)) {
- return;
- }
-
- if (!in_array(jvbNoBase($post->post_type), $this->syncPostTypes)) {
- return;
- }
-
- //Map fields from our custom post types to the fields expected by the integration
- $mappedFields = $this->getFieldMapping($post->post_type);
-
- $fields = $this->getSyncFields($post->ID, 'post', $mappedFields);
-
- // Handle unpublish action
- if ($old_status === 'publish' && $new_status !== 'publish') {
-
- if ($fields["_{$this->service_name}_item_id"] && $this->canSync['delete']) {
- try {
- $this->queueOperation(
- 'delete_post',
- [
- $post,
- $fields["_{$this->service_name}_item_id"]
- ]
- );
- } catch (Exception $e) {
- $this->logError("Failed to handle unpublish for post {$post->ID}: " . $e->getMessage());
- }
- }
- }
- }
-
- /**
- * Handle post deletion
- */
- public function handleDeletePost(int $postID): void
- {
- if (!$this->canSync['delete']) {
- return;
- }
-
- $post = get_post($postID);
- if (!$post || !in_array($post->post_type, $this->syncPostTypes)) {
- return;
- }
-
- $fields = $this->getSyncFields($postID, 'post');
-
- if ($fields["_{$this->service_name}_item_id"] !== '') {
-
- $this->queueOperation(
- 'delete_post',
- [
- 'post_id' => $post->ID,
- ]
- );
- }
- }
-
- protected function handleSaveTerm($term_id, $tt_id, $taxonomy, $update, $args): void
- {
- $noBase = jvbNoBase($taxonomy);
- if (!in_array($noBase, $this->syncTaxonomies)) {
- return;
- }
- $registrar = Registrar::getInstance($noBase);
- if (!$registrar->hasFeature('is_content')) {
- return;
- }
-
-
- $settings = $registrar->getIntegrationConfig($this->service_name);
- if (!$settings) {
- return;
- }
-
- // Similar sync logic as handleSavePost but for terms
- $this->handleTheTermSave($term_id, $taxonomy, $update, $settings);
- }
-
- protected function handleTheTermSave($term_id, $taxonomy, $update, $settings) {
-
- }
/*******************************************************************
@@ -1494,183 +523,6 @@
*******************************************************************/
/**
- * Get API URL for endpoint
- */
- protected function getApiUrl(string $endpoint, ?string $baseKey = null): string|false
- {
- if ($this->hasOAuth && in_array($endpoint, $this->oauth)) {
- return $endpoint;
- }
- if (is_array($this->apiBase)) {
- if ($baseKey && array_key_exists($baseKey, $this->apiBase)) {
- $base = $this->apiBase[$baseKey];
- } else {
- $base = ($this->apiBase['base'] ?? reset($this->apiBase));
- }
- } else {
- $base = $this->apiBase;
- }
-
- if (!$base || $base === '') {
- $this->logError('API base URL not configured for {$this->>service_name}');
- return false;
- }
-
- // Handle named endpoints
- if (!$this->isValidEndpoint($endpoint)) {
- $this->logError("{$endpoint} is not a valid endpoint for {$this->service_name}");
- return false;
- }
-
- // Build full URL
- $base = rtrim($base, '/');
- $endpoint = ltrim($endpoint, '/');
-
- return "{$base}/{$endpoint}";
- }
-
- /**
- * Check if an endpoint is valid, supporting both exact matches and patterns
- *
- * @param string $endpoint
- * @return bool
- */
- protected function isValidEndpoint(string $endpoint): bool
- {
- // Remove query parameters for validation
- $endpointPath = parse_url($endpoint, PHP_URL_PATH);
- if ($endpointPath === false) {
- $endpointPath = $endpoint;
- }
-
- foreach ($this->apiEndpoints as $pattern) {
- // Check for exact match first
- if ($endpointPath === $pattern) {
- return true;
- }
-
- if (str_starts_with($endpointPath, $pattern)) {
- return true;
- }
-
- // Check if pattern contains wildcards (indicated by square brackets)
- if (strpos($pattern, '[') !== false) {
- // Convert the pattern to a regex
- $regexPattern = '#^' . str_replace(['[^/]+'], ['[^/]+'], $pattern) . '(?:\?.*)?$#';
- if (preg_match($regexPattern, $endpoint)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
-
-
- /**
- * Categorize API errors for better tracking
- */
- protected function categorizeApiError(int $code): string
- {
- return match(true) {
- $code >= 400 && $code < 404 => 'client_error',
- $code === 404 => 'not_found',
- $code === 401 => 'authentication',
- $code === 403 => 'authorization',
- $code === 429 => 'rate_limit',
- $code >= 500 && $code < 600 => 'server_error',
- default => 'unknown'
- };
- }
-
- /**
- * Determine error severity based on HTTP code
- */
- protected function getErrorSeverity(int $code): string
- {
- return match(true) {
- $code === 429 => 'warning', // Rate limiting
- $code >= 400 && $code < 500 => 'error', // Client errors
- $code >= 500 => 'critical', // Server errors
- default => 'error'
- };
- }
-
- /**
- * Extract error details from response
- */
- protected function extractErrorDetails($decoded, string $body): array
- {
- $details = [
- 'message' => 'Unknown error',
- 'code' => null,
- 'details' => null
- ];
-
- if ($decoded && isset($decoded['error'])) {
- if (is_array($decoded['error'])) {
- $details['message'] = $decoded['error']['message'] ?? json_encode($decoded['error']);
- $details['code'] = $decoded['error']['code'] ?? null;
- $details['details'] = $decoded['error']['details'] ?? null;
- } else {
- $details['message'] = $decoded['error'];
- }
- } elseif ($decoded && isset($decoded['message'])) {
- $details['message'] = $decoded['message'];
- } elseif (!empty($body)) {
- $details['message'] = $body;
- }
-
- return $details;
- }
-
- /**
- * Extract rate limit information from response
- */
- protected function extractRateLimitInfo($decoded, string $body): array
- {
- $info = [
- 'retry_after' => null,
- 'limit' => null,
- 'remaining' => null,
- 'reset' => null
- ];
-
- // Try to extract from decoded response
- if ($decoded) {
- $info['retry_after'] = $decoded['retry_after'] ?? $decoded['retry-after'] ?? null;
- $info['limit'] = $decoded['x-rate-limit-limit'] ?? null;
- $info['remaining'] = $decoded['x-rate-limit-remaining'] ?? null;
- $info['reset'] = $decoded['x-rate-limit-reset'] ?? null;
- }
-
- return $info;
- }
-
- /**
- * Update error statistics
- */
- protected function updateErrorStats(int $code, string $endpoint): void
- {
- $this->error_stats['total_errors']++;
- $this->error_stats['consecutive_errors']++;
-
- // Track error types
- $error_type = $this->categorizeApiError($code);
- if (!isset($this->error_stats['error_types'][$error_type])) {
- $this->error_stats['error_types'][$error_type] = 0;
- }
- $this->error_stats['error_types'][$error_type]++;
-
- // Save stats to cache
- $this->saveErrorStats();
- }
-
-
-
-
- /**
* Get service name
*/
public function getServiceName(): string
@@ -1697,24 +549,6 @@
return static::getInstance()::$hasExtraOptions;
}
- /*********************************************************************
- RENDERING
- *********************************************************************/
-// public function renderAdditionalOptions()
-// {
-// //Default: nothing.
-// }
-
- /**
- * Render additional action buttons (optional)
- * Override in integration classes that need extra actions
- */
-// public function renderAdditionalActions(): void
-// {
-// // Default: no additional actions
-// // Override in extensions for service-specific actions
-// }
-
/**
* Get service description (optional)
* Override in integration classes for custom descriptions
@@ -1746,236 +580,6 @@
}
-
-
-
-
- public function renderConnection(bool $return = false):string
- {
-
- if ($this->userID && !JVB()->userCanConnect($this->service_name, $this->userID)) {
- return '';
- }
-
- $meta = Meta::forOptions($this->userID.'_integrations');
- $is_connected = $this->isSetUp();
- $credentials = $this->getCredentials();
-
- $admin_only = $this->isOAuthService ? [
- 'client_id',
- 'client_secret',
- ] : [];
-
- ob_start();
- ?>
- <form id="<?=$this->service_name?>" class="integration <?php echo $is_connected ? 'connected' : 'disconnected'; ?>"
- data-service="<?php echo esc_attr($this->service_name); ?>">
- <div class="header row x-btw">
- <h3><?php echo esc_html($this->title); ?></h3>
- <div class="setup">
- <?php if ($is_connected): ?>
- <span class="indicator connected">●</span>
- <span class="text">Set Up</span>
- <?php else: ?>
- <span class="indicator disconnected">●</span>
- <span class="text">Not Set Up</span>
- <?php endif; ?>
- </div>
- </div>
-
- <?php if ($is_connected && array_key_exists('updated_at', $credentials) && $credentials['updated_at'] > 0): ?>
- <div class="meta">
- <small>Last updated: <?php echo human_time_diff($credentials['updated_at']) . ' ago'; ?></small>
- </div>
- <?php endif; ?>
-
- <?php
- if (!empty($this->instructions)) {
- ?>
- <details>
- <summary>
- Instructions
- </summary>
- <ol>
- <?php
- foreach ($this->instructions as $instruction) {
- echo '<li>'.$instruction.'</li>';
- }
- ?>
- </ol>
- </details>
- <?php
- }
-?>
- <details class="initial-setup"<?= $is_connected?'' : ' open'?>>
- <summary>Initial Setup</summary>
- <?php
- foreach ($this->fields as $name => $config) {
- if ($is_connected && !empty($credentials[$name])) {
- if (in_array($name, $admin_only) && !current_user_can('manage_options')) {
- continue;
- }
- ?>
- <span class="label"><?=$config['label']?>:</span>
- <code>
- <?php
- if (str_contains($name, 'secret')) {
- for ($i = 1; $i<=strlen($credentials[$name]) - 8; $i++) {
- echo '*';
- }
- echo substr($credentials[$name], -8);
- } else {
- echo $credentials[$name];
- }
- ?>
- </code>
- <?php
- } else {
- $config['value'] = $credentials[$name]??'';
- $config['autocomplete'] = 'off';
- $config['base'] = $this->service_name.'_';
- echo Form::render($name, '', $config);
- }
- }
- if ($this->hasWebhooks) {
- echo $this->renderWebhookUrl();
- }
- ?>
- </details>
- <?php
-
- if ($this->isOAuthService) {
- $this->renderConnectedOAuthStatus();
- }
-
- ?>
-
- <div class="integration-content">
-
- <?php
-
-
-
- if (!empty($this->advanced)) {
- ?>
- <details>
- <summary>Advanced Settings</summary>
- <?php
- foreach ($this->advanced as $name => $config) {
- $config['value'] = $credentials[$name]??'';
- $config['base'] = $this->service_name.'_';
- $config['autocomplete'] = 'off';
- Form::render($name,null, $config);
- }
- ?>
- </details>
- <?php
- }
- if (!empty($this->defaults)) {
- ?>
- <a href="<?php echo admin_url('admin.php?page=jvb-integration-' . $this->service_name); ?>"
- class="button">
- More Settings
- </a>
- <?php
- }
- ?>
- </div>
- <div class="actions row x-btw wrap">
- <?php
- foreach ($this->buttons as $action => $label) {
- if (!$is_connected && $action !== 'save_credentials') {
- continue;
- }
- $title = $confirm = '';
- switch ($action) {
- case 'save_credentials':
- $title = $label;
- $label = jvbIcon('floppy-disk');
- break;
- case 'clear_credentials':
- $title = $label;
- $label = jvbIcon('plugs');
- $confirm = ' data-confirm="Are you sure you want to delete these credentials?"';
- break;
- case 'clear_cache':
- $title = $label;
- $label = jvbIcon('arrows-clockwise');
- break;
- }
- $title = $title === '' ? '' : ' title ="'.$title.'"';
- ?>
- <button type="button" data-action="<?=$action?>"<?=$title?><?=$confirm?>><?=$label?></button>
- <?php
- }
- ?>
- </div>
- </form>
- <?php
- $result = ob_get_clean();
- if(!$return) {
- echo $result;
- }
- return $result;
- }
-
- protected function renderConnectedOAuthStatus(): void
- {
- if (!$this->isSetup()) {
- return;
- }
- $credentials = $this->getCredentials();
- $hasCredentials = $this->hasOAuthCredentials();
- $returnURL = is_admin() ? admin_url('admin.php?page=jvb-integrations') : (get_the_permalink() ?: home_url());
- ?>
-
- <details <?= $hasCredentials?' open':''?>>
- <summary>
- <?php if ($hasCredentials) { ?>
- Connected Account
- <?php } else { ?>
- <div class="oauth-connect">
- <a href="<?php echo esc_url($this->getOAuthUrl($returnURL)); ?>"
- class="button button-primary jvb-oauth-connect"
- data-service="<?php echo esc_attr($this->service_name); ?>">
- <?php echo jvbIcon($this->icon); ?>
- Authorize Connection
- </a>
- </div>
- <?php } ?>
- <div class="connection-status <?= $hasCredentials ? 'connected' : 'disconnected' ?>">
- <span class="status-indicator">●</span>
- <span><?= $hasCredentials ? 'Connected' : 'Not Connected' ?></span>
- </div>
- </summary>
- <label>OAuth Redirect URL:</label>
- <code>
- <?= $this->getRedirectUri(); ?>
- </code>
-
-
- <?php if (!empty($credentials['updated_at'])): ?>
- <div class="oauth-meta">
- <small>Token expires: <?php
- echo isset($credentials['expires_at'])
- ? human_time_diff($credentials['expires_at'])
- : 'Never';
- ?></small>
- </div>
- <?php endif;
- // Allow child classes to add service-specific connected UI
- $this->renderOAuthConnectedOptions();
- ?>
- </details>
- <?php
- }
-
- protected function renderOAuthConnectedOptions():void
- {
-
- }
-
-
/**
* Update last tested time
*/
@@ -1985,180 +589,6 @@
$cred->updateTested($this->service_name, $this->userID);
}
- public function handleAdminPost(): void
- {
- if (!current_user_can('manage_options')) {
- wp_die('Insufficient permissions');
- }
-
- $service = $this->getServiceName();
-
- // Verify nonce
- $nonce_field = 'jvb_integration_nonce_' . $service;
- $nonce_action = 'jvb_integration_save_' . $service;
- if (!isset($_POST[$nonce_field]) || !wp_verify_nonce($_POST[$nonce_field], $nonce_action)) {
- wp_die('Security check failed');
- }
-
- // Get the action type
- $action_type = sanitize_text_field($_POST['action_type'] ?? 'save');
-
- // Prepare the request in the format handleAjaxRequest expects
- $_REQUEST['action'] = $action_type;
- $_REQUEST['service'] = $service;
-
- // Copy all POST data to REQUEST
- foreach ($_POST as $key => $value) {
- $_REQUEST[$key] = $value;
- }
-
- // Set up for JSON response capture
- ob_start();
-
- try {
- // Call the existing AJAX handler
- $this->handleAjaxRequest();
- $response = ob_get_clean();
-
- // Parse the JSON response
- $result = json_decode($response, true);
-
- if ($result && isset($result['success'])) {
- if ($result['success']) {
- $message = $result['message'] ?? ucfirst($service) . ' settings saved successfully!';
- $this->setAdminNotice($message, 'success');
- } else {
- $message = $result['message'] ?? 'Failed to save ' . ucfirst($service) . ' settings.';
- $this->setAdminNotice($message, 'error');
- }
- } else {
- // If no proper JSON response, check if connection worked
- if ($action_type === 'test') {
- $connected = $this->testConnection();
- $message = $connected ? 'Connection successful!' : 'Connection failed. Please check your credentials.';
- $this->setAdminNotice($message, $connected ? 'success' : 'error');
- }
- }
- } catch (Exception $e) {
- ob_end_clean();
- $this->setAdminNotice('Error: ' . $e->getMessage(), 'error');
- }
-
- // Redirect back to integrations page
- wp_redirect(admin_url('admin.php?page=jvb-integrations'));
- exit;
- }
-
- /**
- * Set admin notice using transients for redirect
- */
- protected function setAdminNotice(string $message, string $type = 'info'): void
- {
- $notices = get_transient('jvb_admin_notices') ?: [];
- $notices[] = [
- 'message' => $message,
- 'type' => $type === 'success' ? 'updated' : 'error'
- ];
- set_transient('jvb_admin_notices', $notices, 30);
- }
-
- /**
- * Display admin notices from transient
- */
- public static function displayAdminNotices(): void
- {
- $notices = get_transient('jvb_admin_notices');
-
- if ($notices) {
- foreach ($notices as $notice) {
- ?>
- <div class="notice notice-<?php echo esc_attr($notice['type']); ?> is-dismissible">
- <p><?php echo esc_html($notice['message']); ?></p>
- </div>
- <?php
- }
- delete_transient('jvb_admin_notices');
- }
- }
-
- public function hasDefaults():bool
- {
- return !empty($this->defaults);
- }
-
- public function renderDefaults():void
- {
- $types = $this->enabledContentTypes();
- if (empty($types)) {
- return;
- }
- $meta = Meta::forOptions($this->userID.'_integrations');
- ?>
- <form>
- <h1><?= $this->title?> Defaults:</h1>
- <p>Find yourself constantly repeating yourself?</p>
- <p>Set defaults for different content types and <?=$this->title?>!</p>
- <?php
- foreach ($this->defaults as $name => $config) {
- $config['required'] = false;
-
- $config['base'] = $this->service_name.'_';
- $config['autocomplete'] = 'off';
- echo Form::render($name, null, $config);
- }
- foreach ($this->syncPostTypes as $type) {
- $registrar = Registrar::getInstance($type);
-
- $icon = $registrar->getIcon();
- $icon = $icon === '' ? jvbDefaultIcon() : $icon;
- ?>
- <details>
- <summary><?= jvbIcon($icon) ?><?= $registrar->getSingular()?> Defaults</summary>
- <?php
- $fields = new AddIntegrationFields($this->service_name);
- $fields = $fields->getIntegrationFields();
- foreach($fields as $name=>$c) {
- $c['required'] = false;
- if ($c['type'] === 'number') {
- $c['type'] = 'text';
- $c['subtype'] = 'number';
- }
- if (array_key_exists('description', $c)) {
- $c['hint'] = $c['description'];
- unset($c['description']);
- }
- echo Form::render($name, null, $c);
- }
- ?>
- </details>
- <?php
- }
- ?>
- </form>
- <?php
- }
-
- public function hasContent():bool
- {
- return $this->has_content;
- }
- public function getDefaultContentType():string
- {
- return $this->defaultContent;
- }
-
- public function enabledContentTypes():array
- {
- if (!$this->has_content) {
- return [];
- }
-
- return array_filter(array_map(function($registrar) {
- $registrar = Registrar::getInstance($registrar);
- return $registrar->getIntegration($this->service_name)->getContentType();
- }, Registrar::withIntegration($this->service_name)));
- }
-
protected function getSupportedImage(int $imgID):int
{
//If this integration supports webp, we can just send the original image id
@@ -2187,11 +617,6 @@
}
- public function getAllowedContent():array
- {
- return $this->allowedContent;
- }
-
/**
* Used by JVBase\registrar\helpers\AddIntegrationFields.php
* @return array
@@ -2206,18 +631,4 @@
return $this->icon;
}
-
-
- public function canBatchUpdate():bool
- {
- return $this->hasBatchUpdate;
- }
- public function canBatchCreate():bool
- {
- return $this->hasBatchCreate;
- }
- public function canBatchDelete():bool
- {
- return $this->hasBatchDelete;
- }
}
--
Gitblit v1.10.0