Skip to content

Rating#1289

Open
tarunnjoshi wants to merge 4 commits intodevfrom
qr-code-rating
Open

Rating#1289
tarunnjoshi wants to merge 4 commits intodevfrom
qr-code-rating

Conversation

@tarunnjoshi
Copy link
Member

@tarunnjoshi tarunnjoshi commented Jun 11, 2025

Rating

Summary by CodeRabbit

  • New Features
    • Introduced a user rating interface accessible via a new shortcode, allowing users to submit ratings (1–10) for specific activities.
    • Ratings are submitted and updated in real time using AJAX, with immediate feedback displayed to the user.
    • The rating system is integrated with CiviCRM data for enhanced activity tracking.

@coderabbitai
Copy link

coderabbitai bot commented Jun 11, 2025

Walkthrough

This update adds a user rating feature to a WordPress theme integrated with CiviCRM. It introduces a shortcode that renders a star rating interface linked to an activity, AJAX handlers to process rating submissions, and uses CiviCRM API4 to update related entity data accordingly.

Changes

File(s) Change Summary
functions.php Added shortcode goonj_user_rating; registered AJAX handlers for rating update; implemented callback to validate input and update CiviCRM activity entity via API4.
templates/user-rating.php New template rendering star rating UI; fetches activity details to determine entity ID; includes JavaScript for AJAX submission and UI feedback.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant WordPress
    participant CiviCRM

    User->>Browser: Loads page with [goonj_user_rating] shortcode
    Browser->>WordPress: Requests shortcode content
    WordPress->>CiviCRM: Fetches activity data by activity ID
    CiviCRM-->>WordPress: Returns activity data
    WordPress-->>Browser: Renders user-rating.php template

    User->>Browser: Clicks a star rating (1-10)
    Browser->>WordPress: AJAX POST (update_user_rating, rating, entity_id)
    WordPress->>CiviCRM: Updates User_Rating field via API4
    CiviCRM-->>WordPress: Returns update status
    WordPress-->>Browser: Responds with JSON (success/error)
    Browser-->>User: Displays message
Loading

Poem

⭐️ Stars align on the digital stage,
A rating born to engage and gauge.
AJAX hums a swift, quiet tune,
CiviCRM updates by afternoon.
From shortcode spark to server's gleam,
User voices flow like a dream.
🌟 Click your star, let your rating beam! ✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfda622 and 7fa093a.

📒 Files selected for processing (2)
  • wp-content/themes/goonj-crm/functions.php (1 hunks)
  • wp-content/themes/goonj-crm/templates/user-rating.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • wp-content/themes/goonj-crm/functions.php
  • wp-content/themes/goonj-crm/templates/user-rating.php
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
wp-content/themes/goonj-crm/templates/user-rating.php (1)

23-52: Inline <script> breaks caching & CSP; enqueue a dedicated file instead

Place this code in assets/js/user-rating.js, enqueue it via wp_enqueue_scripts, and localize ajaxurl, nonce, and entity_id with wp_localize_script.
This keeps templates clean and respects WP asset-loading best practices.

wp-content/themes/goonj-crm/functions.php (1)

858-869: Redundant wp_die() after wp_send_json_*

wp_send_json_success() / wp_send_json_error() already call wp_die() internally, so the explicit call at the end is dead code.

-    wp_die();
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e741266 and 1b8b3b9.

📒 Files selected for processing (2)
  • wp-content/themes/goonj-crm/functions.php (1 hunks)
  • wp-content/themes/goonj-crm/templates/user-rating.php (1 hunks)

Comment on lines 28 to 40
// Prepare data for AJAX request
var data = {
action: 'update_user_rating',
rating: rating,
entity_id: 7323 // Hardcoded ID as per requirement
};

// AJAX request to call the API
jQuery.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: data,
success: function(response) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

AJAX request is missing a WordPress nonce – CSRF vulnerability

Any third-party site can silently POST to admin-ajax.php while the user is logged-in and alter ratings.
Add a nonce to the request and verify it in update_user_rating_callback.

-    var data = {
-        action: 'update_user_rating',
-        rating: rating,
-        entity_id: <?php echo (int) $entity_id; ?> // …
-    };
+    var data = {
+        action: 'update_user_rating',
+        _ajax_nonce: '<?php echo wp_create_nonce( "goonj_user_rating" ); ?>',
+        rating: rating,
+        entity_id: <?php echo (int) $entity_id; ?>
+    };

Then in PHP:

check_ajax_referer( 'goonj_user_rating' );
🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/templates/user-rating.php around lines 28 to 40,
the AJAX request lacks a WordPress nonce, exposing a CSRF vulnerability. Fix
this by generating a nonce in PHP using wp_create_nonce('goonj_user_rating') and
passing it to the JavaScript. Then include this nonce in the AJAX data object.
Finally, in the PHP callback function update_user_rating_callback, verify the
nonce by calling check_ajax_referer('goonj_user_rating') before processing the
request.

Comment on lines +842 to +855
if (!isset($_POST['rating']) || !isset($_POST['entity_id'])) {
wp_send_json_error(['message' => 'Invalid input']);
wp_die();
}

$rating = intval($_POST['rating']);
$entity_id = intval($_POST['entity_id']);

// Validate rating (1 to 10)
if ($rating < 1 || $rating > 10) {
wp_send_json_error(['message' => 'Rating must be between 1 and 10']);
wp_die();
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

update_user_rating_callback lacks nonce & capability checks

Add check_ajax_referer( 'goonj_user_rating' ) to stop CSRF and optionally verify the current user can update the specified entity.

check_ajax_referer( 'goonj_user_rating' );

if ( ! current_user_can( 'read' ) ) {
    wp_send_json_error( [ 'message' => 'Permission denied' ], 403 );
}
🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/functions.php around lines 842 to 855, the
update_user_rating_callback function lacks security checks against CSRF and
unauthorized access. Add a call to check_ajax_referer('goonj_user_rating') at
the start of the function to verify the nonce. Then, add a capability check
using current_user_can('read') or a more specific capability to ensure the user
has permission to update the rating. If the check fails, respond with
wp_send_json_error including a 'Permission denied' message and a 403 status
code.

Comment on lines 820 to 834
$activities = \Civi\Api4\Activity::get(FALSE)
->addSelect(
'Material_Contribution.Collection_Camp',
'Material_Contribution.Institution_Collection_Camp',
'Material_Contribution.Dropping_Center',
'Material_Contribution.Institution_Dropping_Center',
'Material_Contribution.Goonj_Office',
'Office_Visit.Goonj_Processing_Center',
'Material_Contribution.Event'
)
->addWhere('id', '=', $activity_id)
->execute()
->first();
error_log('Activities: ' . print_r($activities, true));
include(get_template_directory() . '/templates/user-rating.php');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fetched $activities is discarded and $entity_id never reaches the template

You fetch activity data but never pass the resulting entity/collection-camp ID to the template; meanwhile the template hard-codes 7323.
Populate $entity_id from $activities and expose it to the template:

-    $activities = \Civi\Api4\Activity::get(FALSE)
+    $activities = \Civi\Api4\Activity::get(FALSE)
         /* … */
-    ->first();
- error_log('Activities: ' . print_r($activities, true));
-    include(get_template_directory() . '/templates/user-rating.php');
+    ->first();
+
+    if ( empty( $activities ) ) {
+        \Civi::log()->warning( 'Activity not found', [ 'id' => $activity_id ] );
+        return ob_get_clean();
+    }
+
+    // Derive the related Collection_Camp ID (example, adjust as per schema)
+    $entity_id = $activities['Material_Contribution.Collection_Camp'] ?? 0;
+
+    include get_template_directory() . '/templates/user-rating.php';
🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/functions.php around lines 820 to 834, the
fetched $activities data is not used to set $entity_id, causing the template to
use a hard-coded value. Extract the relevant entity or collection camp ID from
$activities, assign it to $entity_id, and ensure $entity_id is available to the
included user-rating.php template so it uses dynamic data instead of a fixed ID.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
wp-content/themes/goonj-crm/templates/user-rating.php (1)

90-96: ⚠️ Potential issue

CSRF protection is still missing – nonce must be included
The AJAX payload is dispatched without a WordPress nonce, leaving the endpoint vulnerable to CSRF attacks. This is exactly the issue flagged in the earlier review and remains unfixed.

 var data = {
     action: 'update_user_rating',
+    _ajax_nonce: '<?php echo wp_create_nonce( "goonj_user_rating" ); ?>',
     rating: rating,
     entity_id: <?php echo $entity_id; ?>
 };

Add check_ajax_referer( 'goonj_user_rating' ); at the top of update_user_rating_callback.

🧹 Nitpick comments (2)
wp-content/themes/goonj-crm/templates/user-rating.php (2)

36-37: Avoid error_log in production templates
Raw error_log() calls leak internal state to PHP error logs and clutter logs in production. Use \Civi::log()->debug() (with appropriate log level) or remove once debugging is complete.

Also applies to: 66-66


68-83: Escape dynamic output in HTML
<?php echo $i; ?> is safe here, but follow WordPress convention and wrap with esc_html( $i ) / esc_attr(). Future edits will inherit safe patterns.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b8b3b9 and 47d079b.

📒 Files selected for processing (2)
  • wp-content/themes/goonj-crm/functions.php (1 hunks)
  • wp-content/themes/goonj-crm/templates/user-rating.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/themes/goonj-crm/functions.php
🔇 Additional comments (1)
wp-content/themes/goonj-crm/templates/user-rating.php (1)

85-85: Ensure jQuery is enqueued
The script assumes jQuery is present. Add wp_enqueue_script( 'jquery' ); when registering the shortcode to avoid “undefined jQuery” errors on themes that dequeue it.

Comment on lines 20 to 34
try {
// Fetch activity details.
$activities = Activity::get(FALSE)
->addSelect(
'Material_Contribution.Collection_Camp',
'Material_Contribution.Institution_Collection_Camp',
'Material_Contribution.Dropping_Center',
'Material_Contribution.Institution_Dropping_Center',
'Material_Contribution.Goonj_Office',
'Office_Visit.Goonj_Processing_Center',
'Material_Contribution.Event'
)
->addWhere('id', '=', $activity_id)
->execute()
->first();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Template mixes heavy data access with presentation – violates SRP
The CiviCRM API query (including multiple joins) is executed directly inside the template. This couples database logic to markup and hampers testability.

Move the lookup into a helper (get_entity_id_from_activity( $activity_id )) in functions.php (or a separate service class) and pass the resolved $entity_id to the template.

🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/templates/user-rating.php around lines 20 to 34,
the code directly performs a complex data query inside the template, mixing data
access with presentation and violating the Single Responsibility Principle. To
fix this, move the entire data fetching logic into a helper function named
get_entity_id_from_activity($activity_id) located in functions.php or a
dedicated service class. Then, modify the template to accept the pre-fetched
$entity_id as a parameter, removing all database queries from the template file.

Comment on lines 101 to 107
success: function(response) {
if (response.success) {
document.getElementById('rating-message').innerHTML = '<p style="color: green;">Rating updated successfully!</p>';
} else {
document.getElementById('rating-message').innerHTML = '<p style="color: red;">Error: ' + response.data.message + '</p>';
}
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential XSS – server message is written with innerHTML
response.data.message is interpolated directly into the DOM with innerHTML. If the server ever echoes unsanitised user-supplied data, you have an XSS vector.

- document.getElementById('rating-message').innerHTML =
-   '<p style="color: red;">Error: ' + response.data.message + '</p>';
+ document.getElementById('rating-message').textContent =
+   'Error: ' + response.data.message;
📝 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.

Suggested change
success: function(response) {
if (response.success) {
document.getElementById('rating-message').innerHTML = '<p style="color: green;">Rating updated successfully!</p>';
} else {
document.getElementById('rating-message').innerHTML = '<p style="color: red;">Error: ' + response.data.message + '</p>';
}
},
success: function(response) {
if (response.success) {
document.getElementById('rating-message').innerHTML = '<p style="color: green;">Rating updated successfully!</p>';
} else {
document.getElementById('rating-message').textContent = 'Error: ' + response.data.message;
}
},
🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/templates/user-rating.php around lines 101 to
107, the code inserts server response messages directly into the DOM using
innerHTML, which risks XSS if the message contains unsanitized user input. To
fix this, replace innerHTML with textContent or another safe method to insert
the message text, ensuring that any HTML tags in response.data.message are not
interpreted as code.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
wp-content/themes/goonj-crm/templates/user-rating.php (3)

20-34: Heavy DB logic still embedded in template – violates SRP

The entire Activity::get() query remains inside the presentation layer. This couples markup to data access and makes the template hard to test or reuse. Please move this lookup to a helper/ service in functions.php (or similar) and pass the resolved $entity_id when rendering the template.


112-118: AJAX request is still missing a WordPress nonce → CSRF risk

Previous review already flagged this. A malicious site can POST to admin-ajax.php and change ratings.
Add a nonce to the data payload and verify it in the PHP callback.

-        const data = {
-            action: 'update_user_rating',
-            rating: rating,
-            entity_id: <?php echo $entity_id; ?> // Dynamically set from activity
-        };
+        const data = {
+            action: 'update_user_rating',
+            _ajax_nonce: '<?php echo wp_create_nonce( "goonj_user_rating" ); ?>',
+            rating: rating,
+            entity_id: <?php echo $entity_id; ?>
+        };

And in update_user_rating_callback:

check_ajax_referer( 'goonj_user_rating' );

126-134: Potential XSS – replace innerHTML with textContent

response.data.message is written via innerHTML, allowing an attacker-supplied string to inject markup/JS. Use textContent instead.

- document.getElementById('rating-message').innerHTML =
-   '<p style="color: green;">Rating updated successfully!</p>';
+ document.getElementById('rating-message').textContent =
+   'Rating updated successfully!';

- document.getElementById('rating-message').innerHTML =
-   '<p style="color: red;">Error: ' + response.data.message + '</p>';
+ document.getElementById('rating-message').textContent =
+   'Error: ' + response.data.message;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47d079b and dfda622.

📒 Files selected for processing (1)
  • wp-content/themes/goonj-crm/templates/user-rating.php (1 hunks)

Comment on lines +36 to +37
error_log('Activities: ' . print_r($activities, TRUE));

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Verbose error_log() dumps may leak PII in production logs

print_r($activities, TRUE) and unconditional logging of $entity_id can expose sensitive donor/camp data. Remove or gate behind a debug flag.

-error_log('Activities: ' . print_r($activities, TRUE));
-...
-error_log('Entity ID: ' . $entity_id);
+// error_log(...)  // Remove or wrap with WP_DEBUG check

Also applies to: 66-66

🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/templates/user-rating.php at lines 36-37 and line
66, the error_log calls unconditionally output detailed data including
$activities and $entity_id, which may expose sensitive information. To fix this,
wrap these error_log statements inside a conditional check for a debug flag or
environment variable that is only enabled in development or debugging scenarios,
ensuring no sensitive data is logged in production.

Comment on lines +49 to +55
foreach ($fields as $field) {
if (!empty($activities[$field])) {
$entity_id = intval($activities[$field]);
break;
}
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Possible fatal error when $activities is null

If no activity is found, $activities is null, so $activities[$field] triggers a warning. Bail out early:

-if (!empty($activities[$field])) {
+if ($activities && !empty($activities[$field])) {

Or check $activities === null right after the query and handle gracefully.

📝 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.

Suggested change
foreach ($fields as $field) {
if (!empty($activities[$field])) {
$entity_id = intval($activities[$field]);
break;
}
}
foreach ($fields as $field) {
if ($activities && !empty($activities[$field])) {
$entity_id = intval($activities[$field]);
break;
}
}
🤖 Prompt for AI Agents
In wp-content/themes/goonj-crm/templates/user-rating.php around lines 49 to 55,
the code accesses $activities[$field] without checking if $activities is null,
which can cause a fatal error. Fix this by adding a check before the foreach
loop to ensure $activities is not null, or handle the case where $activities is
null immediately after the query to avoid accessing it when null.

Base automatically changed from develop to dev July 25, 2025 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant