Skip to content

Commit 1909a7e

Browse files
committed
activate_snippet() function now uses test_snippet_code() for validation
1 parent a7a5eea commit 1909a7e

File tree

4 files changed

+86
-48
lines changed

4 files changed

+86
-48
lines changed

src/js/services/manage/activation.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { __ } from '@wordpress/i18n'
2-
import { updateSnippet } from './requests'
32
import type { Snippet } from '../../types/Snippet'
3+
import { updateSnippet } from './requests'
44

55
/**
66
* Update the snippet count of a specific view
@@ -65,9 +65,21 @@ export const toggleSnippetActive = (link: HTMLAnchorElement, event: Event) => {
6565
} else {
6666
row.className += ' erroneous-snippet'
6767

68+
// Handle different types of errors
69+
const errorData = <{ type?: string; message?: string } | undefined>response.data
70+
const errorType = errorData?.type ?? 'action_error'
71+
let errorMessage = __('An error occurred when attempting to activate', 'code-snippets')
72+
73+
if ('validation_error' === errorType && errorData?.message) {
74+
errorMessage = errorData.message
75+
}
76+
6877
if (button) {
69-
button.title = __('An error occurred when attempting to activate', 'code-snippets')
78+
button.title = errorMessage
7079
}
80+
81+
// Show error message to user
82+
console.error('Snippet activation failed:', errorMessage)
7183
}
7284
})
7385
}

src/php/admin-menus/class-manage-menu.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,10 @@ public function ajax_callback() {
321321
} elseif ( $snippet->active ) {
322322
$result = activate_snippet( $snippet->id, $snippet->network );
323323
if ( is_string( $result ) ) {
324+
// Return validation error with proper error type
324325
wp_send_json_error(
325326
array(
326-
'type' => 'action_error',
327+
'type' => 'validation_error',
327328
'message' => $result,
328329
)
329330
);

src/php/rest-api/class-snippets-rest-controller.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,15 +310,23 @@ public function delete_item( $request ) {
310310
*/
311311
public function activate_item( WP_REST_Request $request ) {
312312
$item = $this->prepare_item_for_database( $request );
313+
314+
// DEBUG: Log REST API activation request
315+
error_log( "Code Snippets DEBUG: REST API activation request - ID: {$item->id}, Network: " . ( $item->network ? 'true' : 'false' ) );
316+
313317
$result = activate_snippet( $item->id, $item->network );
314318

315-
return $result instanceof Snippet ?
316-
rest_ensure_response( $result ) :
317-
new WP_Error(
319+
if ( $result instanceof Snippet ) {
320+
error_log( "Code Snippets DEBUG: REST API activation successful" );
321+
return rest_ensure_response( $result );
322+
} else {
323+
error_log( "Code Snippets DEBUG: REST API activation failed - Error: $result" );
324+
return new WP_Error(
318325
'rest_cannot_activate',
319326
$result,
320327
[ 'status' => 500 ]
321328
);
329+
}
322330
}
323331

324332
/**

src/php/snippet-ops.php

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,16 @@ function activate_snippet( int $id, ?bool $network = null ) {
297297
return sprintf( __( 'Could not locate snippet with ID %d.', 'code-snippets' ), $id );
298298
}
299299

300-
$validator = new Validator( $snippet->code );
301-
if ( $validator->validate() ) {
302-
return __( 'Could not activate snippet: code did not pass validation.', 'code-snippets' );
300+
// Use the same comprehensive validation as the edit page
301+
if ( 'php' === $snippet->type ) {
302+
test_snippet_code( $snippet );
303+
304+
if ( $snippet->code_error ) {
305+
return sprintf(
306+
__( 'Could not activate snippet: %s', 'code-snippets' ),
307+
$snippet->code_error[0]
308+
);
309+
}
303310
}
304311

305312
$result = $wpdb->update(
@@ -342,15 +349,21 @@ function activate_snippets( array $ids, ?bool $network = null ): ?array {
342349
return null;
343350
}
344351

345-
// Loop through each snippet code and validate individually.
352+
// Loop through each snippet code and validate individually using comprehensive validation
346353
$valid_ids = [];
347354
$valid_snippets = [];
348355

349356
foreach ( $snippets as $snippet ) {
350-
$validator = new Validator( $snippet->code );
351-
$code_error = $validator->validate();
357+
// Use the same comprehensive validation as single snippet activation
358+
if ( 'php' === $snippet->type ) {
359+
test_snippet_code( $snippet );
352360

353-
if ( ! $code_error ) {
361+
if ( ! $snippet->code_error ) {
362+
$valid_ids[] = $snippet->id;
363+
$valid_snippets[] = $snippet;
364+
}
365+
} else {
366+
// Non-PHP snippets can be activated without validation
354367
$valid_ids[] = $snippet->id;
355368
$valid_snippets[] = $snippet;
356369
}
@@ -459,17 +472,23 @@ function test_snippet_code( Snippet $snippet ) {
459472
$snippet->code_error = null;
460473

461474
if ( 'php' !== $snippet->type ) {
475+
error_log( "Code Snippets DEBUG: Skipping validation for non-PHP snippet type: {$snippet->type}" );
462476
return;
463477
}
464478

479+
error_log( "Code Snippets DEBUG: Running Validator on snippet ID {$snippet->id}" );
465480
$validator = new Validator( $snippet->code );
466481
$result = $validator->validate();
467482

468483
if ( $result ) {
484+
error_log( "Code Snippets DEBUG: Validator found error: " . $result['message'] );
469485
$snippet->code_error = [ $result['message'], $result['line'] ];
486+
} else {
487+
error_log( "Code Snippets DEBUG: Validator passed, running execute_snippet" );
470488
}
471489

472-
if ( ! $snippet->code_error && 'single-use' !== $snippet->scope ) {
490+
if ( ! $snippet->code_error ) {
491+
error_log( "Code Snippets DEBUG: Calling execute_snippet for redeclaration check" );
473492
$result = execute_snippet( $snippet->code, $snippet->id, true );
474493

475494
if ( $result instanceof ParseError ) {
@@ -599,11 +618,14 @@ function execute_snippet( string $code, int $id = 0, bool $force = false ) {
599618
return false;
600619
}
601620

602-
// Fatal errors - try to detect function redeclaration by parsing the code
603-
$function_redeclaration_error = detect_function_redeclaration( $code );
604-
if ( $function_redeclaration_error ) {
605-
return $function_redeclaration_error;
606-
}
621+
// Set up error handling for fatal errors
622+
$old_error_handler = set_error_handler( function( $severity, $message, $file, $line ) {
623+
// Convert fatal errors to exceptions
624+
if ( $severity & ( E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR ) ) {
625+
throw new Error( $message, 0, $severity, $file, $line );
626+
}
627+
return false; // Let other errors be handled normally
628+
});
607629

608630
ob_start();
609631

@@ -613,45 +635,40 @@ function execute_snippet( string $code, int $id = 0, bool $force = false ) {
613635
$result = $parse_error;
614636
} catch ( Error $error ) {
615637
$result = $error;
638+
} catch ( Throwable $throwable ) {
639+
// Handle function redeclaration and other fatal errors
640+
if ( strpos( $throwable->getMessage(), 'Cannot redeclare' ) !== false ) {
641+
$error = new \stdClass();
642+
$error->type = 'fatal_error';
643+
$error->message = $throwable->getMessage();
644+
$error->line = $throwable->getLine();
645+
$error->file = $throwable->getFile();
646+
$result = $error;
647+
} else {
648+
$result = $throwable;
649+
}
616650
}
617651

618-
ob_end_clean();
619-
620-
do_action( 'code_snippets/after_execute_snippet', $code, $id, $result );
621-
return $result;
622-
}
623-
624-
/**
625-
* Detect function redeclaration errors by checking if functions already exist
626-
*
627-
* @param string $code The code to check
628-
* @return object|null Error object if redeclaration detected, null otherwise
629-
*/
630-
function detect_function_redeclaration( string $code ) {
631-
// Extract function names from the code
632-
preg_match_all( '/function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/', $code, $matches );
652+
$output = ob_get_clean();
633653

634-
if ( empty( $matches[1] ) ) {
635-
return null; // No functions found
636-
}
637-
638-
$function_names = $matches[1];
654+
// Restore original error handler
655+
restore_error_handler();
639656

640-
// Check if any of these functions already exist
641-
foreach ( $function_names as $function_name ) {
642-
if ( function_exists( $function_name ) ) {
657+
// If we have output but no result, it might be a fatal error that wasn't caught
658+
if ( ! empty( $output ) && null === $result ) {
643659
$error = new \stdClass();
644660
$error->type = 'fatal_error';
645-
$error->message = "Cannot redeclare {$function_name}() (previously declared)";
646-
$error->line = 1; // We can't determine the exact line easily
661+
$error->message = 'Fatal error during execution';
662+
$error->line = 1;
647663
$error->file = '';
648-
return $error;
649-
}
664+
$result = $error;
650665
}
651-
652-
return null; // No redeclaration detected
666+
667+
do_action( 'code_snippets/after_execute_snippet', $code, $id, $result );
668+
return $result;
653669
}
654670

671+
655672
/**
656673
* Retrieve a single snippets from the database using its cloud ID.
657674
*

0 commit comments

Comments
 (0)