Skip to content
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

[REST] Restore the missing double slash in the ID received by /templates #36881

Merged
merged 13 commits into from
Nov 26, 2021

Conversation

adamziel
Copy link
Contributor

@adamziel adamziel commented Nov 25, 2021

Description

Solves https://core.trac.wordpress.org/ticket/54507

When the permalink structure is set to /index.php/%year%/%monthnum%/%day%/%postname%/, requests to /wp/v2/templates/twentytwentytwo//home fail, breaking the full site editor. The problem is double slash in the request path. WordPress resolves $request['id'] as twentytwentytwo/home instead of twentytwentytwo//home. The endpoint has already been shipped in WordPress 5.8, so changing the URLs structure isn't really an option. This PR proposes a way of processing the received ID so the slashes are always correct regardless of how they came in.

Test plan

  1. Go to WP Admin → Settings → Permalinks.
  2. Select Custom Structure and enter /index.php/%year%/%monthnum%/%day%/%postname%/ into the text field.
  3. Go to WP Admin → Appearance → Editor.
  4. Confirm the editor loads as expected with no WSOD in sight.

If this PR gets merged, it needs to also be backported into WP Beta.

@adamziel adamziel added Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta [Feature] Full Site Editing labels Nov 25, 2021
@adamziel adamziel self-assigned this Nov 25, 2021
@adamziel adamziel changed the title Try/use double slash as a fallback [REST] Fallback template resolution mechanism in the API endpoint Nov 25, 2021
@TimothyBJacobs
Copy link
Member

Will this work for subdirectory themes like theme-experiments/tt1-blocks?

@adamziel adamziel mentioned this pull request Nov 25, 2021
38 tasks
@adamziel adamziel changed the title [REST] Fallback template resolution mechanism in the API endpoint [REST] Fallback resolution mechanism in/templates Nov 25, 2021
@adamziel adamziel changed the title [REST] Fallback resolution mechanism in/templates [REST] Fallback resolution mechanism in/templates Nov 25, 2021
@youknowriad
Copy link
Contributor

The double slash is there for themes inside subfolders, the theme names for this kind of themes contain a "/" so that's why we needed the double slash. So you need to test with these themes as well.

@adamziel
Copy link
Contributor Author

adamziel commented Nov 25, 2021

Good points @youknowriad and @TimothyBJacobs. I think there are two options here:

  1. Try different cut-off points, e.g. a//b//c//d, a/b//c//d, a/b/c//d – it's O(n) so not too terrible. The loop would take each slash and try to double all the slashes on the right.
  2. Extract the relevant fragment from $_SERVER[ 'REQUEST_URI' ] and use that as a fallback.

What do you think?

@TimothyBJacobs
Copy link
Member

Does each check require a database query?

@TimothyBJacobs
Copy link
Member

And to clarify, the double slash is between the theme slug and the template slug. So you'd only ever have one double slash, and subdirectory themes aren't allowed at an arbitrary depth, only one level.

@adamziel
Copy link
Contributor Author

It does @TimothyBJacobs, with the REQUEST_URI way there would be less database queries.

@TimothyBJacobs
Copy link
Member

Yeah I think we could look at REQUEST_URI here. Though I think it'd be ideal if WP Rewrite would handle making sure the path is right in the first place. Not sure how feasible that is.

@Mamaduka
Copy link
Member

@adamziel, what if we try to normalize ID before making a DB call?

Something like: https://3v4l.org/JU4LI

$bad_id = 'twentytwentytwo/index';
$good_id = 'twentytwentytwo//index';
$theme = 'twentytwentytwo';

var_dump( preg_replace( "|$theme/+|", "$theme//", $bad_id ) );
var_dump( preg_replace( "|$theme/+|", "$theme//", $good_id ) );

I think %year%/%monthnum%/%day%/%postname%/ might be a popular permalink structure, and we might end up doing WP_Queries for each request.

P.S. Sorry about the bad regex.

@adamziel
Copy link
Contributor Author

adamziel commented Nov 25, 2021

@TimothyBJacobs I think the culprit is what @noisysocks mentioned in the original ticket:

This is because, when the "almost pretty" permalink structure, WordPress will use $_SERVER['PATH_INFO'] as the route. PATH_INFO will collapse double slashes.

We would have to infer that information from REQUEST_URI. I fear there will be a lot of tricky corner cases, but it's worth a shot.

what if we try to normalize ID before making a DB call?

@Mamaduka I'd love that, but I don't think we can just assume that $theme = get_stylesheet(). Alternatively, we could make REQUEST_URI the default and use $request['id'] as a fallback (or just ignore it).

@TimothyBJacobs
Copy link
Member

Alternatively, we could make REQUEST_URI the default and use $request['id'] as a fallback (or just ignore it).

We're going to need some additional checks here that the REQUEST_URI is sane according to the WP_REST_Request object I think. Because the REST server can process a request object without it coming thru WP_REST_Server::serve_request.

@adamziel
Copy link
Contributor Author

I went for a different, simpler approach. Given that template ID is generated like $theme//$slug and only $theme can contain slashes and $slug cannot, we only have to try doubling the last slash in $request['id']. It is much simpler than parsing REQUEST_URI.

Actually we could even sanitize it so that the last slash is always a double one – it is not optional to have it there.

@adamziel
Copy link
Contributor Author

I think this is in a pretty good place. The only thing that is missing is a test with template name like theme-experiments/tt1-blocks//index. I'm not sure how to add another theme to the test environment, though. I don't think we need to block this PR on that, let's make it a follow up.

@adamziel
Copy link
Contributor Author

I went for a unit test instead. I think this one is ready for feedback now. cc @mcsf @spacedmonkey @TimothyBJacobs @Mamaduka @draganescu @getdave

@adamziel adamziel changed the title [REST] Fallback resolution mechanism in/templates [REST] Restore double slash in the ID received by /templates Nov 26, 2021
@adamziel adamziel changed the title [REST] Restore double slash in the ID received by /templates [REST] Restore the missing double slash in the ID received by /templates Nov 26, 2021
@mcsf
Copy link
Contributor

mcsf commented Nov 26, 2021

Given that template ID is generated like $theme//$slug and only $theme can contain slashes and $slug cannot, we only have to try doubling the last slash […]

Oh, that changes everything. I thought part of the difficulty stemmed from there being no tighter rules in how users can name slugs, particularly around possible slashes.

@mcsf mcsf dismissed their stale review November 26, 2021 13:56

New approach renders my feedback no longer applicable

@adamziel
Copy link
Contributor Author

Let's confirm that with @youknowriad – from my explorations it seems like the template $slug adheres to the same rules as all other slugs in WordPress.

@Mamaduka
Copy link
Member

template $slug adheres to the same rules as all other slugs in WordPress.

That's correct. We just combine $theme//$post->slug for template IDs. So slug will adhere to rules of sanitize_title.

@draganescu
Copy link
Contributor

I think this ended up as a cleaner fix compared to previous explorations. We first default to what just works and only branch to a special case if we need to. Also the _sanitize_template_id is cleaner and easier to follow.

@TimothyBJacobs do you have any further comments?

Also I see the testing instructions is for seeing the WSOD is fixed, but are there any other cases in themes in subfolders than could be affected?

Copy link
Contributor

@draganescu draganescu left a comment

Choose a reason for hiding this comment

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

LGTM with the caveat that I don't know if anything else could be broken by autodoubling we do here, other than fixing our problem. However the resulting changeset is quite lean so if it does break things it's easy to track.

@adamziel adamziel merged commit 7676a59 into trunk Nov 26, 2021
@adamziel adamziel deleted the try/use-double-slash-as-a-fallback branch November 26, 2021 15:06
@github-actions github-actions bot added this to the Gutenberg 12.1 milestone Nov 26, 2021
@adamziel
Copy link
Contributor Author

Also I see the testing instructions is for seeing the WSOD is fixed, but are there any other cases in themes in subfolders than could be affected?

I don't think E2E covers having a theme in a subdirectory, it would be nice to add that (as I mentioned above). Otherwise, I think all the bases are covered. Plus reverting this one should be easy as you said.

@noisysocks noisysocks removed the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Nov 29, 2021
noisysocks pushed a commit that referenced this pull request Nov 29, 2021
…tes (#36881)

* Fall back to a double-slashed template name if a single-slashed one is missing

* Add a unit test

* Use $_SERVER['REQUEST_URI'] as a fallback instead of simply replacing all slashes with a double slash.

* Fallback to parsing the query string instead of doing it by default

* Code style

* Update docstring

* Try doubling the last slash instead of parsing REQUEST_URI

* Use sanitize_callback

* Lint

* Test for both single and double slash

* Add unit tests for _sanitize_template_id

* Update phpunit/class-gutenberg-rest-template-controller-test.php

* Update phpunit/class-gutenberg-rest-template-controller-test.php
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.

8 participants