Use WP_Error for Error Handling — Not Exceptions or False
Share
Returning false on failure hides what went wrong. WP_Error provides structured error codes, messages, and data — matching WordPress core's error handling pattern.
Why This Matters
enables proper error reporting, debugging, and user-facing error messages
Use WP_Error for Error Handling — Not Exceptions or False
Impact: MEDIUM (enables proper error reporting, debugging, and user-facing error messages)
WordPress core doesn't use PHP exceptions for error handling — it uses WP_Error objects. Functions like wp_insert_post(), wp_remote_get(), and wp_create_user() return WP_Error on failure. Your plugin code should follow the same pattern: return WP_Error with a structured code, message, and optional data instead of returning false or throwing exceptions.
Incorrect (ambiguous error returns):
// ❌ Returning false — caller has no idea what went wrongfunction create_invoice( int $order_id, array $data ): int|false { if ( empty( $data['amount'] ) ) { return false; // Why? Missing amount? Invalid amount? Permission issue? } $order = get_post( $order_id ); if ( ! $order ) { return false; // Same false for a completely different error } // ... return $invoice_id;}// Caller has no useful error info$invoice = create_invoice( $order_id, $data );if ( ! $invoice ) { // What happened? We have no idea. Can't show a useful message. echo 'Something went wrong.';}
// ❌ Throwing exceptions (not idiomatic WordPress)function process_payment( float $amount ): void { if ( $amount <= 0 ) { throw new \InvalidArgumentException( 'Invalid amount' ); } // WordPress core and most plugins don't catch exceptions // Unhandled exception = white screen of death}
// ❌ Not checking wp_remote_get for errors before using result$response = wp_remote_get( 'https://api.example.com/data' );$body = json_decode( wp_remote_retrieve_body( $response ), true );// If $response is WP_Error → wp_remote_retrieve_body returns '' → json_decode returns null → crash
Correct (structured WP_Error returns):
// ✅ Return WP_Error with code, message, and datafunction create_invoice( int $order_id, array $data ): int|WP_Error { if ( empty( $data['amount'] ) || $data['amount'] <= 0 ) { return new WP_Error( 'invalid_amount', // Error code (string slug) __( 'Invoice amount must be a positive number.', 'my-plugin' ), // Human-readable [ 'order_id' => $order_id, 'amount' => $data['amount'] ?? null ] // Debug data ); } $order = get_post( $order_id ); if ( ! $order || 'shop_order' !== $order->post_type ) { return new WP_Error( 'invalid_order', __( 'Order not found.', 'my-plugin' ), [ 'order_id' => $order_id ] ); } if ( ! current_user_can( 'edit_shop_orders' ) ) { return new WP_Error( 'unauthorized', __( 'You do not have permission to create invoices.', 'my-plugin' ), [ 'status' => 403 ] ); } $invoice_id = wp_insert_post([ 'post_type' => 'invoice', 'post_status' => 'publish', 'post_parent' => $order_id, ]); if ( is_wp_error( $invoice_id ) ) { return $invoice_id; // Propagate WordPress's own error } return $invoice_id;}