Nos magasins > {page}" (also feeds the BreadcrumbList JSON-LD of head-jsonld.tpl); * - LocalBusiness JSON-LD assigned as $store_jsonld, printed by cms/page-store.tpl. * * After adding this file, delete var/cache/prod/class_index.php so PrestaShop picks up the override. */ class CmsController extends CmsControllerCore { public function getBreadcrumbLinks() { $breadcrumb = parent::getBreadcrumbLinks(); if ($this->assignCase == self::CMS_CASE_PAGE && $this->getLinkedStoreId() && !empty($breadcrumb['links'])) { $current = array_pop($breadcrumb['links']); $breadcrumb['links'][] = [ 'title' => $this->trans('Our stores', [], 'Shop.Theme.Global'), 'url' => $this->context->link->getPageLink('stores'), ]; $breadcrumb['links'][] = $current; } return $breadcrumb; } public function initContent() { parent::initContent(); if ($this->assignCase != self::CMS_CASE_PAGE) { return; } // $cms.store is added by rocketextrastore (hook filterCmsContent) during parent::initContent(). $cms = $this->context->smarty->getTemplateVars('cms'); if (empty($cms['store']) || !is_array($cms['store'])) { return; } $this->context->smarty->assign( 'store_jsonld', json_encode( $this->buildStoreJsonLd($cms['store']), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG ) ); } protected function getLinkedStoreId() { if (!Validate::isLoadedObject($this->cms) || !Module::isEnabled('rocketextrastore')) { return 0; } if (!class_exists('StoreExtra')) { require_once _PS_MODULE_DIR_ . 'rocketextrastore/classes/StoreExtra.php'; } return (int) StoreExtra::getIdStoreByIdCms((int) $this->cms->id); } protected function buildStoreJsonLd(array $store) { $url = $this->context->link->getCMSLink($this->cms); $address = $store['address']; $data = [ '@context' => 'https://schema.org', '@type' => 'SportingGoodsStore', '@id' => $url . '#store', 'name' => 'Foot.fr ' . $store['name'], 'url' => $url, 'parentOrganization' => [ '@type' => 'Organization', 'name' => 'Foot.fr', 'url' => $this->context->link->getPageLink('index'), ], 'address' => [ '@type' => 'PostalAddress', 'streetAddress' => trim($address['address1'] . ' ' . $address['address2']), 'postalCode' => $address['postcode'], 'addressLocality' => $address['city'], // The country name in BO is "France Métropolitaine et Corse": schema.org wants the ISO code. 'addressCountry' => Country::getIsoById((int) $address['id_country']) ?: 'FR', ], ]; $phone = preg_replace('/\D/', '', (string) $store['phone']); if (strlen($phone) === 10 && $phone[0] === '0') { $data['telephone'] = '+33' . substr($phone, 1); } if (!empty($store['image']['bySize']['stores_default']['url'])) { $data['image'] = $store['image']['bySize']['stores_default']['url']; } if ((float) $store['latitude'] && (float) $store['longitude']) { $data['geo'] = [ '@type' => 'GeoCoordinates', 'latitude' => (float) $store['latitude'], 'longitude' => (float) $store['longitude'], ]; $data['hasMap'] = 'https://www.google.com/maps/search/?api=1&query=' . $store['latitude'] . ',' . $store['longitude']; } // A store flagged "FERMÉ TEMPORAIREMENT" / "fermé définitivement" must not advertise opening hours. // ("Fermé le lundi" must not match.) if (!preg_match('/ferm\S*\s+(temporairement|d[ée]finitivement)/iu', (string) $store['note'])) { $hours = $this->parseOpeningHours($store['business_hours']); if ($hours) { $data['openingHoursSpecification'] = $hours; } } return $data; } /** * BO hours are free text, written differently from one store to another: * "10H00-19H00", "10H00-19H", "10H-19H", "10h30-19h", "10h-12h30/14h-18h30", "10h-12h / 14h-19h". * An empty day means closed. */ protected function parseOpeningHours(array $businessHours) { $days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; $specs = []; foreach (array_values($businessHours) as $i => $day) { if (!isset($days[$i])) { break; } $text = implode(' / ', (array) $day['hours']); $pattern = '/(\d{1,2})\s*[hH:]\s*(\d{2})?\s*-\s*(\d{1,2})\s*(?:[hH:]\s*(\d{2})?)?/'; if (!preg_match_all($pattern, $text, $slots, PREG_SET_ORDER | PREG_UNMATCHED_AS_NULL)) { continue; } foreach ($slots as $slot) { $specs[] = [ '@type' => 'OpeningHoursSpecification', 'dayOfWeek' => 'https://schema.org/' . $days[$i], 'opens' => sprintf('%02d:%02d', (int) $slot[1], (int) ($slot[2] ?? 0)), 'closes' => sprintf('%02d:%02d', (int) $slot[3], (int) ($slot[4] ?? 0)), ]; } } return $specs; } }