Skip to content

Conversation

@budzanowski
Copy link
Contributor

Summary

  • Fixes REST API routes not being initialized when abilities-api is used as a composer package
  • Moves REST API route registration from plugin file to bootstrap.php to ensure initialization in all cases
  • Prevents duplicate registration by placing hook inside class existence check

Changes

  • Moved rest_api_init hook registration from abilities-api.php to includes/bootstrap.php
  • Consolidated REST API initialization logic in bootstrap file
  • Ensures REST API routes work for both plugin and composer package installations

🤖 Generated with Claude Code

- Move REST API route registration from abilities-api.php to bootstrap.php
- Ensure REST API routes are initialized when used as composer package
- Prevent duplicate registration by placing hook inside class existence check
- Consolidate initialization logic in single location

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Sep 3, 2025

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.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: budzanowski <budzanowski@git.wordpress.org>
Co-authored-by: gziolo <gziolo@git.wordpress.org>
Co-authored-by: justlevine <justlevine@git.wordpress.org>

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

@gziolo
Copy link
Member

gziolo commented Sep 3, 2025

PHPUnit tests fail. It's very likely that add_action( 'rest_api_init', array( 'WP_REST_Abilities_Init', 'register_routes' ) ); will have to be called explicitly in the bootstrap file to account for the fact that vendor autoloading happens before any WP code is loaded.

@gziolo gziolo added the [Type] Enhancement New feature or request label Sep 3, 2025
@codecov
Copy link

codecov bot commented Sep 3, 2025

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.28%. Comparing base (769de9e) to head (9c305db).
⚠️ Report is 1 commits behind head on trunk.

Files with missing lines Patch % Lines
includes/bootstrap.php 0.00% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##              trunk      #55      +/-   ##
============================================
- Coverage     84.61%   84.28%   -0.34%     
  Complexity       96       96              
============================================
  Files             8        8              
  Lines           507      509       +2     
============================================
  Hits            429      429              
- Misses           78       80       +2     
Flag Coverage Δ
unit 84.28% <0.00%> (-0.34%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@budzanowski budzanowski force-pushed the fix/rest-api-composer-initialization branch from 77552b1 to 867af46 Compare September 3, 2025 14:06
@gziolo gziolo requested a review from justlevine September 3, 2025 15:12
Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

This looks like a good compromise to me. Thank you for proposing the enhancement.

@justlevine, I would appreciate your sanity check before we land and cut a new release.

Copy link
Contributor

@justlevine justlevine left a comment

Choose a reason for hiding this comment

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

Nothing here is breaking or going into core. Worst case in the ~7 weeks before merge someone reports a bug caused by a race condition on action loading, and we tell them to either to instead install it as a plugin or move their require_once vendor/autoload.php somewhere else 😅

A couple smaller and equally nonimportant comments on the diff, but otherwise LGTM 🚀


That said,

I think I still need a sanity check when it comes to this whole Composer use case (cc @Jameswlepage ). nonblocking feedback with that in mind:

  1. Is initialization something that is wanted/expected when autoloading a library? (I would usually assume no.)
  2. If it is (or the real use case is as a plugin), then do we even need an includes/boostrap.php or can we just use abilities-api.php as the entrypoint?

(Only tangential to this PR: is autoloading something that is wanted/expected or is a downstream require_once vendor/wordpress/abilities-api/{whatever-entrypoint}.php a better pattern for this particular repo's goals?)

require_once __DIR__ . '/rest-api/class-wp-rest-abilities-init.php';

// Initialize REST API routes when WordPress is available.
if ( function_exists( 'add_action' ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need the function check if we've already proven ABSPATH, or do we need ABSPATH if we're anyway checking for add_action() before running any WP code?

Copy link
Member

Choose a reason for hiding this comment

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

Good point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ABSPATH prevents processing of the file outside WP env - this is generally useful and in our context stops processing of the file during PHPUnit start procedure, when WP is not yet ready. We want to control the moment this gets loaded.

add_action tests could be considered redundant if ABSPATH is present. Though in WP startup procedure ABSPATH is defined earlier than add_action becomes available. Potentially we can have ABSPATH but no add_action. This just prevents a very "wrong" usage patter from crashing the site.

Copy link
Member

Choose a reason for hiding this comment

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

It's also fine to be extra careful. Let's land this as is, as it won't be included in WP core in the same fashion.

static function (): void {
require_once dirname( __DIR__ ) . '/abilities-api.php';
// Require ( to bypass require_once ).
require dirname( __DIR__ ) . '/includes/bootstrap.php';
Copy link
Contributor

Choose a reason for hiding this comment

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

(I'd feel better about skipping abilities-api.php if understood the purpose of all this, but since it's being left out of core, it doesn't actually matter)

Copy link
Contributor Author

@budzanowski budzanowski Sep 5, 2025

Choose a reason for hiding this comment

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

This is a test bootstrap. The purpose of this is to circumvent the quirkiness of PHPUnit which automatically loads autoloader, at the very beginning, and thus is triggering the loading of the library. Since it is doing this before WordPress environment has been loaded nothing gets actually loaded ( ABSPATH test prevents it ). Though PHP remembers the require_once calls. If we would load again abilities-api.php nothing would happen, because require_once for bootstrap.php file has been already called. Thus I have made a decision to call it directly for tests once again ( using require to force the load ) - after the WP environment has been loaded. This allows proper loading of all library elements and registering of the filter.

For normal operations from inside WP or a plugin this alterations would not be necessary - this is just for the unit tests and avoids tampering with require_once directives inside the production code which I wanted to avoid.

Copy link
Member

Choose a reason for hiding this comment

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

This one is tricky as autoloader requires the same file, but it doesn't run any logic because of ABSPATH check, so it looks that all is correct.

Copy link
Contributor

Choose a reason for hiding this comment

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

(@budzanowski yes I understood the what and the how, it's the premise that we should be "triggering the loading of the library" - or more precisely calling that autoloading is now conflated with instantiating the REST endpoint - but still have a separate bootstrap file that confuses me. The architectural implication is that there would be other functionality in ./abilities-api.php now or in the future that we'd no longer be able to test... but again since it's not true IRL it doesn't matter)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@justlevine I agree this could makes things tricky down the road, but I did not wanted to spend too much time anticipating what may be required in the future without actually knowing how this will be used. I bet we will be able to test ./abilities-api.php separately if needed so hopefully this is not limiting.

@gziolo gziolo enabled auto-merge (squash) September 5, 2025 07:26
@gziolo
Copy link
Member

gziolo commented Sep 5, 2025

I enabled auto-merge. It's interesting to see Claude on the list of commit authors 😄

@gziolo gziolo merged commit 21af812 into WordPress:trunk Sep 5, 2025
16 checks passed
@budzanowski
Copy link
Contributor Author

@justlevine Thank you very much for the review.

Is initialization something that is wanted/expected when autoloading a library? (I would usually assume no.)\

I agree in general about the initialization. But I think the pattern here is just to make all of the global functions available.

If it is (or the real use case is as a plugin), then do we even need an includes/boostrap.php or can we just use abilities-api.php as the entrypoint?

This is mostly a semantic separation. abilities-api.php is plugin entry point and boostrap.php is code logic entry point and it is used by composer autoloader to enable the functionality. They could be merged, but I see that we may in future require some logic in the plugin part that should not be part of the package backend.

@justlevine
Copy link
Contributor

They could be merged, but I see that we may in future require some logic in the plugin part that should not be part of the package backend.

I'm good with this separation seperation of concerns, thanks both for the contribution and your time with the explanation!

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

None yet

Development

Successfully merging this pull request may close these issues.

3 participants