Great, thanks @mmczaplinski! I think that after solving the issue you mention the link processor should work fine with these settings.
I thought that wordpress.com sites with custom domains had the REST API in https://domain.com/wp-json but that doesnât seem to be the case for https://artistintheshed.com.
Maybe that only happens in the Bussiness plan, the one where you can add custom plugins, but not in the Personal or Premium plan.
At least https://public-api.wordpress.com/wp/v2/sites/artistintheshed.com/ seems to work fine, so I guess we should promote the use of https://artistintheshed.com in state.source.url
and not https://artistintheshed.wordpress.com for that case, which is what Michal proposed in version 2:
But I donât think that is working right now, is it? Because state.source.api
is not checking state.source.isWpCom
to check if the site is a WordPress or not, it is doing its own logic:
Code in: https://github.com/frontity/frontity/blob/dev/packages/wp-source/src/state.ts#L73-L87
{
api: ({ state }) => {
// Check if it's a free WordPress.com site.
if (/^https:\/\/(\w+\.)?wordpress\.com/.test(state.source.url))
return addFinalSlash(
`https://public-api.wordpress.com/wp/v2/sites/${state.source.url}`
);
return addFinalSlash(
addFinalSlash(state.source.url) + state.wpSource.prefix.replace(/^\//, "")
);
},
isWpCom: ({ state }) =>
state.source.api.startsWith(
"https://public-api.wordpress.com/wp/v2/sites/"
),
};
If I am right, I guess we need to use state.source.isWpCom
inside state.source.api
. Something like this:
{
api: ({ state }) => {
// Check if it's a WordPress.com site (free, personal or premium).
if (state.source.isWpCom)
return addFinalSlash(
`https://public-api.wordpress.com/wp/v2/sites/${state.source.url}`
);
return addFinalSlash(
addFinalSlash(state.source.url) + state.wpSource.prefix.replace(/^\//, "")
);
},
};
Of course also with the fix proposed by @mburridge that removes the protocol from the URL: https://github.com/frontity/frontity/issues/622#issuecomment-732139397.
Youâre right about checking the isWpCom
@luisherranz . Ideally, we should check if thatâs the case inside state.source.api
but Iâve realized that the problem is that this would introduce mutual infinite recursion
The state.source.api
is checking the state.source.isWpCom
in itâs definition and vice versa. So if the user does not define the isWpCom
themselves, youâll get a âMaximum stack call exceededâ exception.
However, we can check if the state is a derived state using Object.getOwnPropertyDescriptor()
I think we will then need a slightly more complex check like this:
{
api: ({ state }) => {
// Check if it's a free WordPress.com site.
// We have to make sure the `.isWpCom` is NOT a derived state because otherwise
// we would end up in an infinite loop.
if (
typeof Object.getOwnPropertyDescriptor(state.source, "isWpCom").value ===
"boolean" &&
state.source.isWpCom
) {
return addFinalSlash(
`https://public-api.wordpress.com/wp/v2/sites/${state.source.url}`
);
}
return addFinalSlash(
addFinalSlash(state.source.url) + state.wpSource.prefix.replace(/^\//, "")
);
},
isWpCom: ({ state }) =>
// The user can define either the `state.source.url` or `state.souce.api`
// so we should try to detect either of those cases automatically.
/^https:\/\/(\w+\.)?wordpress\.com/.test(state.source.url) ||
state.source.api.startsWith(
"https://public-api.wordpress.com/wp/v2/sites/"
),
}
This will still fail if the user has a site on wordpress.com with a custom domain but has NOT specified "isWpCom": true
. I think that there is nothing that we can do about it though because if the user chooses to use their custom domain, Frontity cannot just know if itâs a wp.com or wp.org.
So, we will have to make it explicit in the documentation that when using a wp.com site with a custom domain, the user has to pass the isWpCom: true
in their settings.
Nice trick! Maybe we could even release a isDerived()
tool based on that code
const isDerived = (obj, propName) =>
typeof Object.getOwnPropertyDescriptor(obj, propName).value === "function";
Regarding the code, I think you still have to check inside state.source.api
if state.source.url
is from a subdomain.wordpress.com site because you cannot rely on state.wpSource.isWpCom
for that:
const api = ({ state }) => {
// Is it a WordPress.com site with a custom domain?
const isCustomWpCom =
!isDerived(state.wpSource, "isWpCom") && state.wpSource.isWpCom;
// Is it a free WordPress.com site using a subdomain.wordpress.com domain?
const isFreeWpCom = /^https:\/\/(\w+\.)?wordpress\.com/.test(
state.source.url
);
if (isCustomWpCom || isFreeWpCom) {
const { hostname } = new URL(state.source.url);
return addFinalSlash(
`https://public-api.wordpress.com/wp/v2/sites/${hostname}`
);
}
return addFinalSlash(
addFinalSlash(state.source.url) + state.wpSource.prefix.replace(/^\//, "")
);
};
Donât you think?
yep, youâre right about that and thatâs a clearer implementation as well!
Awesome. I have just opened a FD for the isDerived
util
We have a lot of cases so I have made a table to make sure we donât forget any of them and we add tests for all of them.
state.frontity.url | state.source.url | state.source.api | state.wpSource.isWpCom | |
---|---|---|---|---|
Free WP com - configured by state.source.url | Set by the user: final-domain.com | Set by the user: sub.wordpress.com | Derived from state.source.url: sub.wordpress.com/wp-json | Derived from state.source.api: true |
Free WP com - configured by state.source.api | Set by the user: final-domain.com | Derived from state.frontity.url: final-domain.com | Set by the user: public-api.wordpress.com/wp/v2/sites/sub.wordpress.com | Derived from state.source.api: true |
Personal and Premium WP com - configured by state.source.url and state.wpSource.isWpCom | Set by the user: final-domain.com | Set by the user: final-domain.com | Derived from state.source.url: public-api.wordpress.com/wp/v2/sites/final-domain.com | Set by the user: true |
Personal and Premium WP com - configured by state.source.url and state.source.api | Set by the user: final-domain.com | Set by the user: final-domain.com | Set by the user: public-api.wordpress.com/wp/v2/sites/final-domain.com | Derived from state.source.api: true |
Personal and Premium WP com - configured by state.source.api | Set by the user: final-domain.com | Derived from state.frontity.url: final-domain.com | Set by the user: public-api.wordpress.com/wp/v2/sites/final-domain.com | Derived from state.source.api: true |
WP org and Business WP com - configured by state.source.url | Set by the user: final-domain.com | Set by the user: wp-domain.com | Derived from state.source.url: wp-domain.com/wp-json | Derived from state.source.api: false |
WP org and Business WP com - configured by state.source.api | Set by the user: final-domain.com | Derived from state.frontity.url: final-domain.com | Set by the user: wp-domain.com/wp-json | Derived from state.source.api: false |
You can use https://www.tablesgenerator.com/markdown_tables if you want to edit the table. I think copy/pasting shoud work.
Last thing: WordPress.com has 5 plans (https://wordpress.com/pricing/). These are the relations with the configuration:
- Free: Free WP com
- Personal and Premium: Personal and Premium WP com
- Business: WP org and Business WP com (these sites have a final-domain.com/wp-json so they can act as regular WP org sites).
- eCommerce: I have no idea, to be honest.
Does this change have any implications for libraries.source.api.init
? Do we need to make any changes to the documentation there?
https://docs.frontity.org/api-reference-1/wordpress-source#libraries-source-api-init
I donât understand some of the cases you mentioned on the table.
When you talk about these three specifically:
- Free WP com - configured by state.source.api
- Personal and Premium WP com - configured by state.source.api
- WP org and Business WP com - configured by state.source.api
What do you mean exactly when you say that state.source.url
is derived from state.frontity.url
? Shouldnât it be derived from state.source.api
?
I thought state.source.url
should point to the WordPress instance, not the Frontity one. Except for the embedded mode: in that case, I guess state.frontity.url
and state.source.url
would be the same.
I donât know why that API is documented, to be honest. That init
is internal and not meant to be used by other packages, only by the source package.
In this specific case, we even have plans to remove it in the not so distant future. So could you please remove it from the docs?
I think we never thought that state.source.url
could be derived from state.source.api
if state.source.api
is defined by the user (not derived) but I guess that with Michalâs isDerived
function we can do that.
Actually, that would mean that state.source.url
is backward compatible and safer to use than it is today.
Is it feasible technically to do it?
Yup, it is. I already wrote the tests for that and all of them are passing. So, yeah.
Ok, is this table correct then?
state.frontity.url | state.source.url | state.source.api | state.source.isWpCom | |
---|---|---|---|---|
Free WP com - configured by state.source.url | Set by the user: final-domain.com | Set by the user: sub.wordpress.com | Derived from state.source.url: public-api.wordpress.com/wp/v2/sites/sub.wordpress.com | Derived from state.source.api: true |
Free WP com - configured by state.source.api (backward compatibility only) | Set by the user: final-domain.com | Derived from state.source.api: sub.wordpress.com | Set by the user: public-api.wordpress.com/wp/v2/sites/sub.wordpress.com | Derived from state.source.api: true |
Personal and Premium WP com - configured by state.source.url and state.wpSource.isWpCom | Set by the user: final-domain.com | Set by the user: final-domain.com | Derived from state.source.url: public-api.wordpress.com/wp/v2/sites/final-domain.com | Set by the user: true |
Personal and Premium WP com - configured by state.source.url and state.source.api (backward compatibility only) | Set by the user: final-domain.com | Set by the user: final-domain.com | Set by the user: public-api.wordpress.com/wp/v2/sites/final-domain.com | Derived from state.source.api: true |
Personal and Premium WP com - configured by state.source.api (backward compatibility only) | Set by the user: final-domain.com | Derived from state.source.api: final-domain.com | Set by the user: public-api.wordpress.com/wp/v2/sites/final-domain.com | Derived from state.source.api: true |
WP org and Business WP com - configured by state.source.url | Set by the user: final-domain.com | Set by the user: wp-domain.com | Derived from state.source.url: wp-domain.com/wp-json | Derived from state.source.api: false |
WP org and Business WP com - configured by state.source.api (backward compatibility only) | Set by the user: final-domain.com | Derived from state.source.api: wp-domain.com | Set by the user: wp-domain.com/wp-json | Derived from state.source.api: false |
I am not taking into account state.wpSource.api
and state.wpSource.isWpCom
now.
I have done a graph of the logic, but I would like to review this with you. Let me know whenever you can and we will jump in a quick call.
I would like to also review with you:
state.wpSource.api
state.wpSource.isWpCom
Ok, we have carefully reviewed the logic and I think we got it right this time
Not only that, but thanks to @mmczaplinskiâs isDerived
function and @David who noticed that we can use that to derive state.source.url
from state.source.api
, now state.source.url
is backward compatible and safe to use in any package!! .
Awesome work guys
Thanks also to @mburridge for bringing into our attention the problem with wordpress.com sites that have custom domains but canât use /wp-json
.
This is the final logic @david is implementing:
I think that there is a small error in the table that youâve created @luisherranz. Iâve explained it in the Loom.
I just wanted to clarify this because the DevRel team is currently documenting the feature and I want to make sure that we really nail it
Also, think that the crucial bit that should be documented is which settings the user will need depending on what kind of hosting they are on. I think that the final table should look like:
Free, Personal or Premium wordpress.com | Business wordpress.com or wp.org | |
---|---|---|
needs state.source.url
|
YES | YES |
needs state.source.api
|
should either set this | NO |
needs state.wpSource.isWpCom
|
or set that or both | NO |
Iâve linked here from the PR to add docs for state.source.url
because it was not 100% clear to the DevRel team from the Discussion above which information should be documented and which one was implementation detail.
Iâm not 100% sure I got the problem you see. To me the table is right. Iâve made a video explaining it in more depth: Loom | Free Screen & Video Recording Software
Let me know if that is correct or there is still something I am not getting
For me the table for the docs should be something like this:
Free wordpress.com | Personal or Premium wordpress.com | Business wordpress.com or wp.org | |
---|---|---|---|
needs state.source.url
|
YES | YES | YES |
needs state.wpSource.isWpCom
|
NO | YES | NO |