Jump to content

Knowledge base, friendly URLs and multilanguage


Remitur

Recommended Posts

With friendly URL enabled and multilanguage enabled, if you translate your kb posts you'll get, i.e.:

https://yourwhmcs.ext/index.php?rp=/knowledgebase/55/How-to-boil-water.html    (English, default language)

and

https://yourwhmcs.ext/index.php?rp=/knowledgebase/55/Come-bollire-l-acqua.html   (italian version)

Right, nice.

The issue?

If I send the italian link to someone who is no logged in, he will have set the default language, so when he click on https://yourwhmcs.ext/index.php?rp=/knowledgebase/55/Come-bollire-l-acqua.html he will bring to the same page but... in the english (default language) version!!!!

If he select the right language, he will bring to home page... and he should now again recover the link, click on it, and finally he'll get the right page in italian version... :-/

Dirty fix: modify the link sent to the user, adding &language=italian ; so sending i.e.

https://yourwhmcs.ext/index.php?rp=/knowledgebase/55/Come-bollire-l-acqua.html&language=italian 

it works fine, but it's annoying because you are required to edit manually the link before sending it ... 😕

Anyone has any better idea? A hook, a trick, some kind of .htaccess rewrite in order to get a better result? 

 

Link to comment
Share on other sites

3 hours ago, brian! said:

 I suppose you could get the title of the article, query the tblkb table and see if there's a language assigned to the article and redirect to the correct language with a hook.... though whether that's worth doing, I don't know.

Exactly.

@Remitur The problem is that WHMCS language is based on sessions so it doesn't matter what's the URL. The article will always use the default language which in your case is English. This hook should work. I tested on my dev system lazily. I'm gonna update if it doesn't work. It's commented. More information are provided below.

<?php

use WHMCS\Database\Capsule;
use WHMCS\Config\Setting;

add_hook('ClientAreaPageKnowledgebase', 1, function($vars)
{
	/**
	* The way I'm getting $ArticleLanguage looks complicated but is necessary to match "Hello hello-hello" title with the rewritten URLs "Hello-hello-hello"
	* In fact there's no way to distinguish real dashes "-" from fake ones added by Friendly URLs of WHMCS
	* Keep in mind that I'm forced to use "raw" static method since WHERE statement doesn't support complex functions like REPLACE
	*/

	// Getting title from querty string
	$PageName = pathinfo($_GET['rp'])['filename'];
	// Retreiving the language of the currently displayed article by ID and title
	$ArticleLanguage = Capsule::select(Capsule::raw('SELECT language FROM tblknowledgebase WHERE parentid = "' . $vars['kbarticle']['id'] . '" AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->language;
	// Retreiving the default language of WHMCS from tblconfiguration
	$DefaultLanguage = Setting::getValue('Language');

	/**
	 * This section is optional but needed if you want to protect yourself against blackhat SEO techniques (read post for more info)
	 */

	// Retreiving default language title
	$LegitURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE id = "' . $vars['kbarticle']['id'] . '" LIMIT 1'))[0]->title;

	// If the URL currently in use is not 100% legit I force a redirect to the article in default langiage
	if ($LegitURL !== $PageName AND !$ArticleLanguage)
	{
		header('Location: index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $LegitURL . '.html');
		die();
	}

	/**
	 * Here we set the right language depending on the URL
	 */

	// I check if the $ArticleLanguage is different from the language currently in use. I also make sure that $ArticleLanguage is different from $_SESSION['Language'] to avoid infinite loops
	if ($ArticleLanguage != $DefaultLanguage AND $ArticleLanguage != $_SESSION['Language'])
	{
		// Set language
		$_SESSION['Language'] = $ArticleLanguage;
		// Redirect visitor to current page to re-load the correct language 
		header('Location: index.php?rp=' . $_GET['rp']);
		die();
	}
});

add_hook('ClientAreaHeadOutput', 1, function($vars)
{
	/**
	 * This guy adds canonical URL inside <head></head> tag so that Google doesn't penalize you (read post for more info) 
	 */

	if ($vars['templatefile'] == 'knowledgebasearticle')
	{
		$PageName = pathinfo($_GET['rp'])['filename'];
		$CanonicalURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE (parentid = "' . $vars['kbarticle']['id'] . '" OR id = "' . $vars['kbarticle']['id'] . '") AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->title;

		return '<link rel="canonical" href="index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $CanonicalURL . '.html"/>';
	}
});

Even though we're now showing the right language to visitors, Google and all other Search Engines still hate us because we're providing duplicate contents. Their hate is so strong that they penalize us on SERP. Here is why:

  • whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-water.html
  • whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-vodka.html
  • whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-rum.html
  • whmcs.com/index.php?rp=/knowledgebase/55/How-to-boil-wine.html

4 URLs, same page and (duplicate) content. The only way to avoid penalties is that we let them know what's the unique URL by using rel="canonical" tag. The above hook adds it automatically where it is supposed to be (<head>here</head>). And if you are questioning why someone should use fake links, take a look at blackhat SEO techniques. One of your malicious competitor could publish some of those fake-links so that weeks later Google & co. penalize you for duplicate content. The above hook protects you from this technique forcing a redirect to the default article in case the URL in use is not the legit one.

Link to comment
Share on other sites

I don't know why I can no longer edit my own post so I'm gonna repost an updated version of the above script. In fact I noticed a small issue.

<?php

use WHMCS\Database\Capsule;
use WHMCS\Config\Setting;

add_hook('ClientAreaPageKnowledgebase', 1, function($vars)
{
	/**
	* The way I'm getting $ArticleLanguage looks complicated but is necessary to match "Hello hello-hello" title with the rewritten URLs "Hello-hello-hello"
	* In fact there's no way to distinguish real dashes "-" from fake ones added by Friendly URLs of WHMCS
	* Keep in mind that I'm forced to use "raw" static method since WHERE statement doesn't support complex functions like REPLACE
	*/

        if (!$vars['kbarticle']['id']): return; endif;

	// Getting title from querty string
	$PageName = pathinfo($_GET['rp'])['filename'];
	// Retreiving the language of the currently displayed article by ID and title
	$ArticleLanguage = Capsule::select(Capsule::raw('SELECT language FROM tblknowledgebase WHERE parentid = "' . $vars['kbarticle']['id'] . '" AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->language;
	// Retreiving the default language of WHMCS from tblconfiguration
	$DefaultLanguage = Setting::getValue('Language');

	/**
	 * This section is optional but needed if you want to protect yourself against blackhat SEO techniques (read post for more info)
	 */

	// Retreiving default language title
	$LegitURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE id = "' . $vars['kbarticle']['id'] . '" LIMIT 1'))[0]->title;

	// If the URL currently in use is not 100% legit I force a redirect to the article in default langiage
	if ($LegitURL !== $PageName AND !$ArticleLanguage)
	{
		header('Location: index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $LegitURL . '.html');
		die();
	}

	/**
	 * Here we set the right language depending on the URL
	 */

	// I check if the $ArticleLanguage is different from the language currently in use. I also make sure that $ArticleLanguage is different from $_SESSION['Language'] to avoid infinite loops
	if ($ArticleLanguage != $DefaultLanguage AND $ArticleLanguage != $_SESSION['Language'])
	{
		// Set language
		$_SESSION['Language'] = $ArticleLanguage;
		// Redirect visitor to current page to re-load the correct language 
		header('Location: index.php?rp=' . $_GET['rp']);
		die();
	}
});

add_hook('ClientAreaHeadOutput', 1, function($vars)
{
	/**
	 * This guy adds canonical URL inside <head></head> tag so that Google doesn't penalize you (read post for more info) 
	 */

	if ($vars['templatefile'] == 'knowledgebasearticle')
	{
	        if (!$vars['kbarticle']['id']): return; endif;

		$PageName = pathinfo($_GET['rp'])['filename'];
		$CanonicalURL = Capsule::select(Capsule::raw('SELECT REPLACE(title, " ", "-") AS title FROM tblknowledgebase WHERE (parentid = "' . $vars['kbarticle']['id'] . '" OR id = "' . $vars['kbarticle']['id'] . '") AND REPLACE(title, "-", " ") = "' . str_replace('-', ' ', $PageName) . '" LIMIT 1'))[0]->title;

		return '<link rel="canonical" href="index.php?rp=/knowledgebase/' . $vars['kbarticle']['id'] . '/' . $CanonicalURL . '.html"/>';
	}
});

 

Edited by Kian
Link to comment
Share on other sites

  • 9 months later...

Hi @Kian

I tested your hook and is working for Basic URLs option but is not working for Full Friendly Rewrite option. I get this url when I use on Full Friendly Rewrite  https://site.com/knowledgebase/3/index.php?rp=/knowledgebase/3/Example-Code-(PHP).html

Any chance you can adapt the hook for Full Friendly Rewrite option? 

thanks,

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated