Hi @sounderly.help. Well, you don’t say or show what your workflow is doing, so I’m not sure what might be going on. But in case it isn’t clear how this technique works, and how it’s implemented in the “gibu” example, I’ll give a little more explanation here.
The profile page (the page named “u”) can understand what User we want to view in two different ways: (1) Using the built-in Bubble mechanism (the page object for page “u” has a type - User) and will automatically fetch the right user if the path is a user’s unique ID. (2) if the path is something else, workflows get the path and try to resolve a User via doing a Search to see if the path value matches some User’s username (a field we made on User).
In case 1, the built-in Bubble state/feature “Current Page’s Thing” (Current Page’s User in this case) will have a value (the correct User). In case 2, Current Page’s User will remain empty/null – and we can’t manually set that value. So we need a place to store our User, should we find one. What I did is put a custom state on the page itself – it’s called “Retrieved User” (its data type is User of course) and since the page is called “u”, this value can be referenced as “u’s Retrieved User”.
So then there are 3 workflows that do the “URL magic”, because there are 3 specific cases that can happen:
1. There is no path specified. (e.g., someone visits https://gibu.bubbleapps.io/u directly):
In this case, there is no user we can retrieve (we’ve not been given anything to go on), so we know we can show the “Not found” group, rather than present this page as someone’s profile. This also handles the case where for some other reason, Current Page User becomes empty (which might be something that can happen…).
2. A path is specified, but that path must not have been the unique ID of a User. (e.g., The Profile Page or The Profile Page) If Current Page User is empty, but there’s some string in the path, we know that Bubble’s attempt to automagically retrieve a User has failed. So we examine the URL ourselves:
What we need to do in this case is “Get Path from URL” and Search to see if there is a User with a username that matches that path, and put that value in our custom state (“Retrieved User”). And that’s what I do here, but I do it in sort of a fancy way.
Rather than just grabbing the string found in the path (which would be fine for a user like username “the-real-emily”), I grab the path and URL decode it first. This allows us to handle usernames that have special characters in them – like emojis!
Look at the “debug info” text at the top of this page, for example: The Profile Page
While you and I see emoji’s here in the browser, this URL is actually:
https://gibu.bubbleapps.io/version-test/u/%F0%9F%8C%88%F0%9F%8D%A9
%F0%9F%8C%88%F0%9F%8D%A9
is the URL encoded version of “rainbow donut”.
We decode that with a single line of JavaScript in the Expression element at the top right of the page:
So that’s why my Search for Users constraint uses Expression: URI Decoder's value
rather than just Get path from page URL
. You don’t have to do this, but I think it’s neat and I’ve seen folks here in the forums try to keep users from having special characters in their usernames - probably for this reason. So we’re killing multiple birds with one stone here.
Moving to step 2 in our workflow: Now we use the Browser plug-in to modify the URL that appears in the browser bar.
You might be thinking that we don’t need to do this. Doesn’t the condition here (page’s User is empty but the path is not empty) already tell us that the URL is one that tries a username as the path? Well, yes it does. So this step might in fact be redundant… but there might be an edge case and it ain’t hurtin’ nobody, so I’ve left it here. (You could experiment with taking it out of this particular workflow as it does seem that it might be redundant with the same step in the next workflow I will discuss. Details on this workflow step are described in the next section.)
Now that we’ve retrieved a User via Search and stashed them in Retrieved User, there is one more thing we need to handle. That Search might turn up empty, right (e.g., there isn’t a user with username “taco-basket” or whatever)? So if Retrieved User is empty/null, we will show the “No User found” group.
There’s one more case we need to handle…
3. Bubble did find a User automagically. That is, the URL path must have contained the unique ID of an existing User. Great, we know what User to display! However, we have to now put that User into the Retrieved User custom state (because all the objects on our page rely on Retrieved User, not page’s User).
Also, the whole point of this exercise is to present a “friendly” URL on this page, so when the URL is the ugly kind (as it is in this case), we want to use Browser to present the friendly version.
So here are the steps:
Set the Retrieved User state to Current Page User:
Now use Browser to rewrite (Modify) the URL shown:
The Browser element (like the Expression element) is up the right hand corner of the page, BTW. It just has its default name in this project (“Browser A”). What we’re doing in the step here is modifying the URL to its friendly version. What we are doing conceptually is this:
Our URL is initially something like this:
https://gibu.bubbleapps.io/version-test/u/1548712862884x690205385654159600?debug_mode=true
It’s our website’s base URL (which there are many versions of, right?), followed by u (the page name), a slash, and then our User’s unique ID is the path. And we might ALSO have URL parameters as we do here (debug_mode is on). We should ideally preserve those, right?
When we use the built-in Navigate > go to page action in Bubble, this is the type of URL that will be constructed.
We want to turn that URL into its “friendly” version which should be like:
https://gibu.bubbleapps.io/version-test/u/the-real-emily?debug_mode=true
That’s our website’s base URL (again, there are many variations like with and without version-test, with and without version-live, etc.), followed by u (the page name), a slash, and then our User’s username as the path. And, ideally, we should preserve the URL parameters part, too.
Bubble makes this pretty easy to do… if you know how to do it. So let’s just go through the URL field here to explain how that works… First, we need the base URL. You might be inclined to just type that out:
https://gibu.bubbleapps.io
… but then how do we handle /version-test/ and /version-live/ and whatever?
Well, we don’t have to. Bubble has a magic expression/variable for this: Website home URL
. This expression takes care of all the different cases for us. Cool. Note that the “home URL” includes a trailing slash.
Now we have to put the page name. Unfortunately, there’s not an equally simple expression/variable that just returns to us the page name by itself. (We could do various convoluted things, but it’s easiest just to type the page name here.) So we type u and then a slash.
Now we write out the username from Retrieved User. The expression for that is u's Retrieved User's Username
in my example app.
The last part handles any URL parameters that may be hanging around and preserves them. Here’s how we do that: The expression/variable This url
is the complete URL from the browser.
So if the URL we visited with is https://gibu.bubbleapps.io/version-test/u/1548712862884x690205385654159600?debug_mode=true
, that’s what’s returned by “This url”.
The only part we are interested in is everything after the path. Now, there’s a lot of different ways we could manipulate the string via RegEx to chop that part off and keep it, but in this case it’s easier to just use the built in :find and replace
function:
The URL is like this:
https://gibu.bubbleapps.io/version-test/u/1548712862884x690205385654159600?debug_mode=true
So we can just “find” the first part – because we know how to construct it (Website home URL the letter u a slash and the path)… and “replace” that by nothing (null/empty/a blank input). If there’s anything after the path in the original URL, that’s all that will be left. If there’s nothing after the path, nothing will be left. Perfect.
4. You might have noticed there’s a 4th green workflow. This one isn’t for URL handling, but it’s here because there’s an edge case that seems to happen in my example app. This workflow just Element > Hides the “No user found” group whenever the Retrieved User value is not empty:
You might be wondering: "Why in the heck do you bother to do that? Just have a Condition on that group that makes the group not visible when Retrieved User isn’t empty, you big dummy… Like this:
"
And indeed, I DO have such a condition on that group. But that condition does not seem to take effect if Retrieved User starts empty and then gets a value. (As when you visit the page without a path and then click on one of the users in the RG.) The condition evaluates properly, but the group itself does not go invisible. It’s weird and this may be a bug in Bubble (if so, it’s sort of a complicated edge case I guess).
So, this workflow just takes care of that problem by doing the hiding via an action. Dunno what else to say about this one.