Skip to content

refactor: Optimize donor dashboard queries #7982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

jfn4th
Copy link

@jfn4th jfn4th commented Jun 17, 2025

Description

This aims to greatly improve donor dashboard load times, particularly for sites with very large donation histories. A site we maintain with 130k donations and 6.3 million rows of donation meta was seeing timeouts when hitting /wp-json/give-api/v2/donor-dashboard/donations, and locally (M1 Pro Macbook Pro) was taking 30-40 seconds to resolve. This was due to getDonationIds and calls to getDonationAggregate each taking 5-8 seconds to run. Here, we remove an (as far as I am aware) unnecessary join to wp_give_revenue in getDonationIds and cache the result so we can reuse the IDs. Then consolidate the aggregate queries into a single query, taking advantage of the ID cache to remove the need for expensive joins. Altogether, this reduces the response time from 30-40 seconds to 1-2 seconds on my machine.

Also replaces the usage of the deprecated Give\ValueObjects\Money class with Give\Framework\Support\ValueObjects\Money updates method typedocs to reflect possibility of null count, revenue, and average, and removes some stray whitespace characters.

Affects

This affects the internal queries used in the /wp-json/give-api/v2/donor-dashboard/donations donor dashboard endpoint.

Testing Instructions

  1. Load the donor dashboard before applying these changes and measure response time to /wp-json/give-api/v2/donor-dashboard/donations
  2. Do the same after applying changes.

Pre-review Checklist

  • Acceptance criteria satisfied and marked in related issue
  • Relevant @unreleased tags included in DocBlocks
  • Includes unit tests
  • Reviewed by the designer (if follows a design)
  • Self Review of code and UX completed

@jonwaldstein jonwaldstein requested a review from alaca June 17, 2025 21:47
@jfn4th jfn4th force-pushed the refactor/donor-dashboard-query-optimizations branch from 84322b2 to 3c08642 Compare June 17, 2025 21:48
@jonwaldstein
Copy link
Contributor

@jfn4th thanks for the PR! 🙌

I'll admit, our donor dashboard queries are a bit outdated with some of our current performance updates we're making so this is a welcome update 😄.

We're a small team and currently working on some big projects but i'll try to prioritize reviewing this within a week or so.

@jfn4th jfn4th force-pushed the refactor/donor-dashboard-query-optimizations branch from 3c08642 to 8c96700 Compare June 17, 2025 22:40
@jfn4th
Copy link
Author

jfn4th commented Jun 17, 2025

Thanks for the info! I realized I missed that getDonationAggregate filtered by a narrower post status than getDonationIDs did, so I've updated the PR to include that and DRY up the getDonationAggregate and my new getDonationsSummary methods since they ended up so similar.

@jfn4th jfn4th force-pushed the refactor/donor-dashboard-query-optimizations branch 5 times, most recently from aa70ac6 to 550cb93 Compare June 18, 2025 02:55
Copy link
Member

@alaca alaca left a comment

Choose a reason for hiding this comment

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

Hey @jfn4th, great work. It will improve the performance of the Donor Dashboard. Thank you. I have a couple of suggestions, other than that, looks good 👍

*
* @return object|null
*/
private function queryDonationRevenueData($donorId, $selectClause)
Copy link
Member

Choose a reason for hiding this comment

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

The idea of passing SQL as a parameter makes me anxious 😅
I'd suggest refactoring this method to something like getRevenueDonationDataQuery, which will return a QueryBuilder object with a base query. Then, when you call it, it will look something like this:

$query = $this->getRevenueDonationDataQuery($ids);
$query->select('whatever');
$data = $query->getAll();

If you are not familiar with our QueryBuilder library, you can check it here https://github.com/impress-org/givewp/blob/develop/src/Framework/QueryBuilder/README.md

@jfn4th jfn4th force-pushed the refactor/donor-dashboard-query-optimizations branch from 550cb93 to 7eb9977 Compare June 23, 2025 17:01
@jfn4th
Copy link
Author

jfn4th commented Jun 23, 2025

Thanks @alaca for the feedback. I've moved to using the QueryBuilder as requested.

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.

3 participants