register_admin_menu();
}
);
add_action(
'admin_init',
function() {
$this->handle_actions();
}
);
}
/**
* Store response from an API request.
*
* @var string
*/
protected $response = '';
/**
* Store response from the integration status API request.
*
* @var string
*/
protected $integration_status_response = [];
/**
* Add menu entries
*/
protected function register_admin_menu() {
if ( apply_filters( 'woocommerce_gla_enable_connection_test', false ) ) {
add_menu_page(
'Connection Test',
'Connection Test',
'manage_woocommerce',
'connection-test-admin-page',
function () {
$this->render_admin_page();
}
);
} else {
add_submenu_page(
'',
'Connection Test',
'Connection Test',
'manage_woocommerce',
'connection-test-admin-page',
function () {
$this->render_admin_page();
}
);
}
}
/**
* Render the admin page.
*/
protected function render_admin_page() {
/** @var OptionsInterface $options */
$options = $this->container->get( OptionsInterface::class );
/** @var Manager $manager */
$manager = $this->container->get( Manager::class );
$blog_token = $manager->get_tokens()->get_access_token();
$user_token = $manager->get_tokens()->get_access_token( get_current_user_id() );
$user_data = $manager->get_connected_user_data( get_current_user_id() );
$url = admin_url( 'admin.php?page=connection-test-admin-page' );
if ( ! empty( $_GET['google-mc'] ) && 'connected' === $_GET['google-mc'] ) {
$this->response .= 'Google Account connected successfully.';
}
if ( ! empty( $_GET['google-manager'] ) && 'connected' === $_GET['google-manager'] ) {
$this->response .= 'Successfully connected a Google Manager account.';
}
if ( ! empty( $_GET['google'] ) && 'failed' === $_GET['google'] ) {
$this->response .= 'Failed to connect to Google.';
}
?>
Connection Test
Google for WooCommerce connection testing page used for debugging purposes. Debug responses are output at the top of the page.
response ) ) { ?>
WooCommerce Connect Server
WordPress.com
Google Account
Merchant Center
More Merchant Center
For single-step development testing, not used for normal account setup flow.
Google Ads
Terms of Service
Product Sync
container->get( OptionsInterface::class );
$wp_api_status = $options->get( OptionsInterface::WPCOM_REST_API_STATUS );
$notification_service = new NotificationsService( $this->container->get( MerchantCenterService::class ), $this->container->get( AccountService::class ) );
$notification_service->set_options_object( $options );
?>
Partner API Pull Integration
container->get( Manager::class );
if ( 'connect' === $_GET['action'] && check_admin_referer( 'connect' ) ) {
// Register the site to WPCOM.
if ( $manager->is_connected() ) {
$result = $manager->reconnect();
} else {
$result = $manager->register();
}
if ( is_wp_error( $result ) ) {
$this->response .= $result->get_error_message();
return;
}
// Get an authorization URL which will redirect back to our page.
$redirect = admin_url( 'admin.php?page=connection-test-admin-page' );
$auth_url = $manager->get_authorization_url( null, $redirect );
// Payments flow allows redirect back to the site without showing plans.
$auth_url = add_query_arg( [ 'from' => 'google-listings-and-ads' ], $auth_url );
// Using wp_redirect intentionally because we're redirecting outside.
wp_redirect( $auth_url ); // phpcs:ignore WordPress.Security.SafeRedirect
exit;
}
if ( 'disconnect' === $_GET['action'] && check_admin_referer( 'disconnect' ) ) {
$manager->remove_connection();
$plugin = $manager->get_plugin();
if ( $plugin && ! $plugin->is_only() ) {
$connected_plugins = $manager->get_connected_plugins();
$this->response = 'Cannot disconnect WordPress.com connection as there are other plugins using it: ';
$this->response .= implode( ', ', array_keys( $connected_plugins ) ) . "\n";
$this->response .= 'Please disconnect the connection using the Jetpack plugin.';
return;
} else {
$redirect = admin_url( 'admin.php?page=connection-test-admin-page' );
wp_safe_redirect( $redirect );
exit;
}
}
if ( 'wp-status' === $_GET['action'] && check_admin_referer( 'wp-status' ) ) {
$request = new Request( 'GET', '/wc/gla/jetpack/connected' );
$this->send_rest_request( $request );
/** @var OptionsInterface $options */
$options = $this->container->get( OptionsInterface::class );
$this->response .= "\n\n" . 'Saved Connection option = ' . ( $options->get( OptionsInterface::JETPACK_CONNECTED ) ? 'connected' : 'disconnected' );
$this->response .= "\n\n" . 'Connected plugins: ' . implode( ', ', array_column( $manager->get_connected_plugins(), 'name' ) ) . "\n";
}
if ( 'wcs-test' === $_GET['action'] && check_admin_referer( 'wcs-test' ) ) {
$url = $this->get_connect_server_url();
$this->response = 'GET ' . $url . "\n";
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) {
$this->response .= $response->get_error_message();
return;
}
$this->response .= wp_remote_retrieve_body( $response );
}
if ( 'partner-notification' === $_GET['action'] && check_admin_referer( 'partner-notification' ) ) {
if ( ! isset( $_GET['topic'] ) ) {
$this->response .= "\n Topic is required.";
return;
}
$item = $_GET['item_id'] ?? null;
$topic = $_GET['topic'];
$mc = $this->container->get( MerchantCenterService::class );
/** @var OptionsInterface $options */
$options = $this->container->get( OptionsInterface::class );
$service = new NotificationsService( $mc, $this->container->get( AccountService::class ) );
$service->set_options_object( $options );
if ( $service->notify( $topic, $item ) ) {
$this->response .= "\n Notification success. Item: " . $item . " - Topic: " . $topic;
} else {
$this->response .= "\n Notification failed. Item: " . $item . " - Topic: " . $topic;
}
return;
}
if ( 'partner-integration-status' === $_GET['action'] && check_admin_referer( 'partner-integration-status' ) ) {
$integration_status_args = [
'method' => 'GET',
'timeout' => 30,
'url' => 'https://public-api.wordpress.com/wpcom/v2/sites/' . Jetpack_Options::get_option( 'id' ) . '/wc/partners/google/remote-site-status',
'user_id' => get_current_user_id(),
];
$integration_remote_request_response = Client::remote_request( $integration_status_args, null );
if ( is_wp_error( $integration_remote_request_response ) ) {
$this->response .= $integration_remote_request_response->get_error_message();
} else {
$this->integration_status_response = json_decode( wp_remote_retrieve_body( $integration_remote_request_response ), true ) ?? [];
// If the merchant isn't connected to the Google App, it's not necessary to display an error indicating that the partner token isn't associated.
if ( ! $this->integration_status_response['is_partner_token_healthy'] && isset( $this->integration_status_response['errors'] ['rest_api_partner_token']['error_code'] ) && $this->integration_status_response['errors'] ['rest_api_partner_token']['error_code'] === 'wpcom_partner_token_not_associated' ) {
unset( $this->integration_status_response['errors'] ['rest_api_partner_token'] );
}
if ( json_last_error() || ! isset( $this->integration_status_response['site'] ) ) {
$this->response .= wp_remote_retrieve_body( $integration_remote_request_response );
}
}
}
if ( 'disconnect-wp-api' === $_GET['action'] && check_admin_referer( 'disconnect-wp-api' ) ) {
$request = new Request( 'DELETE', '/wc/gla/rest-api/authorize' );
$this->send_rest_request( $request );
}
if ( 'wcs-auth-test' === $_GET['action'] && check_admin_referer( 'wcs-auth-test' ) ) {
$url = trailingslashit( $this->get_connect_server_url() ) . 'connection/test';
$args = [
'headers' => [ 'Authorization' => $this->get_auth_header() ],
];
$this->response = 'GET ' . $url . "\n" . var_export( $args, true ) . "\n";
$response = wp_remote_get( $url, $args );
if ( is_wp_error( $response ) ) {
$this->response .= $response->get_error_message();
return;
}
$this->response .= wp_remote_retrieve_body( $response );
}
if ( 'wcs-google-manager' === $_GET['action'] && check_admin_referer( 'wcs-google-manager' ) ) {
if ( empty( $_GET['manager_id'] ) ) {
$this->response .= 'Manager ID must be set';
return;
}
$id = absint( $_GET['manager_id'] );
$url = trailingslashit( $this->get_connect_server_url() ) . 'google/connection/google-manager';
$args = [
'headers' => [ 'Authorization' => $this->get_auth_header() ],
'body' => [
'returnUrl' => admin_url( 'admin.php?page=connection-test-admin-page' ),
'managerId' => $id,
'countries' => 'US,CA',
],
];
$this->response = 'POST ' . $url . "\n" . var_export( $args, true ) . "\n";
$response = wp_remote_post( $url, $args );
if ( is_wp_error( $response ) ) {
$this->response .= $response->get_error_message();
return;
}
$this->response .= wp_remote_retrieve_body( $response );
$json = json_decode( wp_remote_retrieve_body( $response ), true );
if ( $json && isset( $json['oauthUrl'] ) ) {
wp_redirect( $json['oauthUrl'] ); // phpcs:ignore WordPress.Security.SafeRedirect
exit;
}
}
if ( 'wcs-google-ads-setup' === $_GET['action'] && check_admin_referer( 'wcs-google-ads-setup' ) ) {
$request = new Request( 'POST', '/wc/gla/ads/accounts' );
if ( is_numeric( $_GET['ads_id'] ?? false ) ) {
$request->set_body_params( [ 'id' => absint( $_GET['ads_id'] ) ] );
}
$this->send_rest_request( $request );
}
if ( 'wcs-google-ads-check' === $_GET['action'] && check_admin_referer( 'wcs-google-ads-check' ) ) {
$request = new Request( 'GET', '/wc/gla/ads/connection' );
$this->send_rest_request( $request );
}
if ( 'wcs-google-ads-disconnect' === $_GET['action'] && check_admin_referer( 'wcs-google-ads-disconnect' ) ) {
$request = new Request( 'DELETE', '/wc/gla/ads/connection' );
$this->send_rest_request( $request );
}
if ( 'wcs-google-mc' === $_GET['action'] && check_admin_referer( 'wcs-google-mc' ) ) {
/** @var Connection $connection */
$connection = $this->container->get( Connection::class );
$redirect_url = $connection->connect( admin_url( 'admin.php?page=connection-test-admin-page' ) );
if ( ! empty( $redirect_url ) ) {
wp_redirect( $redirect_url ); // phpcs:ignore WordPress.Security.SafeRedirect
exit;
}
}
if ( 'wcs-google-mc-disconnect' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-disconnect' ) ) {
/** @var Connection $connection */
$connection = $this->container->get( Connection::class );
$response = $connection->disconnect();
$this->response .= $response;
}
if ( 'wcs-google-sv-link' === $_GET['action'] && check_admin_referer( 'wcs-google-sv-link' ) ) {
try {
if ( $this->container->get( Middleware::class )->link_merchant_to_mca() ) {
$this->response .= "Linked merchant to MCA\n";
}
} catch ( \Exception $e ) {
$this->response .= $e->getMessage();
}
}
if ( 'wcs-google-mc-setup' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-setup' ) ) {
add_filter(
'woocommerce_gla_site_url',
function( $url ) {
return isset( $_GET['site_url'] ) ? esc_url_raw( $_GET['site_url'] ) : $url;
}
);
$request = new Request( 'POST', '/wc/gla/mc/accounts' );
if ( is_numeric( $_GET['account_id'] ?? false ) ) {
$request->set_body_params( [ 'id' => $_GET['account_id'] ] );
}
$this->send_rest_request( $request );
}
if ( 'wcs-google-mc-claim-overwrite' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-claim-overwrite' ) ) {
$request = new Request( 'POST', '/wc/gla/mc/accounts/claim-overwrite' );
if ( is_numeric( $_GET['account_id'] ?? false ) ) {
$request->set_body_params( [ 'id' => $_GET['account_id'] ] );
}
$this->send_rest_request( $request );
}
if ( 'wcs-google-mc-switch-url' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-switch-url' ) ) {
$request = new Request( 'POST', '/wc/gla/mc/accounts/switch-url' );
if ( is_numeric( $_GET['account_id'] ?? false ) ) {
$request->set_body_params( [ 'id' => $_GET['account_id'] ] );
}
$this->send_rest_request( $request );
}
if ( 'clear-mc-status-cache' === $_GET['action'] && check_admin_referer( 'clear-mc-status-cache' ) ) {
$this->container->get( MerchantStatuses::class )->clear_cache();
$this->response .= 'Merchant Center statuses transient successfully deleted.';
}
if ( 'wcs-google-accounts-check' === $_GET['action'] && check_admin_referer( 'wcs-google-accounts-check' ) ) {
$request = new Request( 'GET', '/wc/gla/mc/connection' );
$this->send_rest_request( $request );
}
if ( 'wcs-google-accounts-delete' === $_GET['action'] && check_admin_referer( 'wcs-google-accounts-delete' ) ) {
$request = new Request( 'DELETE', '/wc/gla/mc/connection' );
$this->send_rest_request( $request );
}
if ( 'wcs-google-accounts-claim' === $_GET['action'] && check_admin_referer( 'wcs-google-accounts-claim' ) ) {
add_filter(
'woocommerce_gla_site_url',
function ( $url ) {
return isset( $_GET['site_url'] ) ? esc_url_raw( $_GET['site_url'] ) : $url;
}
);
try {
$this->container->get( Merchant::class )->claimwebsite();
$this->response .= 'Website claimed';
} catch ( \Exception $e ) {
$this->response .= 'Error: ' . $e->getMessage();
}
}
if ( 'wcs-google-mc-status' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-status' ) ) {
$url = trailingslashit( $this->get_connect_server_url() ) . 'google/connection/google-mc';
$args = [
'headers' => [ 'Authorization' => $this->get_auth_header() ],
'method' => 'GET',
];
$this->response = 'GET ' . $url . "\n" . var_export( $args, true ) . "\n";
$response = wp_remote_get( $url, $args );
if ( is_wp_error( $response ) ) {
$this->response .= $response->get_error_message();
return;
}
$this->response .= wp_remote_retrieve_body( $response );
}
if ( 'wcs-google-mc-id' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-id' ) ) {
try {
$this->response = 'Proxied request > get merchant ID' . "\n";
foreach ( $this->container->get( Middleware::class )->get_merchant_accounts() as $account ) {
$this->response .= sprintf(
"Merchant ID: %s%s\n",
$account['id'],
$account['subaccount'] ? ' (IS a subaccount)' : ''
);
$_GET['merchant_id'] = $account['id'];
}
} catch ( \Exception $e ) {
$this->response .= $e->getMessage();
}
}
if ( 'wcs-google-mc-proxy' === $_GET['action'] && check_admin_referer( 'wcs-google-mc-proxy' ) ) {
/** @var Merchant $merchant */
$merchant = $this->container->get( Merchant::class );
/** @var OptionsInterface $options */
$options = $this->container->get( OptionsInterface::class );
if ( empty( $options->get_merchant_id() ) ) {
$this->response .= 'Please enter a Merchant ID';
return;
}
$this->response = "Proxied request > get products for merchant {$options->get_merchant_id()}\n";
$products = $merchant->get_products();
if ( empty( $products ) ) {
$this->response .= 'No products found';
}
foreach ( $products as $product ) {
$this->response .= "{$product->getId()} {$product->getTitle()}\n";
}
}
if ( 'wcs-ads-customers-lib' === $_GET['action'] && check_admin_referer( 'wcs-ads-customers-lib' ) ) {
try {
$accounts = $this->container->get( Ads::class )->get_ads_accounts();
$this->response .= 'Total accounts: ' . count( $accounts ) . "\n";
foreach ( $accounts as $account ) {
$this->response .= sprintf( "%d : %s\n", $account['id'], $account['name'] );
$_GET['customer_id'] = $account['id'];
}
} catch ( \Exception $e ) {
$this->response .= 'Error: ' . $e->getMessage();
}
}
if ( 'wcs-ads-campaign-lib' === $_GET['action'] && check_admin_referer( 'wcs-ads-campaign-lib' ) ) {
try {
/** @var AdsCampaign $ads_campaign */
$ads_campaign = $this->container->get( AdsCampaign::class );
/** @var OptionsInterface $options */
$options = $this->container->get( OptionsInterface::class );
$this->response = "Proxied request > get ad campaigns {$options->get_ads_id()}\n";
$campaigns = $ads_campaign->get_campaigns();
if ( empty( $campaigns ) ) {
$this->response .= 'No campaigns found';
} else {
$this->response .= 'Total campaigns: ' . count( $campaigns ) . "\n";
foreach ( $campaigns as $campaign ) {
$this->response .= print_r( $campaign, true ) . "\n";
}
}
} catch ( \Exception $e ) {
$this->response .= 'Error: ' . $e->getMessage();
}
}
if ( 'wcs-accept-tos' === $_GET['action'] && check_admin_referer( 'wcs-accept-tos' ) ) {
$result = $this->container->get( Middleware::class )->mark_tos_accepted( 'google-mc', 'john.doe@example.com' );
$this->response .= sprintf(
'Attempting to accept Tos. Successful? %s
Response body: %s',
$result->accepted() ? 'Yes' : 'No',
$result->message()
);
}
if ( 'wcs-check-tos' === $_GET['action'] && check_admin_referer( 'wcs-check-tos' ) ) {
$accepted = $this->container->get( Middleware::class )->check_tos_accepted( 'google-mc' );
$this->response .= sprintf(
'Tos Accepted? %s
Response body: %s',
$accepted->accepted() ? 'Yes' : 'No',
$accepted->message()
);
}
if ( 'wcs-sync-product' === $_GET['action'] && check_admin_referer( 'wcs-sync-product' ) ) {
if ( empty( $_GET['product_id'] ) ) {
$this->response .= 'Please enter a Product ID';
return;
}
$id = absint( $_GET['product_id'] );
$product = wc_get_product( $id );
if ( $product instanceof \WC_Product ) {
if ( empty( $_GET['async'] ) ) {
/** @var ProductSyncer $product_syncer */
$product_syncer = $this->container->get( ProductSyncer::class );
try {
$result = $product_syncer->update( [ $product ] );
$this->response .= sprintf( '%s products successfully submitted to Google.', count( $result->get_products() ) ) . "\n";
if ( ! empty( $result->get_errors() ) ) {
$this->response .= sprintf( 'There were %s errors:', count( $result->get_errors() ) ) . "\n";
foreach ( $result->get_errors() as $invalid_product ) {
$this->response .= sprintf( "%s:\n%s", $invalid_product->get_wc_product_id(), implode( "\n", $invalid_product->get_errors() ) ) . "\n";
}
}
} catch ( ProductSyncerException $exception ) {
$this->response = 'Error submitting product to Google: ' . $exception->getMessage();
}
} else {
// schedule a job
/** @var UpdateProducts $update_job */
$update_job = $this->container->get( JobRepository::class )->get( UpdateProducts::class );
$update_job->schedule( [ [ $product->get_id() ] ] );
$this->response = 'Successfully scheduled a job to sync the product ' . $product->get_id();
}
} else {
$this->response = 'Invalid product ID provided: ' . $id;
}
}
if ( 'wcs-sync-all-products' === $_GET['action'] && check_admin_referer( 'wcs-sync-all-products' ) ) {
if ( empty( $_GET['async'] ) ) {
/** @var ProductSyncer $product_syncer */
$product_syncer = $this->container->get( ProductSyncer::class );
/** @var ProductRepository $product_repository */
$product_repository = $this->container->get( ProductRepository::class );
try {
$products = $product_repository->find_sync_ready_products()->get();
$result = $product_syncer->update( $products );
$this->response .= sprintf( '%s products successfully submitted to Google.', count( $result->get_products() ) ) . "\n";
if ( ! empty( $result->get_errors() ) ) {
$this->response .= sprintf( 'There were %s errors:', count( $result->get_errors() ) ) . "\n";
foreach ( $result->get_errors() as $invalid_product ) {
$this->response .= sprintf( "%s:\n%s", $invalid_product->get_wc_product_id(), implode( "\n", $invalid_product->get_errors() ) ) . "\n";
}
}
} catch ( ProductSyncerException $exception ) {
$this->response = 'Error submitting products to Google: ' . $exception->getMessage();
}
} else {
// schedule a job
/** @var UpdateAllProducts $update_job */
$update_job = $this->container->get( JobRepository::class )->get( UpdateAllProducts::class );
$update_job->schedule();
$this->response = 'Successfully scheduled a job to sync all products!';
}
}
if ( 'wcs-delete-synced-products' === $_GET['action'] && check_admin_referer( 'wcs-delete-synced-products' ) ) {
if ( empty( $_GET['async'] ) ) {
/** @var ProductSyncer $product_syncer */
$product_syncer = $this->container->get( ProductSyncer::class );
/** @var ProductRepository $product_repository */
$product_repository = $this->container->get( ProductRepository::class );
try {
$products = $product_repository->find_synced_products();
$result = $product_syncer->delete( $products );
$this->response .= sprintf( '%s synced products deleted from Google.', count( $result->get_products() ) ) . "\n";
if ( ! empty( $result->get_errors() ) ) {
$this->response .= sprintf( 'There were %s errors:', count( $result->get_errors() ) ) . "\n";
foreach ( $result->get_errors() as $invalid_product ) {
$this->response .= sprintf( "%s:\n%s", $invalid_product->get_wc_product_id(), implode( "\n", $invalid_product->get_errors() ) ) . "\n";
}
}
} catch ( ProductSyncerException $exception ) {
$this->response = 'Error deleting products from Google: ' . $exception->getMessage();
}
} else {
// schedule a job
/** @var DeleteAllProducts $delete_job */
$delete_job = $this->container->get( JobRepository::class )->get( DeleteAllProducts::class );
$delete_job->schedule();
$this->response = 'Successfully scheduled a job to delete all synced products!';
}
}
if ( 'wcs-cleanup-products' === $_GET['action'] && check_admin_referer( 'wcs-cleanup-products' ) ) {
if ( empty( $_GET['async'] ) ) {
/** @var ProductSyncer $product_syncer */
$product_syncer = $this->container->get( ProductSyncer::class );
/** @var ProductRepository $product_repository */
$product_repository = $this->container->get( ProductRepository::class );
/** @var BatchProductHelper $batch_product_helper */
$batch_product_helper = $this->container->get( BatchProductHelper::class );
try {
$products = $product_repository->find_synced_products();
$stale_entries = $batch_product_helper->generate_stale_products_request_entries( $products );
$result = $product_syncer->delete_by_batch_requests( $stale_entries );
$this->response .= sprintf( '%s products cleaned up.', count( $result->get_products() ) ) . "\n";
if ( ! empty( $result->get_errors() ) ) {
$this->response .= sprintf( 'There were %s errors:', count( $result->get_errors() ) ) . "\n";
foreach ( $result->get_errors() as $invalid_product ) {
$this->response .= sprintf( "%s:\n%s", $invalid_product->get_wc_product_id(), implode( "\n", $invalid_product->get_errors() ) ) . "\n";
}
}
} catch ( ProductSyncerException $exception ) {
$this->response = 'Error cleaning up products: ' . $exception->getMessage();
}
} else {
// schedule a job
/** @var CleanupProductsJob $delete_job */
$delete_job = $this->container->get( JobRepository::class )->get( CleanupProductsJob::class );
$delete_job->schedule();
$this->response = 'Successfully scheduled a job to cleanup all products!';
}
}
if ( 'migrate-gtin' === $_GET['action'] && check_admin_referer( 'migrate-gtin' ) ) {
/** @var MigrateGTIN $job */
$job = $this->container->get( JobRepository::class )->get( MigrateGTIN::class );
$job->schedule();
$this->response = 'Successfully scheduled a job to migrate GTIN';
}
}
/**
* Retrieve an authorization header containing a Jetpack token.
*
* @return string Authorization header.
*/
private function get_auth_header(): string {
/** @var Manager $manager */
$manager = $this->container->get( Manager::class );
$token = $manager->get_tokens()->get_access_token();
[ $token_key, $token_secret ] = explode( '.', $token->secret );
$token_key = sprintf( '%s:%d:%d', $token_key, defined( 'JETPACK__API_VERSION' ) ? JETPACK__API_VERSION : 1, $token->external_user_id );
$time_diff = (int) Jetpack_Options::get_option( 'time_diff' );
$timestamp = time() + $time_diff;
$nonce = wp_generate_password( 10, false );
$normalized_request_string = join( "\n", [ $token_key, $timestamp, $nonce ] ) . "\n";
$signature = base64_encode( hash_hmac( 'sha1', $normalized_request_string, $token_secret, true ) );
$auth = [
'token' => $token_key,
'timestamp' => $timestamp,
'nonce' => $nonce,
'signature' => $signature,
];
$header_pieces = [];
foreach ( $auth as $key => $value ) {
$header_pieces[] = sprintf( '%s="%s"', $key, $value );
}
return 'X_JP_Auth ' . join( ' ', $header_pieces );
}
/**
* Send a REST API request and add the response to our buffer.
*/
private function send_rest_request( Request $request ) {
$response = rest_do_request( $request );
$server = rest_get_server();
$data = $server->response_to_data( $response, false );
$json = wp_json_encode( $data, JSON_PRETTY_PRINT );
$this->response .= 'Request: ' . $request->get_method() . ' ' . $request->get_route() . PHP_EOL;
$this->response .= 'Status: ' . $response->get_status() . PHP_EOL;
$this->response .= 'Response: ' . $json;
return $data;
}
}