Awesome work Michal! Thanks
There are different options here to define the new source.url
and I am not sure what is best:
- We can define it in the general settings, like
frontity.url
. - We can define it in the source package, like the old
source.api
.
Both of them will work, but we should reach an agreement to see how we document and explain it.
If we take mars-theme as example, the initial frontity.settings.js would look like this:
1. Defining source.url in the general settings
const settings = {
name: "new-project",
state: {
frontity: {
url: "https://test.frontity.org",
title: "Test Frontity Blog",
description: "WordPress installation for Frontity development",
},
source: {
url: "https://test.frontity.org",
},
},
packages: [
{
name: "@frontity/mars-theme",
state: {
theme: {
menu: [
["Home", "/"],
["Nature", "/category/nature/"],
["Travel", "/category/travel/"],
["Japan", "/tag/japan/"],
["About Us", "/about-us/"],
],
featured: {
showOnList: false,
showOnPost: false,
},
},
},
},
"@frontity/wp-source",
"@frontity/tiny-router",
"@frontity/html2react",
],
};
export default settings;
The wp-source
package would come up with no configuration, and if users want to add some settings, like postTypes for example, they would need to change it from a string to an object, like the theme.
If we release new source packages like wpgraphql
in the future, users don’t have to change this setting.
2. Defining source.url in each source package
const settings = {
name: "redirects",
state: {
frontity: {
url: "https://test.frontity.org",
title: "Test Frontity Blog",
description: "WordPress installation for Frontity development",
},
},
packages: [
{
name: "@frontity/mars-theme",
state: {
theme: {
menu: [
["Home", "/"],
["Nature", "/category/nature/"],
["Travel", "/category/travel/"],
["Japan", "/tag/japan/"],
["About Us", "/about-us/"],
],
featured: {
showOnList: false,
showOnPost: false,
},
},
},
},
{
name: "@frontity/wp-source",
state: {
source: {
url: "https://test.frontity.org",
},
},
},
"@frontity/tiny-router",
"@frontity/html2react",
],
};
export default settings;
For new source packages, users would have to add this setting to this package, even though it is the same for all the source packages.
I personally don’t have a strong opinion here about which option is better.
@juanma @mburridge Which option do you think fits better in the learning journey you are working on? How would be easier to explain Frontity?
I vote to keep doing it the same way we have done it up until now because that part of the state belongs to the source
package.
{
name: "@frontity/wp-source",
state: {
source: {
url: "https://test.frontity.org",
},
},
}
I think it would be confusing to start defining some settings for some packages outside of the package definitions.
I agree, I think it’s easier to understand that changes in specific namespaces of the state are done in the settings of the package assigned to that namespace
But, if this release includes the use of state.frontity.url
when state-source.url
is not defined I would start promoting this
const settings = {
name: "new-project",
state: {
frontity: {
url: "https://test.frontity.org",
title: "Test Frontity Blog",
description: "WordPress installation for Frontity development",
}
},
packages: [
{
name: "@frontity/mars-theme",
state: {
theme: {
menu: [
["Home", "/"],
["Nature", "/category/nature/"],
["Japan", "/tag/japan/"],
["About Us", "/about-us/"],
]
},
},
},
"@frontity/wp-source",
"@frontity/tiny-router",
"@frontity/html2react",
],
};
export default settings;
that (in my opinion):
- it encourages the idea of zero-config
-
featured
settings can be let as the default ones defined for the theme - less code, easier to understand
- we only write the URL of WordPress once
I agree that having the WP URL in two places can be confusing. I think that state.frontity.url
should be the one that we document, and just mention that state.source.api
exists for backward compatibility, or that you can use state.source.url
if you’re adding more properties to the source package.
Otherwise, I think that @juanma’s example above looks much cleaner and less cluttered, and so is less confusing. I think that’s the version of frontity.setting.js
that should be in a new install of Frontity, i.e. with just the single line "@frontity/wp-source",
and the url under state.frontity.url
.
My understanding is that state.source.api
and state.source.url
have precedence over state.frontity.url
so if we keep one of those we need to document that it should be removed so that state.frontity.url
is the one that will be used, or that that is the one that needs to be configured with the WP API url - I think this would be messy and confusing.
I think I might have found a problem with wordpress.com sites where the owner is using a custom URL. I’ve explained it in this loom video
I am not sure we should do that. Right now, at least until the embedded mode is ready and promoted, users will always have to define both frontity.url
and source.url
, because that is needed for the Decoupled mode.
-
frontity.url
: This is the frontend url, the one pointing to node.js. Ex: mysite.com -
source.url
: This is the backend url, the one pointing to WordPress. Ex: wp.mysite.com
I think this could be the issue you are facing @mburridge. You are defining the WordPress url in the frontity.url
setting. It should go in the source.url
. In your case:
-
frontity.url
: http://localhost:3000. -
source.url
: http://mysite.wordpress.com
I thought that the frontity.url
means that you don’t need the source.url
- though you can still use it, or even source.api
if you want. Is my understanding incorrect?
I made the change you specified and the problem still exists with internal links when a wordpress.com site is using a custom domain.
@mburridge, it works like Mario described it:
state.frontity.url
: The URL of Frontity.
state.source.url
: The URL of the backend (WordPress).
-
Decoupled mode (two different domains):
- Frontity:
state.frontity.url
-> mars.frontity.org - Backend:
state.source.url
-> test.frontity.org
- Frontity:
-
Embedded mode (same domain for both):
- Frontity:
state.frontity.url
-> frontity.org - Backend:
state.source.url
-> frontity.org
- Frontity:
Only in Embedded mode, where both Frontity and the backend are in the same domain, you can omit state.source.url
and if you do, it will take the value of state.frontity.url
as a fallback.
-
Embedded mode (same domains for both):
- Frontity:
state.frontity.url
-> frontity.org - Backend: missing
state.source.url
->state.frontity.url
-> frontity.org
- Frontity:
@luisherranz thanks for the clarification. That makes sense. The problem with the link processor on wordpress.com sites using a custom domain is still an issue though.
Sorry I said the state.frontity.url
had to be localhost:3000
. I’ve rewatched the video and it seems the frontend you are expecting is https://artistintheshed.com/, is that right? If that’s the case state.frontity.url
should be that one.
OK, I’m confused.
- Frontity is running locally on
localhost:3000
. - The wordpress.com site is at
https://artistintheshed.wordpress.com
. - The custom URL is
https://artistintheshed.com
.
What should my settings in frontity.settings.js
be for:
state.frontity.url
state.source.url
?
I think I misunderstood you as well
It seems that https://artistintheshed.wordpress.com is redirected to https://artistintheshed.com, and if we take a look at the API, https://public-api.wordpress.com/wp/v2/sites/artistintheshed.com/, seems to work fine.
With this in mind I assume that:
-
state.source.url
:https://artistintheshed.com
. -
state.frontity.url
:http://localhost:3000
or wherever your Frontity app is.
I guess you will have to define somewhere that state.source.url
is a WP.com site, but I am not sure what is the best way to do this, I guess you would need to set state.source.isWpCom: true
.
Could you help us here @mmczaplinski please?
If state.source.url
is set to https://artistintheshed.com
then I get a 404 - I guess because that’s not a valid link to the API. Adding state.source.isWpCom: true
doesn’t make a difference.
If state.source.url
is set to https://artistintheshed.wordpress.com
then it works as that points to the API at wordpress.com.
But then the link component problem that I describe in the loom video occurs - I guess because the internal links pointing to artistintheshed.com/whatever
don’t match the hostname part of the URL which is artistintheshed.wordpress.com
as far as Frontity is concerned.
By the way, this site is just an example because I know they have a custom URL. This problem will occur for any wordpress.com site with a custom URL.
@SantosGuillamot Let me know if this is what you expected me to explain
I think that there is some confusion because we have this bug that @mburridge has reported: https://github.com/frontity/frontity/issues/622.
As a matter of fact, the solution that Michael posted in the github issue is probably correct (or very close to what we it should be) so thanks Michael!
So, assuming that the bug I’ve mentioned is fixed, we should be able to do either of two things:
Version 1.
-
state.source.url
:https://artistintheshed.wordpress.com
-
state.frontity.url
:http://localhost:3000
or wherever your Frontity app is.The url points directly to a site that ends in
wordpress.com
so frontity can detect that and set upstate.source.api
correctly.
Version 2.
-
state.source.url
:https://artistintheshed.com
-
isWpCom
:true
-
state.frontity.url
:http://localhost:3000
or wherever your Frontity app is.In this case, frontity does not know that
https://artistintheshed.com
is a wp.com site, so we have to tell Frontity that
Hope this helps!
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?