Skip to content

Commit 8623cf3

Browse files
committed
Refactor test webhook
1 parent a615ec4 commit 8623cf3

File tree

3 files changed

+338
-67
lines changed

3 files changed

+338
-67
lines changed

plugins/wp-graphql-headless-webhooks/src/Admin/WebhooksAdmin.php

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public function init(): void {
4545

4646
// Register admin-post.php handlers
4747
add_action( 'admin_post_graphql_webhook_save', array( $this, 'handle_webhook_save' ) );
48+
49+
// Register AJAX handlers
50+
add_action( 'wp_ajax_test_webhook', array( $this, 'handle_test_webhook' ) );
4851
}
4952

5053
/**
@@ -79,7 +82,8 @@ public function get_admin_url( array $args = array() ): string {
7982
* @param string $hook_suffix Current admin page.
8083
*/
8184
public function enqueue_assets( string $hook_suffix ): void {
82-
if ( 'graphql_page_' . self::ADMIN_PAGE_SLUG !== $hook_suffix ) {
85+
// Only load on our admin page - check if we're on the webhooks page
86+
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== self::ADMIN_PAGE_SLUG ) {
8387
return;
8488
}
8589

@@ -106,6 +110,7 @@ public function enqueue_assets( string $hook_suffix ): void {
106110
array(
107111
'restUrl' => rest_url( 'graphql-webhooks/v1/' ),
108112
'nonce' => wp_create_nonce( 'wp_rest' ),
113+
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
109114
'headerTemplate' => $this->get_header_row_template(),
110115
'confirmDelete' => __( 'Are you sure you want to delete this webhook?', 'wp-graphql-headless-webhooks' ),
111116
)
@@ -225,6 +230,155 @@ public function handle_webhook_delete(): void {
225230
exit;
226231
}
227232

233+
/**
234+
* Handle webhook test via AJAX
235+
*/
236+
public function handle_test_webhook(): void {
237+
// Verify nonce
238+
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'wp_rest' ) ) {
239+
wp_send_json_error( __( 'Security check failed.', 'wp-graphql-headless-webhooks' ) );
240+
}
241+
242+
// Verify permissions
243+
if ( ! current_user_can( 'manage_options' ) ) {
244+
wp_send_json_error( __( 'Insufficient permissions.', 'wp-graphql-headless-webhooks' ) );
245+
}
246+
247+
$webhook_id = isset( $_POST['webhook_id'] ) ? intval( $_POST['webhook_id'] ) : 0;
248+
if ( ! $webhook_id ) {
249+
wp_send_json_error( __( 'Invalid webhook ID.', 'wp-graphql-headless-webhooks' ) );
250+
}
251+
252+
// Get the webhook
253+
$webhook = $this->repository->get( $webhook_id );
254+
if ( ! $webhook ) {
255+
wp_send_json_error( __( 'Webhook not found.', 'wp-graphql-headless-webhooks' ) );
256+
}
257+
258+
// Create test payload based on the event type
259+
$test_payload = $this->get_test_payload_for_event( $webhook->event );
260+
261+
// Send the webhook using a synchronous request for testing
262+
$args = [
263+
'headers' => $webhook->headers ?: [ 'Content-Type' => 'application/json' ],
264+
'timeout' => 10,
265+
'blocking' => true, // We need blocking for test to get response
266+
];
267+
268+
$payload = apply_filters( 'graphql_webhooks_payload', $test_payload, $webhook );
269+
270+
if ( strtoupper( $webhook->method ) === 'GET' ) {
271+
$url = add_query_arg( $payload, $webhook->url );
272+
$args['method'] = 'GET';
273+
} else {
274+
$url = $webhook->url;
275+
$args['method'] = strtoupper( $webhook->method );
276+
$args['body'] = wp_json_encode( $payload );
277+
if ( empty( $args['headers']['Content-Type'] ) ) {
278+
$args['headers']['Content-Type'] = 'application/json';
279+
}
280+
}
281+
282+
$response = wp_remote_request( $url, $args );
283+
284+
if ( is_wp_error( $response ) ) {
285+
wp_send_json_error( $response->get_error_message() );
286+
}
287+
288+
// Get response details
289+
$response_code = wp_remote_retrieve_response_code( $response );
290+
$response_body = wp_remote_retrieve_body( $response );
291+
292+
// Strip HTML tags from response body to remove any links
293+
$response_body = wp_strip_all_tags( $response_body );
294+
295+
$message = sprintf(
296+
__( 'Webhook sent successfully!\n\nResponse Code: %d\nResponse Body: %s', 'wp-graphql-headless-webhooks' ),
297+
$response_code,
298+
substr( $response_body, 0, 200 ) // Limit response body to 200 chars
299+
);
300+
301+
wp_send_json_success( array( 'message' => $message ) );
302+
}
303+
304+
/**
305+
* Get test payload for a specific event
306+
*
307+
* @param string $event Event type.
308+
* @return array
309+
*/
310+
private function get_test_payload_for_event( string $event ): array {
311+
$base_payload = array(
312+
'event' => $event,
313+
'timestamp' => current_time( 'mysql' ),
314+
'test' => true,
315+
'test_mode' => true, // Additional flag to clearly indicate test mode
316+
'message' => 'This is a TEST webhook payload - no production data was affected',
317+
);
318+
319+
// Add event-specific test data
320+
switch ( $event ) {
321+
case 'smart_cache_created':
322+
case 'smart_cache_updated':
323+
case 'smart_cache_deleted':
324+
$base_payload['data'] = array(
325+
'key' => 'test:post:999999',
326+
'action' => str_replace( 'smart_cache_', '', $event ),
327+
'purge_url' => home_url( '/test-graphql-endpoint' ),
328+
'test_note' => 'This is test data - no actual cache was purged',
329+
);
330+
break;
331+
332+
case 'smart_cache_nodes_purged':
333+
$base_payload['data'] = array(
334+
'key' => 'test:list:post',
335+
'nodes' => array(
336+
array( 'id' => 'test_node_1', 'type' => 'post' ),
337+
array( 'id' => 'test_node_2', 'type' => 'term' ),
338+
),
339+
'test_note' => 'This is test data - no actual nodes were purged',
340+
);
341+
break;
342+
343+
case 'post.published':
344+
case 'post.updated':
345+
case 'post.deleted':
346+
$base_payload['data'] = array(
347+
'id' => 999999,
348+
'title' => 'Test Post (Not Real)',
349+
'status' => 'test',
350+
'author' => 0,
351+
'test_note' => 'This is test data - no actual post exists',
352+
);
353+
break;
354+
355+
case 'user.created':
356+
$base_payload['data'] = array(
357+
'id' => 999999,
358+
'username' => 'test_webhook_user',
359+
'email' => '[email protected]',
360+
'role' => 'test',
361+
'test_note' => 'This is test data - no actual user exists',
362+
);
363+
break;
364+
365+
default:
366+
$base_payload['data'] = array(
367+
'message' => 'This is a test webhook payload',
368+
'test_note' => 'This is test data for event: ' . $event,
369+
);
370+
break;
371+
}
372+
373+
/**
374+
* Filter the test payload for webhook testing
375+
*
376+
* @param array $base_payload The test payload data
377+
* @param string $event The event type being tested
378+
*/
379+
return apply_filters( 'graphql_webhooks_test_payload', $base_payload, $event );
380+
}
381+
228382
/**
229383
* Render admin page
230384
*/

plugins/wp-graphql-headless-webhooks/src/Admin/assets/admin.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
flex-shrink: 0;
2020
}
2121

22+
.webhook-header-row button.remove-header:hover {
23+
background: #d63638;
24+
color: #fff;
25+
}
26+
2227
/* Add some spacing */
2328
#webhook-headers {
2429
margin-bottom: 10px;
@@ -34,6 +39,21 @@
3439
cursor: pointer;
3540
}
3641

42+
/* Test webhook button states */
43+
.test-webhook.testing {
44+
color: #3858e9;
45+
cursor: not-allowed;
46+
pointer-events: none;
47+
}
48+
49+
.test-webhook.success {
50+
color: #00a32a;
51+
}
52+
53+
.test-webhook.error {
54+
color: #d63638;
55+
}
56+
3757
/* Webhooks table column widths */
3858
.wp-list-table.webhooks-table .column-event {
3959
width: 15%;

0 commit comments

Comments
 (0)