How can I create dynamic links to pages

Sorry for the vagueness of the title but as a beginner level coder I really don’t know all the proper terminology.

I am creating a hobby site in PHP which is a gallery-based site for collectors. I have a MySQL database.

When I add on a new collection, I want the ability to show that collection name in the URL.

For example, if I add on a collection site for “Critical Role”, (table id value of “22”) I will also have a column for recording the path as “critical-role”, and I want the URL to be:

To my understanding, this can be accomplished by adding code to the htaccess file (something I have never done), however I want all of this process to be automated – I do not want to manually change the htaccess file everytime I add a new collector set.

Can someone please point me in the right direction as to how to accomplish this, and if there are other options other than the htaccess method and/or is there a way to not have to manually change the htaccess file?

The link itself would point back at the home page, so that it can dynamically create the content for that collection.

Instead of using htaccess for all of this, you would be better off creating a “single entry point” and a “router script”.
I’m not going into full detail about how to set that up, but you have some terms to search about.
But in basic steps, the single entry is just a single file (index.php).
That will just contain an include (require) for the router script.
A router basically determines what gets displayed based on the URL.
The script will get the slug (page name) from the URL, then query the database for it, where it will be an indexed column.

Thank you for the reference terminology of “single entry point” and “router script”.

I have been trying to search those terms, but I really am not finding anything relevant and/or easily discernable.

Ideally I am looking for a website or youtube video that details how to set this up in a “for dummies” format. I am not an advanced programmer and trying to read reddit threads that have pieces of advanced code all over the place is just not quite working for my old brain.

If you have any beginner-level links you can share that would help walk me through this, I would really appreciate it if someone could share those.

Here’s a quick and dirty version:
File .htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /mux.php [L,QSA]

file mux.php (or index.php, or whataver that corresponds with what you have in the htaccess)

$collection = ltrim ($_SERVER['REQUEST_URI'],"/");
echo "Collection = $collection";

Thanks tracknut.

Unfortunately my old brain just doesn’t follow how this works.

To complicate matters, the target will either be a menu or a gallery (i.e. the target of “/critical-role” will be a menu of all sets associated with Critical Role, where-as the target of “/critical-role-monsters-of-taldorei” will be a gallery of the set.)

Note: the index page dynamically creates different content (i.e. menu appearance vs gallery appearance), depending on the selection. I am trying to get away from posting variables (i.e.: (I am guessing I might need to add this into the URL, such as www.example/gallery/critical-role-monsters-of-taldorei and www.mysite/menu/critical-role ?)

So in your example of:

<?php $collection = ltrim ($_SERVER['REQUEST_URI'],"/"); echo "Collection = $collection"; ?>

Lets see if I follow how this works:

  1. A request comes into the htaccess file to navigate to the webpage:
  2. The htaccess rewrite rule will run the code in the mux.php file
  3. In the mux.php file, the value of $collection will be: critical-role
  4. "Collection = critical-role-monsters-of-taldorei is displayed. (I don’t understand why this is being displayed or how it links back to set #22 of my data table which is what I want to have displayed.)

I’m going to do a bit of guessing and pseudo-code here, rather than start writing your whole app :slight_smile: Firstly for your “how it works” list above, that’s not quite it. It should be:

  1. User types the url:
  2. Upon reaching and before connecting to a specific file, the web server processes the .htaccess file. In there it sees a rewrite rule that tells it to run mux.php and pass it the uri “/critical-role-monsters-of-taldorei”
  3. In the mux.php I provided, I just stripped off the leading slash and printed out the uri. Of course your implementation of mux.php is a lot more complicated than that.

So to respond to a couple of your questions.

Firstly, I would assume that as these menus or galleries are created, you need to keep track of not only the name, but the target id number of them. That should allow you to make a query into your database, looking up from what I called $collection (that the user passed in the URL) and getting back the type (menu or gallery) and id (22).

So in mux.php, you would have something like:
$collection = uri
lookup $collection and get $collectionType and $collectionID from database
if ($collectionType == MENU)
lookup roles for $collectionID
do whatever you do with these roles
if ($collectionType == GALLERY)
lookup gallery images for $collectionID
display the images?
error “bad collection name”

Of course you need various checking in all this, because a user could enter any old url that didn’t correspond to a known collection.

I think that is the hard part. Just to be sure I understand, you (will) have collection names in your database that you want to be used in the site’s URL, correct?

I do not know enough about Single Page Applications to know how relevant they are but that is something to search for. What I wish I had known about single page applications - Stack Overflow Blog is quite technical and might change your mind but you can decide for yourself.

Parts of this I am following, but I’m still quite confused. Based on what Tracknut and SamA74 have provided, here is my understanding at this time. I am new at coding, but here is my best attempt:

  1. In my htaccess file, I need to place the following.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /mux.php [L,QSA]
  1. In my index.php file I need to have an includes line referencing the mux.php file.
include ('includes/mux.php');

Question A: Where would I place this? In php code before the <!doctype html> ?

Question B: Does this only trigger if the URL contains a “/”?

  1. In the mux.php file I would have the following code:
$collection = ltrim ($_SERVER['REQUEST_URI'],"/");

<!-- not sure how I set the **$targetType** and **$targetPath** from **  since there are no variables being posted -->

if ($targetType = "sets")
   $sql="SELECT id FROM sets_TAB WHERE ? = path";
   $stmt = $pdo->prepare($sql);
   $result = $stmt->fetch();
   echo "index.php?targetType=sets&targetId=" . $result;
else {
   echo "Bad Name";

Question C: How do I get the values for $targetType and $targetPath from $collection? For $targetType, would I have php code look for the first and second instance of “/” to assign the text between to $targetType, and then assign text after the second instance of “/” to $targetPath ?

No, I don’t think that’s the case. If you look back to where @tracknut provided the first pseudo-code, they say

so to me that suggests that if you want to do the processing in index.php, then you would put that in the fourth line of that sample section of .htaccess instead of where mux.php is placed.

(Disclaimer: I have never knowingly hosted a site on a server that uses .htaccess, so this is not based on any knowledge or experience.)

Yes, correct. No reason I can think of that you wouldn’t just use index.php if that’s the file you wanted to do this with.

Regarding Question C, maybe I’ve got a disconnect on the requirements here. Your initial question was how to make a link (url) to a “collection”, where “collection” was an arbitrary thing that a user created, and you wanted a relatively clean looking url that you didn’t have to keep adding new files for. That solution was provided.

Now you’re asking how to get more fields ($targetType and $targetPath) as they are not part of your initial “collection” thing. I asked if these additional values couldn’t just be derived from “collection” via some database query, and I’m not sure I saw an answer to that. If they cannot be pulled from the database, then are you expecting the user to enter them? Are you expecting them to be passed in this same url? And if so, perhaps you should just be doing all of this via a Query String in the url, rather than using .htaccess at all? For example:

That of course isn’t pretty, but if you need users to be entering three values into a url by hand, “pretty” is kind of going out the window.

Thank you for trying to help me clear up my cloud of confusion over this.

The user would not be entering any values. They would just be clicking on a menu selection.

Here is the current page I am re-designing:

I have a hierarchical menu selection which consists of intermixed sub-menus and gallery selections (i.e. “Dungeons and Dragons” will take you to a sub-menu, where-as “Oriville Heroclix” will take you to the gallery since there are no other sets associate with this product line.

The routing is essentially handled by a pages table where I record the type of link (menu or site), the id# from the either the menu table or the sets table, the display order (if any), parent menu id# from the pages table.

I mainly want clean URL’s for SEO purposes. (Although I have read mixed opinions as to whether stripping the URL variable passing makes SEO better).

Ideally, the pretty URL would change, depending what I am trying to produce on the index page:

Menu example:

When the user clicks on a menu selection, then I want to detect that if the first “/” is followed by “menu”, to trigger the menu section of the index page, and build out a menu of the children from the pages table that are associated with the parent menu for “dungeons-and-dragons-icons-of-the-realms”.

Gallery example:

When a user clicks on a gallery selection (for a specific set), then I want to detect that the first “/” is followed by “gallery”, to trigger the gallery section of the index page, and build out the gallery for this set. From this URL I want to extract the middle element of “critical-role” as that will correspond to a value in the product line table, and to extract the last element of “monsters-of-taldorei” as that will correspond to the name of the set.

If the rewrite rule is changed to “RewriteRule . /index.php [L,QSA]”, then I’m not sure what I need to do next. Does this mean that any URL with a “/” in it is going to be referred back to the index.php page, and then I use coding on the index page to extract the elements between the slashes, to determine what gets displayed on the index page?

Following my above train of thought, I would just need this then in my index.php page?

$pathing = ltrim ($_SERVER['REQUEST_URI'],"/");
preg_match_all('#/mk_([^/]*)#', $pathing, $pathElements);
$targetType = $pathElements[0];
$targetElement1 = $pathElements[1];
$targetElement2 = $pathElements[2];

Ok, thanks for the details. I think I’m getting it.

If you want to be able to parse those two URI’s, having them be arbitrary sets of strings separated by slashes, the previous .htaccess file will work. It’s just going to pass the whole string to mux.php (or in your case to index.php) without any parsing. so for example if you send the url:

then in index.php you can look at $_SERVER[‘REQUEST_URI’] and see that it will be the string “/menu/dungeons-and-dragons-icons-of-the-realms”. If you explode this string using a slash as the separator:

$parts = explode ("/",$_SERVER['REQUEST_URI'] );

Then look at $parts, it will be an array of (in this example) two elements (skip the first empty one, it is what’s prior to the leading slash, ie an empty string), the first being “menu” and the second being “dungeons-and-dragons-icons-of-the-realms”. There is no practical limit to the number of elements you could pass this way, so your gallery example would have three elements in the $parts array. So as long as they are in a known order (ie “” is not the same as “”) you’re fine other than to trap bogus user-entered urls (hacking attempts and/or mistakes).

Once you have those items separated into $parts, then I suspect you’re off and running?

SPA and Singe Entry Point are not to be confused. With SEP there are still multiple pages (as the user perceives it), but there is only one PHP file (index.php call it what you will) in the root, which handles the page routing based on the URL. Or as I prefer, the index does nothing but require_once the router or entry point and all the workings are kept below the root.

This it the kind of thing I’m thinking of. I have just used htaccess in the past, but it can soon get quite complex and confusing. Handling it in PHP seems a better way.
So if the first part says menu or gallery, we know what type of page we want to show and can load the controller and HTML template for that. The second part gives us the slug for the particular menu or gallery we want, so you may query the database for it based on the slug, rather than ID.

I believe I am now. Its actually a pretty simple process now that I have wrapped this old brain around it.

The only part I don’t really understand about the htaccess code is how if handles which requests with slashes to send back to the index.php for handling, rather than processing the URL as typed.

Currently I have the redirection going to my testpage: index99.php

If I type: “” then it redirects correctly via the htaccess code.

If I type “” then it redirects correctly to the forum – which is good, but I don’t understand why the htacess code is allowing it. Do one of those letters in the htaccess code basically only apply the redirect if a valid link is not found on the site/server?

These two conditions in your .htaccess file:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

The first tests if REQUEST_FILENAME (which is really a full path and file name) that was entered in the URL does not exist as a file (!-f), and the second tests that it does not exist as a directory (!-d). If it is either a file or a directory, the RewriteRule is not executed and the URL entered by the user is processed without changes.

Be aware (I suppose it could have been mentioned earlier :slight_smile: ) this whole .htaccess thing is specific to the Apache web server. We got lucky that’s what you’re on, but if you ever put it on some other web server, all bets are off…

Great. Perfectly clear now. Thank you so much for your time and patience with this.

The new issue this creates though is with my relative linking in my website.

If there is just a single slash in the URL, all is fine. (i.e. is fine, but is not).

If there are multiple slashes, then it messes with the relative linking (such as my style sheets and images folders)


<link type="text/css" rel="stylesheet" href="css/mgstyles2021.css?v001">

I would like to preserve relative linking as it really helps in code development.

Is there any way to keep relative linking, or will I have to use absolute links now in my code?

(If I have to use absolute linking, then I will likely just have a prefix to the relative link set as a variable for my root source that I can easily change depending on where the code is currently running (i.e. my computer vs the webserver).

Hmmm… I’m not sure on this one. You are essentially providing a url with several “levels” in it, and expecting a relative link to your css or images to work as if you were at the top level. Can’t you just add the leading slash in the href (“/css/mgstyles2021.css?v001”) and have it work? No need to put in something that changes depending on the host for that, that I can think of.

Unfortunately that does not work.

I have now added the / before css, but I’m still getting the same results.

Edit: Okay, I got it to work now.

Thanks again for all your help tracknut. I learned a lot!

1 Like