SEO Friendly URL's - one step forward

crnogorac081

Hi Ruud,

first, for me its lame to have a access file at all, with just (mostly) 1 parameter set in it ($page_id) and mostly with 5 of them (for news, bakery etc..)

specially if you want a website with tons of items/news/pages etc..When you can do the job with just one file.

That is my point. I hope you agree
Web developer

crnogorac081

You can also put additional parameters in url, like

www.mysite.xy/latest/news/football/game-is-postponed/page-2/something-5/
or
www.mysite.xy/latest/news/football/game-is-postponed/?page=2&something=x

it will both match
www.mysite.xy/latest/news/football/game-is-postponed/

so you can put more parameters in nice url
Web developer

Ruud

It looks a bit like how shorturl v2 did the job.

I changed that to the current method (actually using the access files) because it is much faster, and the are no problems with news/baker/topics and other mods that might use their own access files.
There were always these kind of little problems. With the current method there are no more issues (as far as I know).

Personally, I am fine with WB writing the accessfiles. Nobody will ever see them (using shorturl).
If you need this solution for the permission problems of the pages directory (on some servers having to set it to 777), the same problems will stay with media and modules directories.

[url=https://dev4me.com/modules-snippets/]Dev4me - WebsiteBaker modules[/url] - [url=https://wbhelp.org/]WBhelp.org[/url]

crnogorac081

Honestly i dont know. I did this based on my poor knowledge. Maybe Ruud and others should review the code.

This is how it works (my idea):

mostly, access files contains

$page_id = 2;
require("config.php");
require(WB_PATH."/index.php");


Now,  want to access page: http://www.websitebaker.org/en/help/designer-guide/porting-an-existing-html-template.php

which is, as rewriten url  http://www.websitebaker.org/en/help/designer-guide/porting-an-existing-html-template  *(without .php, also note that there is no phisical file)

First I make array of links :

[1] en/help/designer-guide/porting-an-existing-html-template
[2] en/help/designer-guide
[3] en/help
[4] en

and i search _pages table in Database for the longest link, if it is not matched, i seach shorter one, and so one until it match something (if no match - redirect to error404 page)

create a list of required search fields for each modules:
example: for wysiwyg, code, form etc..,  you only need $page_id to work (I found this info in phisical access files) , and for bakery you may need $item_id (when displaying specific item) or without item_id (when showing overview page), same for news page - you may need $post_id, $section_id etc , when displaying specific post, or without for overview.

Then when you match page and have its PAGE_ID, then search in _sections table from Database, and search for sections, and throw sections (module names) in array.

Then loop in array, if page has section wysiwyg, they just show $page_id, if page has section News, show $page_id.

Now, the catch (how it works):

you have url like: www.mysite.xy/latest/news/

1. chop links:
[1] /latest/news   -matched, and stop.
[2] /latest

it will match first link, and fetch $page_id for it.
we continue to see if there is something more interesting in url (like post's link)
we see that there is no match. and thats it.

but if you have url like: www.mysite.xy/latest/news/football/game-is-postponed/

1. chop links:
[1] /latest/news/football/game-is-postponed/     --- no match, continue
[2] /latest/news/football              --------- no match, continue
[3] /latest/news       ----- match. stop searching.
[4] /latest

we get $page_id from this match, and we continue to see if there is something more interesting in url (like post's link)

from /latest/news/football/game-is-postponed/ we strip /latest/news so we have left /football/game-is-postponed

now we loop in _news_posts table to get best match (search longest link first) and we will match link and get $post_id and $section_id from database.

How to create links like /group-name/friendly-news-post-name urls, you can find in my first post.

same principles is for bakery.

So basicly in this one file, based on url, you only fetch parameters required for access files.

please test and give comments

Web developer

Boudi

Sounds great! We MUST take steps forward in SEO in order to conquer the major CMS systems.

Any idea how reliable this coding is?
...:: Bake the Unbakable ::...

crnogorac081

Hi,

i didnt know where to put this so I put it here.

Based on Ruud's fantastic SEO Friendly URL's solution, I went one step forward.
The step forward goes in intention to remove phisical .php pages and /pages directory, like any modern cms today has and works.

Why making a pile of pages specialy for news, bakery etc, because you just need item_id or post_id from it ?

Here is how I did it:

1. follow Ruud's instructions and install SEO FRIENDLY URL PATCH from his post: http://www.websitebaker.org/forum/index.php/topic,17725.0.html

(install droplet, copy .htaccess file and wb.php to root)

2. open wb.php and replace all code with folowwing:



require("config.php");  // i need db connection
define('ERROR_PAGE' , '/error404'); //Change this to point to your existing 404 page is in admin/pages menu.

if (isset($_GET['_wb'])) {

$_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI']; 
$_SERVER['SCRIPT_NAME'] = $_SERVER['REQUEST_URI'];

$page_link1 = trim($_GET['_wb'],'/');
$page_link = '/'.$page_link1;
$link_chunks = explode("/",$page_link1);
$links_array = Array();
    for ($i = 0; $i < count($link_chunks); ++$i) {
$sublink = '';
for ($j = 0; $j < $i; $j++) {
  $sublink .= '/'.$link_chunks[$j];
}
        $links_array[] = $sublink.'/'.$link_chunks[$i];
    }
$links_array = array_reverse($links_array,false); // reverse order for best possible match
$count_chunks = count($links_array);
$matches = 0;

$k = 0;
while( $k < $count_chunks AND $matches < 1) {

$qpages = $database->query("SELECT page_id FROM `".TABLE_PREFIX."pages` WHERE `link` = '$links_array[$k]'");
if (!$qpages OR $qpages->numRows() == 0) {
$matches = 0;
$matched_link = '';
} else {
$matches = 1;
$matched_link = $links_array[$k];
$page_row = $qpages->fetchRow();
$matched_page_id = $page_row['page_id'];
}
$k++;
}
if ($matches == 0) { header('Location: '.WB_URL.ERROR_PAGE); }

// List modules who needs more parameters than just page_id
$module['bakery'] = array('item_id');
$module['news'] = array('section_id', 'post_id');
// ... here put more modules..

// We move on with page_id
if(isset($matched_page_id)) {
$sections_query = $database->query("SELECT module FROM ".TABLE_PREFIX."sections WHERE page_id = '$matched_page_id' ORDER BY section_id ASC ");
while( $section = $sections_query->fetchRow() ) {
// Check if the module is added to the module list
$module_name = $section['module'];

if(array_key_exists($module_name, $module)) {
switch ($module_name) {
case 'bakery':
$id_name = $module[$module_name][0];
//Search for item_id from url
$k = 0;
while( $k < $count_chunks AND $bakerymatches < 1) {
$qpages = $database->query("SELECT $id_name FROM ".TABLE_PREFIX."mod_bakery_items WHERE link = '$links_array[$k]'");
if (!$qpages OR $qpages->numRows() == 0) {
$bakerymatches = 0;
} else {
$bakerymatches = 1;
$matched_link = $links_array[$k];
$page_row = $qpages->fetchRow();
$item_id = $page_row[$id_name];
define("ITEM_ID", $item_id);
}
$k++;
}
break;
case 'news':
$section_id_name = $module[$module_name][0];
$post_id_name = $module[$module_name][1];
// search for post_id
$qpages = $database->query("SELECT $section_id_name, $post_id_name FROM ".TABLE_PREFIX."mod_news_posts WHERE link = '$page_link'");
if ($qpages->numRows() > 0) {
$page_row = $qpages->fetchRow();
// populate required variables for specific post
$iPageId = $matched_page_id;
$section_id = $page_row[$section_id_name];
$post_id = $page_row[$post_id_name];
$post_section = $page_row[$section_id_name];
}
break;
default :
$page_id = $matched_page_id;
break;
}
}
}
$page_id = $matched_page_id;
}


} else {
header('Location: '.WB_URL.ERROR_PAGE);
}

require('index.php');



Note that I tested on PREVIEW server, wb 2.8.4 installed on WB portable. So far it looks nice on bakery, news  wysiwyg, code and form modules.

for testing news module, open save_post.php  and after line


line: 63
    $newLink = '/posts/'.$sNewFile;

insert:

/////// More code
// Create nice URLs => /posts/' replaced with: /group_name/
$query_groups = $database->query("SELECT title FROM `".TABLE_PREFIX."mod_news_groups` WHERE group_id = '$group_id'");
if($query_groups->numRows() > 0) {
$row = $query_groups->fetchRow();
$category_name  = '/'.page_filename($admin->add_slashes($row['title']));
} else {
// For no category, put under /posts/
$category_name = '/posts';
}
// Get page link URL
$query_page = $database->query("SELECT link FROM ".TABLE_PREFIX."pages WHERE page_id = '$page_id'");
$page = $query_page->fetchRow();
$page_link = $page['link'];
// finaly, create nice urls - /page/group/post_title
$post_link = $page_link.$category_name.'/'.page_filename($title).PAGE_SPACER.$post_id;
    $newLink = $post_link;
/////


find line
        switch($sDoWhat)

and dissable entire switch with comments
/ * 
        switch($sDoWhat)
...
...
        }
*/

to stop to create access files.

you will be able to create and view posts and news page , there is only one glitch when you submit comment (I need to fix returning path after submitting, but it can be done in 3 lines of code :D )



Of course there may be an easier ways and better ones to code this, so feel free to improve this code

It is really time to get rid of .php pages files, please consider for something like this to be implemented in core in 2.8.4
Web developer