WpSource: Define a map of `allowedQueries` to only preserve them in data references (links)

Description

When using @frontity/wp-source, you may want some different links to point to the same data object if they only differ by the search query (like links with a utm_campaign parameter). For example, these calls should return the same data object:

state.source.get("/2016/the-beauties-of-gullfoss/");
state.source.get("/2016/the-beauties-of-gullfoss/?utm_campaign=twitter");

As some links with query parameters can actually point to different data objects (e.g. the search parameter, ?s=some+search), in this case, you would want state.source.get(link) to return a different data object for each one. For instance, these calls should return different data objects:

state.source.get("/category/nature/");
state.source.get("/category/nature/?s=some+param");

The main idea is to implement an option called allowedQueries in @frontity/wp-source to specify which query params should be preserved in the data links. Those that were not specified would be internally removed.

Examples

  • UTM query params (/my-post?utm_campaign=frontity)
    Users wouldn’t want them to generate a new data object. In this case, it would be enough not to include any of the utm_campaign, utm_source, etc. params inside state.wpSource.allowedQueries (or set them to false).

  • Searches (/my-tag/?s=some+search)
    To make this param to return a new data object, it should be included in state.wpSource.allowedQueries:

    state: {
      wpSource: {
        allowedQueries: { s: true }
      }
    }
    
  • Previews (/my-post?preview=true)
    Again, to make this param to return a new data object, it should be included in state.wpSource.allowedQueries:

    state: {
      wpSource: {
        allowedQueries: { s: true, preview: true }
      }
    }
    

Requirements

  • This functionality should be specific to @frontity/wp-source.
  • The value of state.router.link should not be modified - that means the query filtering should only happen internally in @frontity/wp-source.
  • libraries.source.normalize() implementation should remain the same as other packages rely on it. Right now, it works like a kind of link prettifier.

Possible solution

I think the best way to go here is to modify the wp-source implementation of the API that generates and returns data objects, i.e. actions.source.fetch(link) and state.source.get(link).

They should behave just like passing the link argument without those params. So, prior to run any logic, they should remove any param that is not specified in state.wpSource.allowedQueries, and then continue the normal execution.

Some insights

  1. This feature could be deprecated in the near future because the same could be easily implemented using Frontity hooks.

  2. This also would partially fix state.router.link mismatch when the URL is not the same in the server as in the client #623. But, to completely solve it, we would have to change @frontity/tiny-router as well so it replaces state.router.link with the link in the browser during the init() action. That way, any query param modified in server-side would be preserved in the client. Also, other packages relying on state.router.link would get the correct value, not the altered one, so I think we should do this anyway.

  3. I’m not sure what should be the default value for state.wpSource.allowedQueries. There is a problem if we just leave @frontity/wp-source to do the same thing it’s doing right now (i.e. to create a data object for every different link) by default. Doing the changes described above, the app would crash during hydration in the case the server link and the client link contain different queries. That, of course, could be fixed by setting state.wpSource.allowedQueries appropriately. But yeah, that makes me think it’s not the best default behavior. Any ideas on here are welcome. :blush:

Thanks for the FD @david :slightly_smiling_face:

I guess the main question here is:

  • Do we wait until we have Frontity hooks to do this?
  • Or do we create something for Source v1?

And if we create something for Source v1, we do so:

  • Only for queries, like David is proposing here?
  • Maybe for queries and for post/pages pagination? (Posts/pages pagination)
  • Fully featured and extensible, like what I explained in the Router Converters FD (which is basically the same concept, but for actions.router.set())?

Why not make it a blacklist instead of a whitelist? I don’t think we can make a whitelist backward compatible anyway.

Any update to this feature?

I had to implement what I feel is a hack in the beforeSSR actions (see code below) to not allow the utm param to be passed to the wp api, as it was giving me a 404 return:

// Removing param from router link so that its not passed to the WP json api
var find = state.router.link.indexOf("utm");
if (find > 0) {
  state.router.link = state.router.link.split('?')[0];
 }