Gut zu wissen das du mit EyeCandy unterwegs bist... Ich schaue mal eben, wo bei EyeCandy was hingehört...
@slavek das EyeCandy Template hat keinen "canonical"-Tag deswegen "-USERMOD" der "head.html" Datei erstellen unter ""templates/EyeCandy/module/" also "templates/EyeCandy/module/head-USERMOD.html" In diese USERMOD fügst du nun den canonical-Tag ein (vor dem "<base>"-Tag) HTML: {if {$content_data.CANONICAL_TAG}} <link rel="canonical" href="{$content_data.CANONICAL_TAG}"/> {/if} Nun überladen wir die "HeaderContentView"-Klasse und fügen den folgenden Code in "user_classes/overloads/HeaderContentView/CustomizedHeader.php" ein PHP: <?php/* -------------------------------------------------------------- CustomizedHeader.php 2016-07-05 Gambio GmbH http://www.gambio.de Copyright (c) 2016 Gambio GmbH Released under the GNU General Public License (Version 2) [http://www.gnu.org/licenses/gpl-2.0.html] --------------------------------------------------------------*/class CustomizedHeader extends CustomizedHeader_parent{ public function prepare_data() { parent::prepare_data(); $seoBoost = MainFactory::create('GMSEOBoost'); if ($seoBoost->boost_products && isset($_GET['gm_boosted_product']) && CURRENT_TEMPLATE == 'EyeCandy') { $canonicalUrl = xtc_href_link($seoBoost->callProductsMainCategory($GLOBALS['actual_products_id'])); $this->content_array['CANONICAL_TAG'] = $canonicalUrl; } }} Danach die Caches leeren und auf einer Produktseite den Quellcode im Browser öffnen und prüfen ob der canonical-Tag auf der Produktseite vorhanden ist. Hinweis: Der canonical-Tag wird nicht auf Kategorieseiten hinzugefügt (macht auch wenig Sinn ). Keine schöne Lösung, aber auf die schnelle tut's auch
Ich habe so gemacht: Step 1: Step 2: Habe bekommen: PARSE ERROR(4): "syntax error, unexpected 'public' (T_PUBLIC)"
Hast du den zusätzlichen Codeschnippsel für BugfixSEOBoost richtig eingefügt? Ich sende gleich mal den kompletten Code für BugfixSEOBoost
Die komplette "BugfixGMSEOBoost"-Klasse PHP: <?php/*** Dieser Bugfix behebt die Fehler in der Darstellung und Verlinkung* der Systemkomponenten Artikelnavigator und Breadcrumb.** Mit der Konstante @see const SHORT_URL = false (standard) | true* kann zwischen einer Standardform (false) und Kurzform (true)* der URL für ein Produkt geschaltet werden.** Mein Dank geht an die freundliche Unterstützung der Community Mitglieder:* "barbara", "marmoles" und "Kai Schoelzke".*/class BugfixGMSEOBoost extends BugfixGMSEOBoost_parent{ const SHORT_URL = false; protected $currentCategoryId; public function __construct() { parent::__construct(); $this->currentCategoryId = $this->currentCategory(); } public function get_boosted_product_url($p_pID, $p_pName = '', $p_language_id = false, $p_url_keywords = '') { $t_language_data_array = $this->get_language_data('product', $p_pID, $p_language_id, $p_url_keywords); if (gm_get_conf('USE_SEO_BOOST_LANGUAGE_CODE') == 'true') { $t_language_data_array['code'] .= '/'; } else { $t_language_data_array['code'] = ''; } $p_pName = $this->get_coolerized_product_name($p_pID, $t_language_data_array['language_id']); $t_link = $t_language_data_array['code']; $t_path = $this->get_product_path($p_pID, $t_language_data_array['language_id']); if ($t_path != '' && self::SHORT_URL === false) { $t_link .= $t_path.'/'; } $t_link .= $p_pName; $t_link .= '.html'; return $t_link; } public function get_product_path($products_id, $languages_id = false) { if ($languages_id === false) { $languages_id = (int)$_SESSION['languages_id']; } $out = ''; $result = xtc_db_query("SELECT categories_id FROM products_to_categories p2c WHERE p2c.products_id = '".(int)$products_id."' AND ".$this->sqlCategoriesId($this->currentCategoryId)." LIMIT 1"); if (xtc_db_num_rows($result) > 0) { $data = xtc_db_fetch_array($result); $out = $this->get_full_categories_names($data['categories_id'], $languages_id); } return $out; } /** * Gibt die Hauptkategorie eines verlinkten Artikels zurück. * * @param null $productsId * * @return mixed */ public function callProductsMainCategory($productsId = null) { $out = ""; $query = xtc_db_query("SELECT categories_id, gm_url_keywords FROM products_to_categories p2c INNER JOIN products_description pd ON pd.products_id = p2c.products_id WHERE (p2c.products_id = '".$productsId."' AND pd.language_id = '".$_SESSION['languages_id']."') AND ".$this->sqlCategoriesId(null)." LIMIT 1"); if (xtc_db_num_rows($query) > 0) { $data = xtc_db_fetch_array($query); $out = self::SHORT_URL ? $data['gm_url_keywords'].".html" : $this->get_full_categories_names($data['categories_id'], $_SESSION['languages_id'])."/".$data['gm_url_keywords'].".html"; } return $out; } /** * Workaround um die ID der aktuellen Kategorie zu erfassen. * Mit dieser Information wird der Pfad zum Produkt ermittelt * und an den Breadcrumb übergeben. * * @return int */ protected function currentCategory() { $pathInfo = array_filter(explode('/', $_SERVER['PATH_INFO'])); // Produktseite if (!isset($_GET['cPath'])) { $query = xtc_db_query("SELECT cd.categories_id FROM categories_description cd LEFT JOIN categories c USING (categories_id) WHERE categories_status = TRUE AND gm_url_keywords = '".$this->currentCategoryName($pathInfo)."' AND language_id = '".$_SESSION['languages_id']."' LIMIT 1"); $result = xtc_db_fetch_array($query); if ($result) { $_GET['p2c'] = $result['categories_id']; $_GET['cPath'] = xtc_get_category_path($result['categories_id']); return (int)$result['categories_id']; } return null; } // Kategorieseite return (int)end(explode('_', $_GET['cPath'])); } /** * Workaround um den Namen der aktuellen Kategorie zu erfassen. * Mit dieser Information wird der Pfad zum Produkt ermittelt @see currentCategory * * @param $currentPath * * @return string */ protected function currentCategoryName($currentPath) { if (isset($_GET['gm_boosted_category'])) { $_SESSION['currentCategoryName'] = end($currentPath); return self::SHORT_URL === true ? $_SESSION['currentCategoryName'] : end($currentPath); } if (isset($_GET['gm_boosted_product']) && self::SHORT_URL === true) { return $this->sessionCategoryName($_SESSION['currentCategoryName']); } if (empty($currentPath)) { unset($_SESSION['currentCategoryName']); } return array_reverse($currentPath)[1]; } /** * Workaround um die URL der Hauptkategorie aus der Startseite eines Artikels zu erfassen. * Ist die $_SESSION['currentCategoryName'] bereits belegt, * wird diese für die Darstellung in URL-Kurzform übernommen. * * @param bool $session_exist * * @return mixed */ protected function sessionCategoryName($session_exist = false) { if (!$session_exist) { $query = xtc_db_query("SELECT cd.gm_url_keywords FROM products_to_categories p2c, categories_description cd WHERE p2c.products_id = ".(int)$_GET['products_id']." AND cd.categories_id = p2c.categories_id AND cd.language_id = ".$_SESSION['languages_id']." LIMIT 1"); $result = xtc_db_fetch_array($query); return $_SESSION['currentCategoryName'] = $result['gm_url_keywords']; } return $_SESSION['currentCategoryName']; } /** * Legt Anhand der aktuellen Kategorie-ID fest * welche Anweisung für die Datenbankabfrage * festgelegt wird. * * @param $categories_id * * @return string */ private function sqlCategoriesId($categories_id) { if (empty($categories_id)) { return 'p2c.categories_id != 0'; } return 'p2c.categories_id = '.$categories_id.''; }} Caches leeren nicht vergessen
Wahrscheinlich ist es das zu kompliziert fuer mich Aber, ich werde jetzt noch einmal probieren: Step.1 kompletten Code fuer BugfixSEOBoost kopieren und umschreiben Step.2 Welche is "<base>"-Tag? Kannst Du mir bitte die Datei umschreiben oder zeigen, wohin muss es genau den canonical-Tag einfuegen? Und soll ich dann am Ande zwei Dateien haben: 1)head.html und 2)head-USERMOD.html oder soll dort nur eins Datei bleiben, also nur die neue head-USERMOD.html ? Step.3 Wie verstehe ich hier: soll ich zuerst eine Katalog "HeaderContentView"(weil befindet sich keine dort) und dann eine Datei CustomizedHeader.php erstellen, und Code einfuegen? "user_classes/overloads/HeaderContentView/CustomizedHeader.php" Step.4 Cache leeren
Kein Problem @slavek Step 1. Du kopierst die Datei "head.html" aus dem Ordner "templates/EyeCandy/module/", fügst diese in den selben Ordner wieder ein (Copy & Paste) und benennst diese Kopie in "head-USERMOD.html" um. Step 2. In die kopierte "head-USERMOD.html"-Datei fügst du diesen Code über "<base>" ein (siehe bild_1) HTML: {if {$content_data.CANONICAL_TAG}} <link rel="canonical" href="{$content_data.CANONICAL_TAG}"/> {/if} Step 3. Du erstellst einen Ordner mit dem Namen "HeaderContentView" unter "user_classes/overloads". In diesem Ordner "HeaderContentView" erstellst du eine Datei und benennst diese "CustomizedHeader.php". In die "CustomizedHeader.php"-Datei fügst du nun diesen Code ein PHP: <?php/* -------------------------------------------------------------- CustomizedHeader.php 2016-07-05 Gambio GmbH http://www.gambio.de Copyright (c) 2016 Gambio GmbH Released under the GNU General Public License (Version 2) [http://www.gnu.org/licenses/gpl-2.0.html] --------------------------------------------------------------*/class CustomizedHeader extends CustomizedHeader_parent{ public function prepare_data() { parent::prepare_data(); $seoBoost = MainFactory::create('GMSEOBoost'); if ($seoBoost->boost_products && isset($_GET['gm_boosted_product']) && CURRENT_TEMPLATE == 'EyeCandy') { $canonicalUrl = xtc_href_link($seoBoost->callProductsMainCategory($GLOBALS['actual_products_id'])); $this->content_array['CANONICAL_TAG'] = $canonicalUrl; } }} Step 4. Wenn du bereits die BugfixGMSEOBoost-Klasse von oben übernommen hast, dann brauchst du nichts mehr zu machen. Ansonsten den kompletten Code (BugfixGMSEOBoost-Klasse von (Link nur für registrierte Nutzer sichtbar.)) kopieren und unter "user_classes/overloads/GMSEOBoost/BugfixGMSEOBoost.php" einfügen. Caches leeren... Produktseite aufrufen... Quellcode im Browser öffnen und prüfen ob der canonical-Tag vorhanden ist. Wenn du magst kannst du statt "[CANONICAL_TAG]" die Übergabe auch "[CANONICAL_URL]" umbenennen, damit es vielleicht verständlicher ist, was da übergeben wird. Müsstest jedoch im "CustomizedHeader.php" und in der "head-USERMOD.html" den Text "CANONICAL_TAG" nach "CANONICAL_URL" abändern.
/* -------------------------------------------------------------- CustomizedHeader.php 2016-07-05 Gambio GmbH http://www.gambio.de Copyright (c) 2016 Gambio GmbH Released under the GNU General Public License (Version 2) [http://www.gnu.org/licenses/gpl-2.0.html] -------------------------------------------------------------- */ class CustomizedHeader extends CustomizedHeader_parent { public function prepare_data() { parent:repare_data(); $seoBoost = MainFactory::create('GMSEOBoost'); if ($seoBoost->boost_products && isset($_GET['gm_boosted_product']) && CURRENT_TEMPLATE == 'EyeCandy') { $canonicalUrl = xtc_href_link($seoBoost->callProductsMainCategory($GLOBALS['actual_products_id'])); $this->content_array['CANONICAL_TAG'] = $canonicalUrl; } } } WARNING(2): "class_parents(): Class CustomizedHeader does not exist and could not be loaded" WARNING(2): "array_values() expects parameter 1 to be array, boolean given" FATAL ERROR(1): "Class 'CustomizedHeader' not found"
@slavek Kannst du bitte Screenshots von der "user_classes/overloads" Ordnerstruktur hochladen und auch von den Dateien wo du den Code eingefügt hast?
In deiner "CustomizedHeader.php" hast du vergessen in der ersten Zeile das "<?php" mit zu kopieren. In die aller erste Zeile dieser Datei gehört ein "<?php"
Jetzt keine Fehlermeldung, aber die URLs sind jetzt wie vorher ..? www.shop.de/Kategorie/Unterkategorie/Artikel.html vor letzter Anderung war es: www.shop.de/Artikel.html ..und jetzt wider laaaaaaaange URLs ?!
false Jetzt keine Fehlermeldung, die URLs sind SHORT, aber was soll sich jetzt aendern???? Am ende URL ist wie vorher .html www.shop.de/Artikel.html Wie pruefen jetzt ob alles hat gut geklappt?
kein "canonical" vorhanden und.... "charset=utf-8" ist wieder weg, meta Analyzer zeigt jetzt keine Meta-Angaben
@slavek Ups! Sorry hatte dir die alte BugfixGMSEOBoost-Klasse angegeben. Das ist die richte PHP: <?php/*** Dieser Bugfix behebt die Fehler in der Darstellung und Verlinkung* der Systemkomponenten Artikelnavigator und Breadcrumb.** Mit der Konstante @see const SHORT_URL = false (standard) | true* kann zwischen einer Standardform (false) und Kurzform (true)* der URL für ein Produkt geschaltet werden.** Mein Dank geht an die freundliche Unterstützung der Community Mitglieder:* "barbara", "marmoles" und "Kai Schoelzke".*/class BugfixGMSEOBoost extends BugfixGMSEOBoost_parent{ const SHORT_URL = false; protected $currentCategoryId; public function __construct() { parent::__construct(); $this->currentCategoryId = $this->currentCategory(); } public function get_boosted_product_url($p_pID, $p_pName = '', $p_language_id = false, $p_url_keywords = '') { $t_language_data_array = $this->get_language_data('product', $p_pID, $p_language_id, $p_url_keywords); if (gm_get_conf('USE_SEO_BOOST_LANGUAGE_CODE') == 'true') { $t_language_data_array['code'] .= '/'; } else { $t_language_data_array['code'] = ''; } $p_pName = $this->get_coolerized_product_name($p_pID, $t_language_data_array['language_id']); $t_link = $t_language_data_array['code']; $t_path = $this->get_product_path($p_pID, $t_language_data_array['language_id']); if ($t_path != '' && self::SHORT_URL === false) { $t_link .= $t_path.'/'; } $t_link .= $p_pName; $t_link .= '.html'; return $t_link; } public function get_product_path($products_id, $languages_id = false) { if ($languages_id === false) { $languages_id = (int)$_SESSION['languages_id']; } $out = ''; $result = xtc_db_query("SELECT categories_id FROM products_to_categories p2c WHERE p2c.products_id = '".(int)$products_id."' AND ".$this->sqlCategoriesId($this->currentCategoryId)." LIMIT 1"); if (xtc_db_num_rows($result) > 0) { $data = xtc_db_fetch_array($result); $out = $this->get_full_categories_names($data['categories_id'], $languages_id); } return $out; } /** * Gibt die Hauptkategorie eines verlinkten Artikels zurück. * * @param null $productsId * * @return mixed */ public function callProductsMainCategory($productsId = null) { $out = ""; $query = xtc_db_query("SELECT categories_id, gm_url_keywords FROM products_to_categories p2c INNER JOIN products_description pd ON pd.products_id = p2c.products_id WHERE (p2c.products_id = '".$productsId."' AND pd.language_id = '".$_SESSION['languages_id']."') AND ".$this->sqlCategoriesId(null)." LIMIT 1"); if (xtc_db_num_rows($query) > 0) { $data = xtc_db_fetch_array($query); $out = self::SHORT_URL ? $data['gm_url_keywords'].".html" : $this->get_full_categories_names($data['categories_id'], $_SESSION['languages_id'])."/".$data['gm_url_keywords'].".html"; } return $out; } /** * Workaround um die ID der aktuellen Kategorie zu erfassen. * Mit dieser Information wird der Pfad zum Produkt ermittelt * und an den Breadcrumb übergeben. * * @return int */ protected function currentCategory() { $pathInfo = array_filter(explode('/', $_SERVER['PATH_INFO'])); // Produktseite if (!isset($_GET['cPath'])) { $query = xtc_db_query("SELECT cd.categories_id FROM categories_description cd LEFT JOIN categories c USING (categories_id) WHERE categories_status = TRUE AND gm_url_keywords = '".$this->currentCategoryName($pathInfo)."' AND language_id = '".$_SESSION['languages_id']."' LIMIT 1"); $result = xtc_db_fetch_array($query); if ($result) { $_GET['p2c'] = $result['categories_id']; $_GET['cPath'] = xtc_get_category_path($result['categories_id']); return (int)$result['categories_id']; } return null; } // Kategorieseite return (int)end(explode('_', $_GET['cPath'])); } /** * Workaround um den Namen der aktuellen Kategorie zu erfassen. * Mit dieser Information wird der Pfad zum Produkt ermittelt @see currentCategory * * @param $currentPath * @return string */ protected function currentCategoryName($currentPath) { if (isset($_GET['gm_boosted_category'])) { $_SESSION['currentCategoryName'] = end($currentPath); return self::SHORT_URL === true ? $_SESSION['currentCategoryName'] : end($currentPath); } if (isset($_GET['gm_boosted_product']) && self::SHORT_URL === true) { return $this->sessionCategoryName($_SESSION['currentCategoryName'], $currentPath); } if (empty($currentPath)) { unset($_SESSION['currentCategoryName']); } return array_reverse($currentPath)[1]; } /** * Workaround um die URL der Hauptkategorie aus der Startseite eines Artikels zu erfassen. * Ist die $_SESSION['currentCategoryName'] bereits belegt, * wird diese für die Darstellung in URL-Kurzform übernommen. * * @param bool $currentCategoryName * @param $currentPath * @return mixed */ protected function sessionCategoryName($currentCategoryName = null, $currentPath) { if (is_null($currentCategoryName)) { $productsName = trim(str_replace('.html', '', end($currentPath))); $query = xtc_db_query("SELECT cd.gm_url_keywords FROM products_description pd LEFT JOIN products_to_categories p2c USING (products_id) LEFT JOIN categories_description cd USING (categories_id) WHERE pd.gm_url_keywords = '".$productsName."' AND pd.language_id = ".(int)$_SESSION['languages_id']." LIMIT 1"); $result = xtc_db_fetch_array($query); return $_SESSION['currentCategoryName'] = $result['gm_url_keywords']; } return $currentCategoryName; } /** * Legt Anhand der aktuellen Kategorie-ID fest * welche Anweisung für die Datenbankabfrage * festgelegt wird. * * @param $categories_id * @return string */ private function sqlCategoriesId($categories_id) { if (empty($categories_id)) { return 'p2c.categories_id != 0'; } return 'p2c.categories_id = '.$categories_id.''; }} Bei Bedarf "SHORT_URL" auf "true" setzen