get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching "SELECT consumer_secret FROM {$wpdb->prefix}woocommerce_api_keys WHERE description LIKE %s ORDER BY key_id DESC LIMIT 1", chargebacks911_key_description_like() )); return is_string($secret) ? $secret : ''; } /** LIKE pattern for the descriptions wc-auth gives this app's keys: " - API ()". */ function chargebacks911_key_description_like(): string { global $wpdb; return $wpdb->esc_like(sanitize_text_field(chargebacks911_setting('appname')).' - API (').'%'; } /** * Drop empty values (Laravel reads them as null) and add Shopify-style `hmac` once the store has connected. * * @param array $params * @return array */ function chargebacks911_signed(array $params): array { $params = array_filter($params, static fn (string $value): bool => $value !== ''); ksort($params); $secret = chargebacks911_signing_secret(); if ($secret !== '') { $params['hmac'] = hash_hmac('sha256', http_build_query($params, '', '&', PHP_QUERY_RFC3986), $secret); } return $params; } /** Refuse activation without WooCommerce 8.4+; chargebacks911_require_woocommerce() finishes it. */ function chargebacks911_activate(): void { if (! chargebacks911_woocommerce_ready()) { set_transient('chargebacks911_activation_refused', true, MINUTE_IN_SECONDS); } } /** Uninstall the app (signed, best effort), then delete this app's wc-auth keys. */ function chargebacks911_deactivate(): void { global $wpdb; chargebacks911_lifecycle_event('uninstall'); $wpdb->query($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching "DELETE FROM {$wpdb->prefix}woocommerce_api_keys WHERE description LIKE %s", chargebacks911_key_description_like() )); } /** * Report a signed plugin lifecycle event ("uninstall"); best effort, so WordPress never blocks on the backend. * * @return array{ok: bool, status: int, error: string} */ function chargebacks911_lifecycle_event(string $event): array { if (! chargebacks911_backend_configured()) { return ['ok' => false, 'status' => 0, 'error' => 'Backend connection is not configured.']; } if (chargebacks911_shop() === '') { return ['ok' => false, 'status' => 0, 'error' => 'WooCommerce store ID is missing.']; } $body = chargebacks911_signed([ 'app' => chargebacks911_setting('app'), 'shop' => chargebacks911_shop(), 'timestamp' => (string) time(), ]); if (! isset($body['hmac'])) { return ['ok' => false, 'status' => 0, 'error' => 'The store never connected.']; } $response = wp_remote_post(rtrim(chargebacks911_setting('app_url'), '/').'/api/marketplace/'.$event.'?marketplace=woocommerce', [ 'timeout' => 15, 'headers' => [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'X-REQUEST-ID' => 'woocommerce-'.$event.'-'.wp_generate_uuid4(), ], 'body' => wp_json_encode($body), ]); if (is_wp_error($response)) { return ['ok' => false, 'status' => 0, 'error' => $response->get_error_message()]; } $status = (int) wp_remote_retrieve_response_code($response); return ['ok' => $status >= 200 && $status < 300, 'status' => $status, 'error' => '']; }