| @@ -116,9 +116,9 @@ | ||
| 116 | 116 | ?> |
| 117 | 117 | <div class="wpzinc-option"> |
| 118 | 118 | <div class="full"> |
| 119 | 119 | <a href="<?php echo esc_attr( $this->get_oauth_url() ); ?>" class="button button-primary"> |
| 120 | - <?php esc_html_e( 'Connect a Buffer Account', 'wp-to-buffer' ); ?> | |
| 120 | + <?php esc_html_e( 'Connect an additional Buffer Account', 'wp-to-buffer' ); ?> | |
| 121 | 121 | </a> |
| 122 | 122 | </div> |
| 123 | 123 | </div> |
| 124 | 124 | <?php |
| @@ -331,8 +331,13 @@ | ||
| 331 | 331 | * @param bool|int $token_expires Token Expiry. |
| 332 | 332 | */ |
| 333 | 333 | public function set_tokens( $access_token = '', $refresh_token = '', $token_expires = false ) { |
| 334 | 334 | |
| 335 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: set_tokens(): Started.' ); | |
| 336 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: set_tokens(): access_token = ' . $access_token ); | |
| 337 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: set_tokens(): refresh_token = ' . $refresh_token ); | |
| 338 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: set_tokens(): token_expires = ' . $token_expires ); | |
| 339 | + | |
| 335 | 340 | $this->access_token = $access_token; |
| 336 | 341 | $this->refresh_token = $refresh_token; |
| 337 | 342 | $this->token_expires = $token_expires; |
| 338 | 343 | |
| @@ -388,18 +393,29 @@ | ||
| 388 | 393 | * @since 2.0.0 |
| 389 | 394 | */ |
| 390 | 395 | public function refresh_token() { |
| 391 | 396 | |
| 397 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): Started.' ); | |
| 398 | + | |
| 392 | 399 | // Bail if we don't have a refresh token. |
| 393 | 400 | if ( empty( $this->refresh_token ) ) { |
| 401 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): Error: No refresh token available; cannot refresh.' ); | |
| 394 | 402 | return new \WP_Error( 'missing_refresh_token', __( 'No refresh token exists', 'wp-to-buffer' ) ); |
| 395 | 403 | } |
| 396 | 404 | |
| 405 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): access_token = ' . $this->access_token ); | |
| 406 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): refresh_token = ' . $this->refresh_token ); | |
| 407 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): token_expires = ' . $this->token_expires ); | |
| 408 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): token_expires = ' . ( $this->token_expires && time() > (int) $this->token_expires ? 'expired ' . ( time() - (int) $this->token_expires ) . 's ago' : 'expires in ' . ( (int) $this->token_expires - time() ) . 's' ) ); | |
| 409 | + | |
| 397 | 410 | // Bail if the access token hasn't yet expired. |
| 398 | 411 | if ( strtotime( '+15 minutes' ) < $this->token_expires ) { |
| 412 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): Skipped: Access token not yet within the 15 minute refresh window.' ); | |
| 399 | 413 | return false; |
| 400 | 414 | } |
| 401 | 415 | |
| 416 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): Requesting new access token.' ); | |
| 417 | + | |
| 402 | 418 | // Send request. |
| 403 | 419 | $result = $this->oauth_request( |
| 404 | 420 | $this->oauth_authorize_url . 'token', |
| 405 | 421 | array( |
| @@ -410,8 +426,10 @@ | ||
| 410 | 426 | ); |
| 411 | 427 | |
| 412 | 428 | // If an error occured, log and return it now. |
| 413 | 429 | if ( is_wp_error( $result ) ) { |
| 430 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: refresh_token(): Error: [%s] %s', $result->get_error_code(), $result->get_error_message() ) ); | |
| 431 | + | |
| 414 | 432 | /** |
| 415 | 433 | * Perform any actions when refreshing an expired access token fails. |
| 416 | 434 | * |
| 417 | 435 | * @since 6.0.0 |
| @@ -432,8 +450,14 @@ | ||
| 432 | 450 | 'refresh_token' => $result['refresh_token'], |
| 433 | 451 | 'token_expires' => strtotime( '+' . $result['expires_in'] . ' seconds' ), |
| 434 | 452 | ); |
| 435 | 453 | |
| 454 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): Success' ); | |
| 455 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): New access_token = ' . $result['access_token'] ); | |
| 456 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): New refresh_token = ' . $result['refresh_token'] ); | |
| 457 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): New token_expires = ' . $result['token_expires'] ); | |
| 458 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: refresh_token(): New token_expires = ' . ( $result['token_expires'] && time() > (int) $result['token_expires'] ? 'expired ' . ( time() - (int) $result['token_expires'] ) . 's ago' : 'expires in ' . ( (int) $result['token_expires'] - time() ) . 's' ) ); | |
| 459 | + | |
| 436 | 460 | /** |
| 437 | 461 | * Perform any actions with the new access token, such as saving it. |
| 438 | 462 | * |
| 439 | 463 | * @since 6.0.0 |
| @@ -560,11 +584,14 @@ | ||
| 560 | 584 | // Return stored profiles if available and not forcing a refresh. |
| 561 | 585 | $option_name = $this->base->plugin->name . '-profiles-' . $account_id; |
| 562 | 586 | $profiles = get_option( $option_name ); |
| 563 | 587 | if ( ! $force && is_array( $profiles ) ) { |
| 588 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: profiles(): account=%s: returning %d cached profile(s).', $account_id, count( $profiles ) ) ); | |
| 564 | 589 | return $profiles; |
| 565 | 590 | } |
| 566 | 591 | |
| 592 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: profiles(): account=%s: fetching profiles from Buffer (force=%s).', $account_id, $force ? 'yes' : 'no' ) ); | |
| 593 | + | |
| 567 | 594 | // Build GraphQL query. |
| 568 | 595 | $query = ' |
| 569 | 596 | query GetChannels($organizationId: OrganizationId!) { |
| 570 | 597 | channels(input: { organizationId: $organizationId }) { |
| @@ -595,8 +622,9 @@ | ||
| 595 | 622 | ); |
| 596 | 623 | |
| 597 | 624 | // Check for errors. |
| 598 | 625 | if ( is_wp_error( $results ) ) { |
| 626 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: profiles(): account=%s: FAILED to fetch profiles: [%s] %s', $account_id, $results->get_error_code(), $results->get_error_message() ) ); | |
| 599 | 627 | return $results; |
| 600 | 628 | } |
| 601 | 629 | |
| 602 | 630 | // Build profiles array from results. |
| @@ -743,9 +771,9 @@ | ||
| 743 | 771 | switch ( $service ) { |
| 744 | 772 | |
| 745 | 773 | case 'instagram': |
| 746 | 774 | $metadata = array( |
| 747 | - 'type' => $params['post_type'] === 'story' ? 'story' : 'post', | |
| 775 | + 'type' => in_array( $params['post_type'], array( 'story', 'video_story' ), true ) ? 'story' : 'post', | |
| 748 | 776 | 'shouldShareToFeed' => true, |
| 749 | 777 | ); |
| 750 | 778 | |
| 751 | 779 | // First Comment. |
| @@ -952,8 +980,25 @@ | ||
| 952 | 980 | ), |
| 953 | 981 | ); |
| 954 | 982 | } |
| 955 | 983 | break; |
| 984 | + | |
| 985 | + case 'video': | |
| 986 | + case 'video_story': | |
| 987 | + // Bail if no video URL is defined. | |
| 988 | + if ( empty( $params['video_url'] ) ) { | |
| 989 | + break; | |
| 990 | + } | |
| 991 | + | |
| 992 | + // Buffer fetches the video from a public URL, so we only send the URL. | |
| 993 | + $assets = array( | |
| 994 | + array( | |
| 995 | + 'video' => array( | |
| 996 | + 'url' => $params['video_url'], | |
| 997 | + ), | |
| 998 | + ), | |
| 999 | + ); | |
| 1000 | + break; | |
| 956 | 1001 | } |
| 957 | 1002 | |
| 958 | 1003 | // Include assets. Always overwrites the default empty array |
| 959 | 1004 | // initialised above, if the service branch built any. |
| @@ -1073,10 +1118,19 @@ | ||
| 1073 | 1118 | * @return \WP_Error|array |
| 1074 | 1119 | */ |
| 1075 | 1120 | private function graphql_query( $query, $variables = array() ) { |
| 1076 | 1121 | |
| 1122 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): Started.' ); | |
| 1123 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): query = ' . $query ); | |
| 1124 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): variables = ' . print_r( $variables, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r | |
| 1125 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): access_token = ' . $this->access_token ); | |
| 1126 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): refresh_token = ' . $this->refresh_token ); | |
| 1127 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): token_expires = ' . $this->token_expires ); | |
| 1128 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): token_expires = ' . ( $this->token_expires && time() > (int) $this->token_expires ? 'expired ' . ( time() - (int) $this->token_expires ) . 's ago' : 'expires in ' . ( (int) $this->token_expires - time() ) . 's' ) ); | |
| 1129 | + | |
| 1077 | 1130 | // Check required parameters exist. |
| 1078 | 1131 | if ( empty( $this->access_token ) ) { |
| 1132 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): Error: No access token was specified' ); | |
| 1079 | 1133 | return new \WP_Error( 'missing_access_token', __( 'No access token was specified', 'wp-to-buffer' ) ); |
| 1080 | 1134 | } |
| 1081 | 1135 | |
| 1082 | 1136 | // Fetch a new access token and refresh token. |
| @@ -1083,11 +1137,17 @@ | ||
| 1083 | 1137 | $result = $this->refresh_token(); |
| 1084 | 1138 | |
| 1085 | 1139 | // Bail if something went wrong. |
| 1086 | 1140 | if ( is_wp_error( $result ) ) { |
| 1141 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): Error: ' . $result->get_error_message() ); | |
| 1087 | 1142 | return $result; |
| 1088 | 1143 | } |
| 1089 | 1144 | |
| 1145 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): access_token = ' . $this->access_token ); | |
| 1146 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): refresh_token = ' . $this->refresh_token ); | |
| 1147 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): token_expires = ' . $this->token_expires ); | |
| 1148 | + $this->base->get_class( 'log' )->add_to_debug_log( 'Buffer API: graphql_query(): token_expires = ' . ( $this->token_expires && time() > (int) $this->token_expires ? 'expired ' . ( time() - (int) $this->token_expires ) . 's ago' : 'expires in ' . ( (int) $this->token_expires - time() ) . 's' ) ); | |
| 1149 | + | |
| 1090 | 1150 | // Build body. |
| 1091 | 1151 | $body = array( 'query' => $query ); |
| 1092 | 1152 | if ( ! empty( $variables ) ) { |
| 1093 | 1153 | $body['variables'] = $variables; |
| @@ -1105,14 +1165,22 @@ | ||
| 1105 | 1165 | ); |
| 1106 | 1166 | |
| 1107 | 1167 | // If an error occured, return it now. |
| 1108 | 1168 | if ( is_wp_error( $result ) ) { |
| 1169 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: graphql_query(): Error: [%s] %s', $result->get_error_code(), $result->get_error_message() ) ); | |
| 1109 | 1170 | return $result; |
| 1110 | 1171 | } |
| 1111 | 1172 | |
| 1112 | - // Parse and return the response. | |
| 1113 | - return $this->parse_response( $result ); | |
| 1173 | + // Parse the response. | |
| 1174 | + $response = $this->parse_response( $result ); | |
| 1114 | 1175 | |
| 1176 | + // Log any API error, so failures that would otherwise be silent are captured. | |
| 1177 | + if ( is_wp_error( $response ) ) { | |
| 1178 | + $this->base->get_class( 'log' )->add_to_debug_log( sprintf( 'Buffer API: graphql_query(): API returned error: [%s] %s', $response->get_error_code(), $response->get_error_message() ) ); | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + return $response; | |
| 1182 | + | |
| 1115 | 1183 | } |
| 1116 | 1184 | |
| 1117 | 1185 | /** |
| 1118 | 1186 | * Returns the headers to use in an authenticated GraphQL API request. |
| @@ -1222,10 +1290,20 @@ | ||
| 1222 | 1290 | '403 Forbidden' |
| 1223 | 1291 | ); |
| 1224 | 1292 | } |
| 1225 | 1293 | |
| 1294 | + // Retain-and-retry on server errors: return without touching stored tokens. | |
| 1295 | + if ( $http_code >= 500 ) { | |
| 1296 | + return new \WP_Error( 'buffer_api_server_error', $http_code . ' server error' ); | |
| 1297 | + } | |
| 1298 | + | |
| 1226 | 1299 | // Decode response. |
| 1227 | 1300 | $body = json_decode( $http_body, true ); |
| 1301 | + | |
| 1302 | + // Bail if the response isn't valid JSON. | |
| 1303 | + if ( ! is_array( $body ) ) { | |
| 1304 | + return new \WP_Error( 'buffer_api_invalid_response', 'Invalid API response' ); | |
| 1305 | + } | |
| 1228 | 1306 | |
| 1229 | 1307 | // If an error is detected, return it. |
| 1230 | 1308 | if ( array_key_exists( 'error', $body ) ) { |
| 1231 | 1309 | return new \WP_Error( |