Skip to content

Commit 3e1c4ee

Browse files
committed
Smart cache integration
1 parent 85322c8 commit 3e1c4ee

File tree

3 files changed

+221
-0
lines changed

3 files changed

+221
-0
lines changed

plugins/wp-graphql-headless-webhooks/src/Events/WebhookEventManager.php

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public function register_hooks(): void {
4747
add_action( 'delete_attachment', [ $this, 'on_media_deleted' ], 10, 1 );
4848
add_action( 'wp_insert_comment', [ $this, 'on_comment_inserted' ], 10, 2 );
4949
add_action( 'transition_comment_status', [ $this, 'on_comment_status' ], 10, 3 );
50+
51+
// Smart Cache integration
52+
add_action( 'graphql_purge', [ $this, 'on_graphql_purge' ], 10, 3 );
53+
add_action( 'wpgraphql_cache_purge_nodes', [ $this, 'on_cache_purge_nodes' ], 10, 2 );
5054
}
5155

5256
/**
@@ -179,4 +183,121 @@ public function on_comment_status( $new_status, $old_status, $comment ) {
179183
'new_status' => $new_status,
180184
] );
181185
}
186+
187+
/**
188+
* Handle WPGraphQL Smart Cache purge events
189+
*
190+
* @param string $key Cache key being purged
191+
* @param string $event Event type (e.g., post_UPDATE)
192+
* @param string $graphql_endpoint GraphQL endpoint URL
193+
*/
194+
public function on_graphql_purge( $key, $event, $graphql_endpoint ) {
195+
// Parse the event to extract post type and action
196+
$event_parts = explode( '_', $event );
197+
if ( count( $event_parts ) !== 2 ) {
198+
return;
199+
}
200+
201+
$post_type = $event_parts[0];
202+
$action = strtolower( $event_parts[1] );
203+
204+
// Map Smart Cache actions to our webhook events
205+
$event_map = [
206+
'create' => 'smart_cache_created',
207+
'update' => 'smart_cache_updated',
208+
'delete' => 'smart_cache_deleted',
209+
];
210+
211+
if ( ! isset( $event_map[ $action ] ) ) {
212+
return;
213+
}
214+
215+
$webhook_event = $event_map[ $action ];
216+
217+
// Build payload with decoded information
218+
$payload = [
219+
'cache_key' => $key,
220+
'key_type' => $this->classify_cache_key( $key ),
221+
'post_type' => $post_type,
222+
'action' => $action,
223+
'graphql_endpoint' => $graphql_endpoint,
224+
'timestamp' => current_time( 'c' ),
225+
];
226+
227+
// Try to decode the key if it's a Relay global ID
228+
if ( class_exists( '\GraphQLRelay\Relay' ) ) {
229+
try {
230+
$decoded = \GraphQLRelay\Relay::fromGlobalId( $key );
231+
if ( ! empty( $decoded['type'] ) && ! empty( $decoded['id'] ) ) {
232+
$payload['decoded_key'] = $decoded;
233+
$payload['object_id'] = absint( $decoded['id'] );
234+
235+
// Add object details based on type
236+
if ( $decoded['type'] === 'post' && $action !== 'delete' ) {
237+
$post = get_post( $decoded['id'] );
238+
if ( $post ) {
239+
$payload['object'] = [
240+
'id' => $post->ID,
241+
'title' => $post->post_title,
242+
'status' => $post->post_status,
243+
'type' => $post->post_type,
244+
'url' => get_permalink( $post ),
245+
];
246+
}
247+
}
248+
}
249+
} catch ( \Exception $e ) {
250+
// Not a valid Relay ID, continue without decoding
251+
}
252+
}
253+
254+
$this->trigger_webhooks( $webhook_event, $payload );
255+
}
256+
257+
/**
258+
* Handle WPGraphQL cache purge nodes event
259+
*
260+
* @param string $key Cache key
261+
* @param array $nodes Nodes being purged
262+
*/
263+
public function on_cache_purge_nodes( $key, $nodes ) {
264+
$payload = [
265+
'cache_key' => $key,
266+
'nodes' => $nodes,
267+
'nodes_count' => count( $nodes ),
268+
'timestamp' => current_time( 'c' ),
269+
];
270+
271+
$this->trigger_webhooks( 'smart_cache_nodes_purged', $payload );
272+
}
273+
274+
/**
275+
* Classify the type of cache key
276+
*
277+
* @param string $key Cache key
278+
* @return string
279+
*/
280+
private function classify_cache_key( string $key ): string {
281+
if ( strpos( $key, 'list:' ) === 0 ) {
282+
return 'list';
283+
}
284+
285+
if ( strpos( $key, 'skipped:' ) === 0 ) {
286+
return 'skipped';
287+
}
288+
289+
// Check if it's a Relay ID
290+
if ( class_exists( '\GraphQLRelay\Relay' ) ) {
291+
try {
292+
$decoded = \GraphQLRelay\Relay::fromGlobalId( $key );
293+
if ( ! empty( $decoded['type'] ) && ! empty( $decoded['id'] ) ) {
294+
return 'relay_id';
295+
}
296+
} catch ( \Exception $e ) {
297+
// Not a valid Relay ID
298+
}
299+
}
300+
301+
return 'unknown';
302+
}
182303
}

plugins/wp-graphql-headless-webhooks/src/Repository/WebhookRepository.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class WebhookRepository implements WebhookRepositoryInterface {
4242
'media_deleted' => 'Media Deleted',
4343
'comment_inserted' => 'Comment Inserted',
4444
'comment_status' => 'Comment Status Changed',
45+
// Smart Cache events
46+
'smart_cache_created' => 'Smart Cache - Content Created',
47+
'smart_cache_updated' => 'Smart Cache - Content Updated',
48+
'smart_cache_deleted' => 'Smart Cache - Content Deleted',
49+
'smart_cache_nodes_purged' => 'Smart Cache - Nodes Purged',
4550
];
4651

4752
/**
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
/**
3+
* Test file for Smart Cache webhook integration
4+
*
5+
* This file demonstrates how to test the Smart Cache events with webhooks.
6+
* Place this in your WordPress installation and run it to see the integration in action.
7+
*/
8+
9+
// Add this to your theme's functions.php or a custom plugin to test
10+
11+
add_action( 'init', function() {
12+
// Only run this test if explicitly requested via URL parameter
13+
if ( ! isset( $_GET['test_smart_cache_webhooks'] ) ) {
14+
return;
15+
}
16+
17+
// Security check
18+
if ( ! current_user_can( 'manage_options' ) ) {
19+
wp_die( 'Unauthorized' );
20+
}
21+
22+
echo '<h1>Smart Cache Webhook Integration Test</h1>';
23+
echo '<pre>';
24+
25+
// Test 1: Simulate a graphql_purge event for post creation
26+
echo "Test 1: Simulating post CREATE event\n";
27+
echo "=====================================\n";
28+
29+
do_action( 'graphql_purge', 'list:post', 'post_CREATE', 'mysite.local/graphql' );
30+
echo "✓ Triggered: graphql_purge with list:post key\n\n";
31+
32+
// Test 2: Simulate a graphql_purge event for post update with Relay ID
33+
echo "Test 2: Simulating post UPDATE event with Relay ID\n";
34+
echo "==================================================\n";
35+
36+
// Create a test post first
37+
$post_id = wp_insert_post([
38+
'post_title' => 'Test Post for Smart Cache',
39+
'post_content' => 'This is a test post',
40+
'post_status' => 'publish',
41+
'post_type' => 'post'
42+
]);
43+
44+
// Generate the Relay global ID (base64 encoded "post:ID")
45+
$relay_id = base64_encode( 'post:' . $post_id );
46+
47+
do_action( 'graphql_purge', $relay_id, 'post_UPDATE', 'mysite.local/graphql' );
48+
echo "✓ Triggered: graphql_purge with Relay ID: $relay_id\n";
49+
echo " Decodes to: post:$post_id\n\n";
50+
51+
// Test 3: Simulate a graphql_purge event for post deletion
52+
echo "Test 3: Simulating post DELETE event\n";
53+
echo "====================================\n";
54+
55+
do_action( 'graphql_purge', $relay_id, 'post_DELETE', 'mysite.local/graphql' );
56+
echo "✓ Triggered: graphql_purge for deletion\n\n";
57+
58+
// Test 4: Simulate cache purge nodes event
59+
echo "Test 4: Simulating cache purge nodes event\n";
60+
echo "==========================================\n";
61+
62+
$test_nodes = [
63+
['id' => $relay_id, 'type' => 'post'],
64+
['id' => 'dGVybTox', 'type' => 'term'], // Example term
65+
];
66+
67+
do_action( 'wpgraphql_cache_purge_nodes', 'list:post', $test_nodes );
68+
echo "✓ Triggered: wpgraphql_cache_purge_nodes with " . count($test_nodes) . " nodes\n\n";
69+
70+
// Clean up test post
71+
wp_delete_post( $post_id, true );
72+
73+
echo "Test completed!\n\n";
74+
echo "Check your webhook logs to see if the events were captured.\n";
75+
echo "Expected webhook events:\n";
76+
echo "- smart_cache_created (from Test 1)\n";
77+
echo "- smart_cache_updated (from Test 2)\n";
78+
echo "- smart_cache_deleted (from Test 3)\n";
79+
echo "- smart_cache_nodes_purged (from Test 4)\n";
80+
81+
echo '</pre>';
82+
83+
// Add a button to view webhooks
84+
echo '<p><a href="' . admin_url('options-general.php?page=webhooks') . '" class="button button-primary">View Webhooks Admin</a></p>';
85+
86+
die(); // Stop WordPress execution
87+
});
88+
89+
// Add logging to see when Smart Cache events are triggered
90+
add_action( 'graphql_webhooks_before_trigger', function( $event, $payload ) {
91+
if ( strpos( $event, 'smart_cache' ) === 0 ) {
92+
error_log( '[Smart Cache Webhook] Event: ' . $event );
93+
error_log( '[Smart Cache Webhook] Payload: ' . print_r( $payload, true ) );
94+
}
95+
}, 10, 2 );

0 commit comments

Comments
 (0)