Jake Vanderwerf
2026-01-04 22e1bb3fcc3b3db1c0f5c2e6a4aecaf408c307a5
inc/integrations/Integrations.php
@@ -430,7 +430,6 @@
      } else {
         $result =  $this->$method();
      }
      error_log('Action result: '.print_r($result, true));
      if (is_wp_error($result)) {
         return [
            'success' => false,
@@ -651,9 +650,7 @@
      }
      try {
         error_log('Credentials to save: '.print_r($this->credentials, true));
         if ($this->isOAuthService && !$this->hasOAuthCredentials()){
            error_log('Just saving credentials, we don\'t have OAuth setup yet...');
            //If this is an OAuth service, we might only be saving the app credentials first
            $result = true;
         } else {
@@ -761,6 +758,9 @@
      array  $options = []
   ): array|WP_Error
   {
      if (!$this->is_healthy) {
         return new WP_Error('unhealthy', 'Connection marked unhealthy. Skipping fetch');
      }
      $this->ensureInitialized();
      if (!$this->isSetUp()){
         $this->logError('Connection not setup for '.$this->service_name, [
@@ -774,24 +774,21 @@
         return new WP_Error('rate_limit', 'Rate limit exceeded. Please try again later.');
      }
      // Debug: Check if credentials are loaded
      error_log('['.$this->service_name.'] Make Request - Credentials loaded: ' . (!empty($this->credentials) ? 'Yes' : 'No'));
      error_log('With Credentials: '.print_r($this->credentials, true));
      $attempt = 0;
      $lastError = null;
      while ($attempt < $this->maxRetries) {
         try {
            $this->logDebug('[Integrations] Making request to '.$this->service_name);
//          $this->logDebug('[Integrations] Making request to '.$this->service_name);
            $result = $this->executeRequest($method, $endpoint, $data, $baseKey, $options);
            if (!$result) {
               return new WP_Error('Request Error');
            }
            $this->recordRequest($method, $endpoint);
            $this->logDebug('[Integrations]', [
               'response' => $result
            ]);
//          $this->logDebug('[Integrations]', [
//             'response' => $result
//          ]);
            // Reset error stats on success
            $this->resetErrorStats();
            return $result;
@@ -840,7 +837,7 @@
         return null;
      }
      $this->logDebug("$method request to: $url: ".print_r($args, true));
//    $this->logDebug("$method request to: $url: ".print_r($args, true));
      // Make the request
      $response = match($method) {
@@ -871,9 +868,9 @@
         if ($retry_count === 0) {
            $retry_count++;
            $this->logDebug('Got 401, attempting token refresh...');
//          $this->logDebug('Got 401, attempting token refresh...');
            if ($this->refreshOAuthToken()) {
               $this->logDebug('Token refreshed successfully, retrying request...');
//             $this->logDebug('Token refreshed successfully, retrying request...');
               // Rebuild request args with new token
               $args = $this->buildRequestArgs($method, $data, $options);
@@ -929,7 +926,8 @@
      if (!$force && $ttl > 0) {
         $cached = $this->cache->get($cacheKey);
         if ($cached !== false) {
            $this->logDebug("Cache hit for: $cacheKey");
//          $this->logDebug("Cache hit for: $cacheKey");
            return $cached;
         }
      }
@@ -1215,14 +1213,10 @@
   public function handleAjaxResponse()
   {
      error_log('Ajax Response: '.print_r($_GET, true));
      $code = $_GET['code'];
      $state =  $_GET['state'];
      error_log('OAuth Callback - Code: ' . $code);
      error_log('OAuth Callback - State: ' . $state);
      $state_parts = explode('|', $state);
      $state_key = $state_parts[0] ?? '';
@@ -1230,16 +1224,13 @@
      $user_id = ($user_id === 0) ? null : $user_id;
      $return_url = isset($state_parts[2]) ? base64_decode($state_parts[2]) : admin_url('admin.php?page=jvb-integrations');
      error_log('Service: '.print_r($this->service_name, true));
      $state_data = get_transient('oauth_state_' . $state_key);
      error_log('State Data: '.print_r($state_data, true));
      if (!$state_data || $state_data['service'] !== $this->service_name) {
         wp_die('Invalid state parameter', 'OAuth Error');
      }
      // Delete the transient to prevent reuse
      delete_transient('oauth_state_' . $state_key);
      error_log('Return URL: '.print_r($return_url, true));
      // Handle error from OAuth provider
      if (array_key_exists('error', $_GET)) {
         $error_description = $_GET['error_description'] ?? 'Authorization denied';
@@ -1394,7 +1385,7 @@
               // Only attempt refresh once per request
               if (!$this->token_refresh_attempted) {
                  $this->token_refresh_attempted = true;
                  $this->logDebug('OAuth token expired, attempting refresh');
//                $this->logDebug('OAuth token expired, attempting refresh');
                  if (!$this->refreshOAuthToken()) {
                     $this->logError('Failed to refresh expired OAuth token - stopping execution');
@@ -1403,14 +1394,14 @@
                  }
               } else {
                  // Already attempted refresh in this request
                  $this->logDebug('Token refresh already attempted, skipping');
//                $this->logDebug('Token refresh already attempted, skipping');
                  return;
               }
            }
            // Check if we should proactively refresh (before expiry)
            elseif ($this->shouldRefreshToken() && !$this->token_refresh_attempted) {
               $this->token_refresh_attempted = true;
               $this->logDebug('OAuth token should be refreshed proactively');
//             $this->logDebug('OAuth token should be refreshed proactively');
               if (!$this->refreshOAuthToken()) {
                  $this->logError('Failed to proactively refresh OAuth token');
                  // Not critical - token is still valid, so continue
@@ -1637,8 +1628,6 @@
      $auth_url = $this->oauth['authorize'] . '?' . http_build_query($params);
      // Debug log for troubleshooting
      error_log("Generated OAuth URL for {$this->service_name}: " . $auth_url);
      return $auth_url;
   }
@@ -1932,7 +1921,6 @@
         return false;
      }
      // Build refresh request data
      $request_data = [
         'client_id' => $this->credentials['client_id'],
         'client_secret' => $this->credentials['client_secret'],
@@ -1940,12 +1928,24 @@
         'grant_type' => 'refresh_token'
      ];
      // Use centralized OAuth request method
      $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' => $response->get_error_message()
            'error' => $error_message
         ]);
         return false;
      }
@@ -2136,45 +2136,36 @@
    */
   public function handleSavePost(int $postID, WP_Post $post, bool $update): void
   {
      error_log('Testing For Save Post');
      if (jvbNoSaveIt($postID, $post)) {
         error_log('Excluded by jvbNoSaveIt');
         return;
      }
      if (empty($this->syncPostTypes)) {
         error_log('No Syncable post types');
         return;
      }
      $config = JVB_CONTENT[jvbNoBase($post->post_type)]??null;
      if (!$config) {
         error_log('No Config set');
         return;
      }
      $settings = $config['integrations'][$this->service_name]??null;
      if (!$settings) {
         error_log('No settings');
         return;
      }
      $fields = $this->getSyncFields($postID, 'post', ['schedule_'.$this->service_name]);
      error_log('Fields to check: '.print_r($fields, true));
      if (!$fields['share_to_'.$this->service_name]) {
         return;
      }
      $isShared = isset($fields["_{$this->service_name}_item_id"]);
      if ($update && $isShared && !$fields['_keep_synced_'.$this->service_name]) {
         error_log('Do not keep synced, not syncing with '.$this->service_name);
         return;
      }
      if ($post->post_status !== 'publish' && !$isShared) {
         error_log('Not published and not already shared');
         return;
      }
      error_log('Sending to integration for processing...');
      $this->handleTheSavePost($postID, $post, $update, $settings);
   }
@@ -2647,11 +2638,6 @@
      ];
      $this->is_healthy = true;
      $this->saveErrorStats();
      $this->logDebug('Integration health manually reset', [
         'reset_by' => get_current_user_id(),
         'reset_time' => time()
      ]);
   }
   /**
@@ -2786,9 +2772,6 @@
      // Check for duplicate processing (idempotency)
      if ($this->isWebhookProcessed($payload)) {
         $this->logDebug('Webhook already processed', [
            'webhook_id' => $this->extractWebhookId($payload)
         ]);
         return true; // Return true to prevent retries
      }
@@ -3201,7 +3184,6 @@
      // Verify nonce
      $nonce_field = 'jvb_integration_nonce_' . $service;
      $nonce_action = 'jvb_integration_save_' . $service;
      error_log('handleAdminPost: '.print_r($_POST, true));
      if (!isset($_POST[$nonce_field]) || !wp_verify_nonce($_POST[$nonce_field], $nonce_action)) {
         wp_die('Security check failed');
      }