Adds SearchWP integration - #17
Conversation
WalkthroughA new integration for SearchWP has been added to the EchoDash plugin. This introduces a dedicated class that hooks into SearchWP's query events, tracking both successful and zero-result searches. The integration is registered in the main plugin file, enabling EchoDash to record and process search-related analytics from SearchWP. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant SearchWP
participant EchoDash_SearchWP
participant EchoDash
User->>SearchWP: Performs a search
SearchWP-->>EchoDash_SearchWP: Fires searchwp\query\ran action
EchoDash_SearchWP->>EchoDash_SearchWP: search_query_performed($query)
EchoDash_SearchWP->>EchoDash: track_event (search_performed or search_no_results)
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Claude finished @jack-arturo's task —— View job Code Review for SearchWP IntegrationCompleted comprehensive review of the SearchWP integration implementation focusing on WordPress plugin standards, security, architecture, and testing. Todo List:
✅ Overall Assessment: Well-Implemented IntegrationThe SearchWP integration follows EchoDash's established patterns and WordPress best practices. The implementation is clean, secure, and follows the repository's architectural standards. 📋 Detailed Review FindingsWordPress Plugin Standards ✅
Security Practices ✅
Integration Architecture ✅
Documentation Standards
|
| Aspect | Status | Notes |
|---|---|---|
| Security | ✅ Excellent | Proper validation and defensive programming |
| Performance | ✅ Good | Efficient event tracking, no unnecessary queries |
| Maintainability | ✅ Excellent | Clear structure, follows established patterns |
| Documentation | Version tagging needs standardization | |
| WordPress Standards | ✅ Excellent | Follows all WordPress best practices |
| Integration Pattern | ✅ Perfect | Matches existing integration architecture |
🎯 Integration-Specific Strengths
- Smart Trigger Logic: Excellent separation of successful vs. zero-result searches
- Comprehensive Data Capture: Captures search terms, results count, query time, and engine name
- Defensive Programming: Multiple layers of validation for the SearchWP query object
- User Experience: Provides meaningful default events with proper merge tag mappings
- Performance Optimized: Uses direct data passing rather than additional database lookups
📝 Files Modified
- echodash.php:278 - Added SearchWP integration registration ✅
- includes/integrations/searchwp/class-echodash-searchwp.php - New integration class ✅
- includes/integrations/searchwp/searchwp-icon.png - Integration icon ✅
Summary: This is a well-crafted integration that demonstrates solid understanding of both WordPress plugin development and the EchoDash architecture. The only minor issue is the version tagging convention. The code is production-ready and follows all established patterns.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
includes/integrations/searchwp/class-echodash-searchwp.php (3)
106-138: Align timestamp preview with runtime timezonePreviews use
gmdate(...)while runtime data usescurrent_time('mysql')(site timezone). Prefer consistency to avoid confusion in the UI.- 'preview' => gmdate( 'Y-m-d H:i:s' ), + 'preview' => current_time( 'mysql' ),
159-165: Sanitize search terms before trackingGuard against potential injection later in the pipeline by stripping tags.
- 'search_terms' => $search_terms, + 'search_terms' => is_string( $search_terms ) ? wp_strip_all_tags( $search_terms ) : $search_terms,
147-151: Optional: avoid tracking admin-side queriesSearchWP may run queries in admin contexts (e.g., tools/reindex). If you only want user-facing searches, bail in admin.
public function search_query_performed( $query ) { - if ( empty( $query ) || ! method_exists( $query, 'get_keywords' ) ) { + if ( is_admin() && ! wp_doing_ajax() ) { + return; + } + if ( ! is_object( $query ) || ! method_exists( $query, 'get_keywords' ) ) { return; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
includes/integrations/searchwp/searchwp-icon.pngis excluded by!**/*.png
📒 Files selected for processing (2)
echodash.php(1 hunks)includes/integrations/searchwp/class-echodash-searchwp.php(1 hunks)
🔇 Additional comments (1)
includes/integrations/searchwp/class-echodash-searchwp.php (1)
50-52: No parent::init() to invoke hereEchoDash_Integration::init() is declared as an abstract method (see includes/integrations/class-echodash-integration.php:103) and has no implementation, so there’s no common bootstrap to call. You can safely omit any
parent::init()call in your override.Likely an incorrect or invalid review comment.
| 'searchwp' => 'SearchWP', | ||
| 'woocommerce' => 'WooCommerce', | ||
| 'woo-subscriptions' => 'WC_Subscriptions_Product', | ||
| ); |
There was a problem hiding this comment.
Fix SearchWP dependency detection to ensure the integration loads
class_exists( 'SearchWP' ) is unlikely to be true in modern SearchWP (v4+ uses namespaced classes). Use the Query class to detect presence.
Apply this diff:
- 'searchwp' => 'SearchWP',
+ // Detect SearchWP v4+ via its namespaced Query class.
+ 'searchwp' => '\SearchWP\Query',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'searchwp' => 'SearchWP', | |
| 'woocommerce' => 'WooCommerce', | |
| 'woo-subscriptions' => 'WC_Subscriptions_Product', | |
| ); | |
| // Detect SearchWP v4+ via its namespaced Query class. | |
| 'searchwp' => '\SearchWP\Query', | |
| 'woocommerce' => 'WooCommerce', | |
| 'woo-subscriptions' => 'WC_Subscriptions_Product', | |
| ); |
🤖 Prompt for AI Agents
In echodash.php around lines 278 to 281, the current detection for the SearchWP
dependency using class_exists('SearchWP') is outdated because SearchWP v4+ uses
namespaced classes. Update the detection logic to check for the presence of the
SearchWP\Query class instead, ensuring the integration loads correctly with
modern versions.
| if ( empty( $query ) || ! method_exists( $query, 'get_keywords' ) ) { | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Strengthen guard: use object check instead of empty()
empty( $query ) is ineffective for objects. Use is_object() to avoid edge cases.
- if ( empty( $query ) || ! method_exists( $query, 'get_keywords' ) ) {
+ if ( ! is_object( $query ) || ! method_exists( $query, 'get_keywords' ) ) {
return;
}🤖 Prompt for AI Agents
In includes/integrations/searchwp/class-echodash-searchwp.php around lines 148
to 151, replace the empty($query) check with is_object($query) to properly
verify that $query is an object before calling method_exists. This strengthens
the guard by ensuring $query is an object and prevents edge cases where empty()
does not behave as expected with objects.
| // Get search data. | ||
| $search_terms = $query->get_keywords(); | ||
| $results_count = isset( $query->found_results ) ? (int) $query->found_results : 0; | ||
| $query_time = isset( $query->query_time ) ? (float) $query->query_time : 0; | ||
| $engine_name = method_exists( $query, 'get_engine' ) && method_exists( $query->get_engine(), 'get_name' ) ? $query->get_engine()->get_name() : 'default'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Make result and engine extraction more robust
- Prefer
get_results()when available to computeresults_count. - Avoid calling
method_exists()on the result of a method call; fetch engine once and check it.
- $search_terms = $query->get_keywords();
- $results_count = isset( $query->found_results ) ? (int) $query->found_results : 0;
- $query_time = isset( $query->query_time ) ? (float) $query->query_time : 0;
- $engine_name = method_exists( $query, 'get_engine' ) && method_exists( $query->get_engine(), 'get_name' ) ? $query->get_engine()->get_name() : 'default';
+ $search_terms = $query->get_keywords();
+
+ // Derive results count.
+ $results_count = 0;
+ if ( method_exists( $query, 'get_results' ) ) {
+ $results = $query->get_results();
+ $results_count = is_array( $results ) ? count( $results ) : (int) $results;
+ } elseif ( isset( $query->found_results ) ) {
+ $results_count = (int) $query->found_results;
+ }
+
+ $query_time = isset( $query->query_time ) ? (float) $query->query_time : 0;
+
+ // Resolve engine safely.
+ $engine_name = 'default';
+ if ( method_exists( $query, 'get_engine' ) ) {
+ $engine = $query->get_engine();
+ if ( is_object( $engine ) && method_exists( $engine, 'get_name' ) ) {
+ $engine_name = $engine->get_name();
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Get search data. | |
| $search_terms = $query->get_keywords(); | |
| $results_count = isset( $query->found_results ) ? (int) $query->found_results : 0; | |
| $query_time = isset( $query->query_time ) ? (float) $query->query_time : 0; | |
| $engine_name = method_exists( $query, 'get_engine' ) && method_exists( $query->get_engine(), 'get_name' ) ? $query->get_engine()->get_name() : 'default'; | |
| // Get search data. | |
| $search_terms = $query->get_keywords(); | |
| // Derive results count. | |
| $results_count = 0; | |
| if ( method_exists( $query, 'get_results' ) ) { | |
| $results = $query->get_results(); | |
| $results_count = is_array( $results ) ? count( $results ) : (int) $results; | |
| } elseif ( isset( $query->found_results ) ) { | |
| $results_count = (int) $query->found_results; | |
| } | |
| $query_time = isset( $query->query_time ) ? (float) $query->query_time : 0; | |
| // Resolve engine safely. | |
| $engine_name = 'default'; | |
| if ( method_exists( $query, 'get_engine' ) ) { | |
| $engine = $query->get_engine(); | |
| if ( is_object( $engine ) && method_exists( $engine, 'get_name' ) ) { | |
| $engine_name = $engine->get_name(); | |
| } | |
| } |
🤖 Prompt for AI Agents
In includes/integrations/searchwp/class-echodash-searchwp.php around lines 152
to 156, improve robustness by first checking if the query object has a
get_results() method and using it to determine results_count instead of directly
accessing found_results. Also, assign the result of get_engine() to a variable
before checking if it exists and has a get_name() method, then use that variable
to get the engine name or default to 'default'. This avoids calling
method_exists() on the result of a method call.
Summary by CodeRabbit