Skip to content

Translate: Optimize queries, caching, and input handling in Locale route - #1038

Open
timse201 wants to merge 96 commits into
WordPress:trunkfrom
timse201:patch-2
Open

timse201 wants to merge 96 commits into
WordPress:trunkfrom
timse201:patch-2

Conversation

@timse201

@timse201 timse201 commented Oct 10, 2026 •

Copy link
Copy Markdown

Refactors the Locale route to significantly reduce database load, and improve overall performance:

  • Ensure restore_current_blog() is always called via a try/finally block when retrieving plugin icons.
  • Replace deprecated SQL_CALC_FOUND_ROWS with separate count and data queries in get_paged_active_sub_projects().
  • Batch-fetch sub-projects and translation set contributors in single queries instead of iterative loops.
  • Prime user caches using wp_cache_get_multiple() and switch to WP_User::get_data_by() to avoid unnecessary usermeta lookups.
  • Introduce in-memory caches for projects, statuses, sub-projects, and favorites, along with persistent object caching for top-level active projects.
  • Extract repetitive logic into helper methods (render_dashicon(), calculate_percent_complete(), get_locale_glossary_details()).
  • Modernize codebase to adopt PHP 8+ features and strict comparisons.
  • Support locale-aware string collation via the Collator class when available.

assisted by Gemini 4 Argon

Summary by CodeRabbit

Summary

  • Improvements
    • Contributor listings include contributions from active nested subprojects, show aggregated totals and latest activity, and are sorted by contribution count.
    • Project listings support searching and sorting, including by completion percentage, and include active subprojects.
    • Editor lookups include editors inherited from parent projects.
    • Favorite project filtering and project pagination provide more consistent results.
  • Bug Fixes
    • Invalid locale set slugs are rejected, and empty project pages return a not-found response.
    • Glossary lookups handle projects without a translation set.
    • Requests for unauthorized waiting tabs redirect to the selected default tab while retaining query parameters.
    • Missing project or plugin icon records are handled safely.

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props timse201, obenland.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • No new commits to review - use @coderabbitai full review for a full pass

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 51f5e449-6f4a-47b2-85ff-2fe6e452455b
📥 Commits

Reviewing files that changed from the base of the PR and between cfff8a4 and 692c473.

📒 Files selected for processing (1)
  • wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/inc/routes/class-locale.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

📝 Walkthrough

The locale route updates project-set validation, glossary lookup, editor and contributor retrieval, active-subproject lookup, and project pagination. Listings use bound query parameters and separate count queries. Favorite and top-level project results use caching.

Changes: Locale route behavior

Layer / File(s) Summary
Locale project lookup
wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/inc/routes/class-locale.php
Routes validate set slugs against locale variants, redirect unavailable waiting-tab requests, and return 404 for empty later pages. Shared glossary lookup and icon handling account for missing records.
Editor and contributor retrieval
wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/inc/routes/class-locale.php
Inherited editors are retrieved through cycle-safe ancestor traversal. Contributor data is fetched in batches across matching translation sets and aggregated by user and project. Active subproject results are cached, and nested children are fetched in one query.
Paged project queries and favorites
wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/inc/routes/class-locale.php
Paged listings use bound search and favorite parameters and separate data and count queries. Completion sorting handles zero totals. Favorite results and top-level project results use caching.

Priority: ⬇️ Low

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Refactor

Suggested reviewers: obenland

Merge Risk: ⚪ Minimal · up to 692c4

No identified issue prevents merging after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Docstring Coverage Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 1 files.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely summarizes the main changes: query optimization, caching, and input handling in the Locale route.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as outdated.

@timse201 timse201 changed the title Translate: Optimize contributor queries and caching Translate: Optimize sub-project queries and contributor caching in Locale route. Oct 10, 2026
@timse201 timse201 changed the title Translate: Optimize sub-project queries and contributor caching in Locale route. Translate: Optimize queries, caching, and input handling in Locale route Oct 11, 2026
@timse201

timse201 commented Oct 11, 2026 •

Copy link
Copy Markdown
Author

Some comparison. First is the old behavior.

get_active_sub_projects

  • Runs an individual SQL query for each sub-project inside a foreach loop to find child projects.
  • Fetches all nested child projects in a single batch query and organizes them in PHP.

get_active_sub_projects

  • Does not cache query results in memory; repeats database queries on multiple calls.
  • Saves project lists in a static $cache array keyed by project ID and arguments.

get_paged_active_sub_projects

  • Uses deprecated SQL_CALC_FOUND_ROWS, forcing MySQL to perform a full table scan and expensive filesort across all matching rows to calculate pagination.
  • Splits pagination into a LIMIT data query and a lightweight COUNT(*) query without ORDER BY, avoiding unnecessary filesorts and table scans.

get_translation_editors

  • Runs a new database query for every parent project level inside a while loop.
  • Collects all parent project IDs in memory first and fetches editors using a single query.

get_locale_contributors

  • Runs translation set lookups and heavy statistical SQL queries separately in a loop for each project.
  • Finds all translation set IDs in one query, then runs one combined query for all sets.

get_locale_contributors

  • Calls get_user_by() individually for every contributor and editor
  • Collects all user IDs and primes the WordPress cache in advance with cache_users().

get_locale_contributors

  • Checks if a user is an editor using in_array() inside a loop
  • Stores editor IDs as keys in an associative array and checks them using isset()

Early 404 Exit

  • Prepares view variables and triggers apply_filters() before checking if the project list is empty.
  • Checks if projects exist immediately and stops execution early with a 404 error if empty.

@timse201 timse201 moved this from 👀 In review (PRs only) to 🚀 Ready for deploy (PRs only) in WordPress.org Oct 19, 2026
@timse201

timse201 commented Oct 19, 2026 •

Copy link
Copy Markdown
Author

@obenland
I have fixed some edge cases and added some empty checks.
No usermeta is queried (WP_User::get_data_by() is used), except in favorites.
Collator is now used to sort editor names which is a bit slower. But it sorts special characters, too.
And a array_slice caps user favorites on special. (Sorting for waiting strings)

I can't find any errors that could occur now. Only when something changes on translate.WP.org.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Enhancement New feature or request

Projects

Status: 🚀 Ready for deploy (PRs only)

Development

Successfully merging this pull request may close these issues.

2 participants