Social sharing friendly URL?

I remember trying to achieve this with my app a few months back and unfortunately I found no solution. However I did find a work around, which may not be as sleek but it still achieves the same result:
Get your app to find a user from a data key. Set up a workflow to trigger when the page is loaded that will set the pages ‘User’ to the data key. To do this choose ‘Get data from URL’ then set the key to ‘User’ or ‘Profile’. The URL will then be “.com/user_profile?user=hamper”

I hope this made sense. It was kind of complicated to explain.

1 Like

See this: Individual URL's for users

@romanmg

Thanks for responding. You had me all the way up until "Then everything within would just be “Parent groups [field]”

“Get data from page URL” has 2 types available - parameter and path. Choose Path."

Simply because my user_profile page has TONS and TONS of functionality and I don’t think this is a practical approach for me. When I tried it caused me a lot of issues, especially when implementing “Parent groups”…

Thanks for the response. I appreciate the help. I need it to be simplified to “user_profile/username”

1 Like

This (profile pages with username URLs) is discussed as nauseum here in the forums. Here are several threads that may be helpful.

First, here’s an excruciatingly detailed description of how to do this, what you can do, and what you can’t do:

More recently, @marcuslate asked about this and got all the same info, some presented on a different way:

Super Clean URLs

@marc2 also asked about this recently, he got a lot of the same feedback, though this thread also touches on applications of the Browser plugin:

1 Like

@keith

o_0 why is this so hard? This is my failed attempt at following your directions:

Step 1
image2

Step 2 – I used the recommended ([A-Z][a-z])(?=[A-Z])
image3

Step 3
image4

And it doesn’t work, so I’ve done something wrong

I only need the ability to extract the username. I don’t care about first and last name, like in your example. So lets say for example that the user name is Anthony Bigums. I’d be fine with a URL being “.com/user_profile/Anthony-Bigums”

1 Like

@keith

I feel like I’m close, but it still isn’t working:

i2

hours into trouble shooting this :persevere:

Step 1: thisPath is reading the URL
Step 2: username is using a Regex code to extract the username from the URL
Step 3: is taking the extracted username and matching it to the username?

My confusion is, how is this being applied to the structure of the URL? I don’t understand…

Isn’t there just an easy way to remove Unique Id from the URL or something? This just isn’t working, no matter what I try…

As Keith says, it is entirely possible, and there are lots of threads.

Here is it working …

https://teamytime.com/team/Costa

“Costa” is something the user has set up. And what I do is exactly what you are trying to do, I read in the path (which is “Costa”), then look up that on the relevant table.

The issue you are facing is that you now have two ways of referring to user.

In the manual path and in the built-in page thing.

If you want to go with the manual method (which gives you the cleanest URL) then ditch the content-type on the page. That way you won’t get all the rest of the URL and need a Regex.

Trying to get the various bits of the URL is likely to be more trouble that it is worth as any Regex is going to be returning the parts of the URL in Regex “groups” - which Bubble doesn’t handle well.

So simple answer, remove the User as page thing, and use a State based on the Path.

1 Like

@NigelG

If I ditch “content type” user, this is the result:

errors

I built the mother-of-all-examples for this… the Rosetta Stone of “how do I do this as of January 2019 in Bubble”. I’ve not recorded a video yet (which may in fact be necessary to understand this), but here’s the sample app (Live version, run mode):

Then examine what’s been done in edit/dev mode to make this work (anyone can view):

There’s a lot of good stuff here. This method (1) does not break any core Bubble functionality (profile pages can be accessed in the “traditional” bubble manner via a UID OR via username path argument), (2) preserves URL parameters so that things like “debug_mode=true” or Google Ads utm params still work, (3) combines the technique of retrieving an object from the database via URL path parameter (or via the standard method) with the Browser plug-in’s “rewrite URL” technique, (4) enables emoji (or other non-standard character) URLs, and (5) features some really quite clever fake user profiles.

Go and use it. Go and examine the code. Post any questions you have here. I’ll answer them in the forthcoming video.

It is THE way to do this as of this writing. It is also computationally efficient… if it fast enough that the Googlebot will actually index the pages? We don’t know yet. I’ll cover in the video.

2 Likes

@keith

I’m blown away by your willingness to help. I truly appreciate this. I’m going to jump into this tomorrow evening and I’ll keep you posted on my results and/or questions.

I actually just got finished taking another stab at @romanmg’s approach. Though it isn’t “wrong”, it just isn’t the correct approach for my use case, no matter which way I slice it. She wouldn’t have known because I didn’t give enough context for her to have known that.

1 Like

BTW, ALL this app does is create user profiles with a limited set of customizations. It demonstrates a bunch of other stuff I’m tired of seeing asked about in the forums as well – but those are just “in passing”. On the workflows page(s), you’ll see workflows color-coded by how important they are. (Green ones relate to the topic at hand. Grey ones are boring and you should already understand what they do. Orange ones are of interest, but not directly related to the topic we are discussing here.)

This project uses two non-vanilla plugins: Browser (which I’m growing more fond of) and Toolbox (which is essential to almost any Bubble project). The first is used to re-write the URLs just in the browser to give the effect of navigating to a different URL when we don’t actually do that. Toolbox (one Expression element) is used just as a place to retrieve the URL path parameter and decode it (in the case of emoji/multi-byte characters in the URL).

Other than that, this is plain vanilla Bubble.

Why not have both? See my example…

image

Nice one :+1: - should put the topic to bed until Bubble integrate something natively with the URL alias, all in good time.

Also just to add, Keith’s method is supportive of the SEO page options too, as in you’ll be able to set the SEO title and description due to the data type being set.

@keith

Awesome stuff. I got it working, but I’m experiencing an interesting hiccup. I’m firing this workflow with a “on page load” command. This way, if a user is viewing their own profile when logged in or not, or another user is previewing this profile logged in or not, or someone anywhere from the web comes to this page it will appear.

The URL is simplified exactly how I need it to be by appearing as “.com/user_profile/[user name]”, however, if I simply reload the page from my browsers reload button it doesn’t yield the same results. It actually erases the [user name] from the URL, hence not loading any relevant information on the users profile.

It’s possible that you’ve included a workflow to accommodate this scenario, but I may be missing it. Maybe, my “on page load” is breaking the functionality, but I doubt it.

Any ideas?

Was easier not to in my case, as I started from a clean URL as the basis of the product.

See my live working app… :slight_smile:

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.

2 Likes

nice keith