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

Ability to specify the site for a request #16367

Merged
merged 4 commits into from
Jan 2, 2025

Conversation

nfourtythree
Copy link
Contributor

@nfourtythree nfourtythree commented Dec 31, 2024

Description

Adds the ability to specify the current site via an X-Craft-Site HTTP header.

The need for this feature is apparent in headless projects where the front end and control panel are decoupled.

Example project setup

  • The front end of the project is at example.com
  • Multisite (base URLs, example.com, example.com/us, example.com/uk etc)
  • The control panel is at cms.example.com
  • headlessMode config setting is set to true

In this setup requests from the headless front end will be sent to the control panel. With the fact that headlessMode is on and the base site URLs are separate from the control panel, it means there is a need for extra steps for making site-specific requests.

Taking the element API plugin requests as an example with the following config in element-api.php

<?php

use craft\elements\Entry;
use craft\helpers\UrlHelper;

return [
    'endpoints' => [
        'articles.json' => function() {
            return [
                'elementType' => Entry::class,
                'criteria' => ['section' => 'articles'],
                'transformer' => function(Entry $entry) {
                    return [
                        'id' => $entry->id,
                        'title' => $entry->title,
                        'siteId' => $entry->siteId,
                        'url' => $entry->url,
                    ];
                },
            ];
        },
    ]
];

A request to cms.example.com/articles.json will return entries with the siteId for the primary site. Because of the decoupled natured of the project you can't call cms.example.com/uk/articles.json as there is no routing for that.

It, of course, would be possible to pass the site handle as a parameter to the endpoint and then this would need to be done for all of the endpoints. The developer would also need to pass that parameter to everything else they were doing (say if there were other element queries in the transformer).

This PR adds the header X-Craft-Site (a site handle) to be able to tell Craft that the whole request is for a specified site. This way it can be done once, there is no need to pass around a handle/ID to each thing that happens. The current site will be set to the one in the header and things (element queries etc) will work as if it was that site was being requested (and be more like a non-headless implementation).

The above example is for the Element API plugin but this method will also work if you are calling the GraphQL endpoint as well. Again, the developer could specify the site or siteId in the GQL query but with this method only header would be needed.

The PR would also benefit Commerce. Commerce has front end controller actions that are currently looking at the requested site to figure out the store and set other data on products, orders etc. All of these actions could be updated to pass around a site ID/handle, making sure to pass down that data throughout all the code ensuring no site related queries are missed. However, with the feature outlined in this PR, those controllers and code would not need to change.


A couple of final notes.

I debated whether this should be a parameter (site) that could be specified in a query string or body or if it should be a header. I settled on a header due to the fact that it would be a new concept that wouldn't cause any conflicting issues with current code in projects.

The issue that this PR solves only shows itself in projects that are set up as highlighted above. There is a possibility that this could be a header that only is used with headlessMode on. But there could potentially be projects setup where the front end and CP are decoupled but the project isn't truly "headless"

src/web/Request.php Outdated Show resolved Hide resolved
@brandonkelly brandonkelly force-pushed the feature/ability-to-set-request-site branch from 71ace17 to 5d93583 Compare January 2, 2025 19:46
@brandonkelly brandonkelly changed the base branch from 5.6 to 4.14 January 2, 2025 19:47
[ci skip]
@brandonkelly brandonkelly changed the title [5.6] Ability to specify the site for a request Ability to specify the site for a request Jan 2, 2025
@brandonkelly brandonkelly merged commit 3db93e8 into 4.14 Jan 2, 2025
@brandonkelly brandonkelly deleted the feature/ability-to-set-request-site branch January 2, 2025 19:50
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