Ja, dann einen Moment. Ich melde mich gleich. Muss meinen Lehrling erst in Gambio und Photoshop einführen
@slavek diesen Code übernehmen "BugfixGMSEOBoost.php" 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 = true; protected $currentCategoryId; protected $output = []; 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 SEO spezifische Meta "alternate" und "canonical" Angabe eines Artikels zurück. * * @param null $productsId * * @return mixed */ public function getSeoTags($productsId = null) { $languageData = $this->get_language_data('product', $productsId); if (gm_get_conf('USE_SEO_BOOST_LANGUAGE_CODE') == 'true') { $languageData['code'] .= '/'; } else { $languageData['code'] = ''; } $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); $this->output['canonical_url'] = self::SHORT_URL ? $languageData['code'].$data['gm_url_keywords'].".html" : $this->get_full_categories_names($data['categories_id'], $_SESSION['languages_id']).$languageData['code'].$data['gm_url_keywords'].".html"; } $query = xtc_db_query("SELECT languages_id, code FROM languages WHERE status = 1"); if (xtc_db_num_rows($query) > 0) { $activeCodes = []; while ($activeCode = xtc_db_fetch_array($query)) { $activeCodes['codes'][$activeCode['code']] = $activeCode['languages_id']; } } array_walk($activeCodes, function ($value) use ($productsId) { $alternateUrl = xtc_href_link($this->get_boosted_product_url($productsId, '', $value)); if ($value != $_SESSION['languages_id']) { $this->output['alternate_url'][strtolower(key($value))] = htmlspecialchars($alternateUrl); } }); return $this->output; } /** * 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.''; }}
@monevo hallo! habe gerade instaliert... und kein fatal error mehr! DEUTSCH: ("alternate" hreflang=EN) <link rel="alternate" hreflang="en" href="http://www.shop.de/en/artikel.html"/> <link rel="canonical" href="http://www.shop.de/de/artikel.html"/> <base href="http://www.shop.de/" /> SPANISCH: ("alternate" hreflang=EN) <link rel="alternate" hreflang="en" href="http://www.shop.de/en/article.html"/> <link rel="canonical" href="http://www.shop.de/es/articulo.html"/> <base href="http://www.shop.de/" /> ENGLISCH: ("alternate" hreflang=EN) <link rel="alternate" hreflang="en" href="http://www.shop.de/en/article.html"/> <link rel="canonical" href="http://www.shop.de/en/article.html"/> <base href="http://www.shop.de/" /> canonical-URL = jetz alles OK! Spachcode/Landcode eingebaut! JETZ NOCH MEINE FRAGE: Wie kannst Du selbst sehen, in allen drei Sprachen ist als "alternate" hreflang immer nur Englisch (<link rel="alternate" hreflang="en" href="http://www.shop.de/en/article.html") Sogar fuer Englisch "alternate hreflang ist Englisch?! Ist es korrekt so? Soll es nicht so sein???: alternate hreflang fuer Deutsch = Englisch und Spanisch alternate hreflang fuer Englisch = Deutsch und Spanisch alternate hreflang fuer Spanisch = Deutsch und Englisch Vielen Dank im Voraus fuer Deine Antwort! lg, slavek
Hallo @slavek so sollte es auch sein, da habe ich wohl an einer Stelle gepennt. Ich schaue gleich mal, wo es hackt...
@slavek Code übernehmen "BugfixGMSEOBoost.php" 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 = true; protected $currentCategoryId; protected $output = []; 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 SEO spezifische Meta "alternate" und "canonical" Angabe eines Artikels zurück. * * @param null $productsId * * @return mixed */ public function getSeoTags($productsId = null) { $languageData = $this->get_language_data('product', $productsId); if (gm_get_conf('USE_SEO_BOOST_LANGUAGE_CODE') == 'true') { $languageData['code'] .= '/'; } else { $languageData['code'] = ''; } $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); $this->output['canonical_url'] = self::SHORT_URL ? $languageData['code'].$data['gm_url_keywords'].".html" : $this->get_full_categories_names($data['categories_id'], $_SESSION['languages_id']).$languageData['code'].$data['gm_url_keywords'].".html"; } $query = xtc_db_query("SELECT languages_id, code FROM languages WHERE status = 1"); if (xtc_db_num_rows($query) > 0) { $activeCodes = []; while ($activeCode = xtc_db_fetch_array($query)) { $activeCodes[$activeCode['code']] = $activeCode['languages_id']; } } foreach ($activeCodes as $code => $key) { if ($key != $_SESSION['languages_id']) { $alternateUrl = xtc_href_link($this->get_boosted_product_url($productsId, '', $key)); $this->output['alternate_url'][strtolower($code)] = htmlspecialchars($alternateUrl); } } return $this->output; } /** * 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.''; }} Was macht die Kaffeekasse?
@monevo Jetzt hat alles super geklappt! Vielen Dank! Artikelseite-Quelltext: <link rel="alternate" hreflang="en" href="http://www.shop.de/en/article.html"/> <link rel="alternate" hreflang="de" href="http://www.shop.de/de/artikel.html"/> <link rel="canonical" href="http://www.shop.de/es/articulo.html"/> <base href="http://www.shop.de/" /> Hola Google, ¿qué tal? I am the most mature out of my twin brothers and I want to be indexed. I speak Spanish and these are my cousins from other countries. Can you please index them too? lg, slavek
Hallo, ich hatte dieses Bugfix mit SEOBoost in meinem v2.4.0.1 eingebaut, also unter user_classes in Hauptverzeichnis und sehe, dass in aktuelle Version user_classes befindet sich in Hauptverseichnis nicht. Also jetzt nach dem Update auf 3.10.0.1 kann ich user_classes komplett Loeschen? Oder soll ich das vor dem Update machen und jetzt zum Probleme im Shop kommen kann? lg slavek
Du kannst diesen Bugfix eigentlich wieder aus deinem Shop entfernen, weil dieser bereits ich glaube in der 3.8 integriert wurde.
Hallo Sergej @monevo aber sag mir bitte wie? Ich habe ganze Ordner "user_classes" aus(Link nur für registrierte Nutzer sichtbar.)(Link nur für registrierte Nutzer sichtbar.) aber sehe, dass mit dem Update alle Dateien aus Hauptverzeichnis /user_classes/overloads wurden an Hauptverzeichnis /GXUserComponents/overloads verschoben. Muss ich jetzt alle markierte Dateien aus dem Ordner "overloads" wie auf dem Foto loeschen? Oder muss hier etwas bleiben?
Den Ordner "user_classes" hättest du vor dem Update nicht löschen brauchen. Das würde der Updater bereits für dich machen. Im Prinzip kannst du alle Dateien (und nur die) entfernen (oder Ordner umbenennen), die im Zusammenhang mit dem Bugfixing aus diesem Beitrag angelegt/überladen wurden. Natürlich kannst du vorab eine Kopie der Dateien bei dir Lokal ablegen (man weißt nie ) Ich glaube bei dir wurden, neben dem eigentlichen Bugfixing aus dem Beitrag hier, noch weitere Sachen angepasst. Musst du gucken, was bzgl. Breadcrumb und Artikelnavigator weg kann und was an Anpassung da ist, welches nichts mit dem Bugfixing hier aus dem Beitrag zu tun hat. So oder so, kann mir gut vorstellen, dass du die vorhandenen Anpassungen gegen die neue Shopversion abgleichen und ggfl. die Anpassung auf die neue Shopversion überführen musst. Von 2.4 nach 3.10 ist ein langer Weg. Dazu kommt noch ein automatischer Wechsel von EyeCandy nach Honeygrid.
Ich habe ein Update mit diesem Paket auf einmal gemacht: Update_GX_2.4.0.0_auf_3.10.0.1, aber diese Ordner"user_classes" wurde nicht geloescht. ?! Auserdem sehe ich, dass weitere Ordners, die wahrscheinlich nicht geloescht wurden: (Link nur für registrierte Nutzer sichtbar.) img StyleEdit Update falsch gemacht? Oder? Koennen diese alte Ordners probleme im Shop machen, oder die stoeren ganz nicht? Ich habe auf Honeygrid geaendert, und der Shop funktioniert. Jetzt, wenn habe ich Deine alte Bugfix von overloads, geloescht, die URL-Kategorie wieder perfekt wie vorher funktionieren, aber jetzt geht es ohne Bugfix Ich habe alle markierte Dateien aus dem Ordner overloads geloescht, die wahrschenlich waren nur fuer EyeCandy gemacht. Jetzt werden wir sehen, ob ich dieses neue GX3 zur Zeit ohne externes Grafikdesign nur mit StyleEdit3 verwalten kann... lg slavek