. */ namespace Fisharebest\Webtrees\Theme; use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Controller\PageController; use Fisharebest\Webtrees\Database; use Fisharebest\Webtrees\Fact; use Fisharebest\Webtrees\Filter; use Fisharebest\Webtrees\FlashMessages; use Fisharebest\Webtrees\Functions\Functions; use Fisharebest\Webtrees\GedcomRecord; use Fisharebest\Webtrees\GedcomTag; use Fisharebest\Webtrees\HitCounter; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Menu; use Fisharebest\Webtrees\Module; use Fisharebest\Webtrees\Module\AncestorsChartModule; use Fisharebest\Webtrees\Module\CompactTreeChartModule; use Fisharebest\Webtrees\Module\DescendancyChartModule; use Fisharebest\Webtrees\Module\FamilyBookChartModule; use Fisharebest\Webtrees\Module\FamilyTreeFavoritesModule; use Fisharebest\Webtrees\Module\FanChartModule; use Fisharebest\Webtrees\Module\GoogleMapsModule; use Fisharebest\Webtrees\Module\HourglassChartModule; use Fisharebest\Webtrees\Module\InteractiveTreeModule; use Fisharebest\Webtrees\Module\LifespansChartModule; use Fisharebest\Webtrees\Module\PedigreeChartModule; use Fisharebest\Webtrees\Module\RelationshipsChartModule; use Fisharebest\Webtrees\Module\StatisticsChartModule; use Fisharebest\Webtrees\Module\TimelineChartModule; use Fisharebest\Webtrees\Module\UserFavoritesModule; use Fisharebest\Webtrees\Site; use Fisharebest\Webtrees\Theme; use Fisharebest\Webtrees\Tree; use Fisharebest\Webtrees\User; /** * Common functions for all themes. */ abstract class AbstractTheme { /** @var Tree The current tree */ protected $tree; /** @var string An escaped version of the "ged=XXX" URL parameter */ protected $tree_url; /** @var int The number of times this page has been shown */ protected $page_views; /** * Custom themes should place their initialization code in the function hookAfterInit(), not in * the constructor, as all themes get constructed - whether they are used or not. */ final public function __construct() { } /** * Create accessibility links for the header. * * "Skip to content" allows keyboard only users to navigate over the headers without * pressing TAB many times. * * @return string */ protected function accessibilityLinks() { return ''; } /** * Create scripts for analytics and tracking. * * @return string */ protected function analytics() { if ($this->themeId() === '_administration' || !empty($_SERVER['HTTP_DNT'])) { return ''; } else { return $this->analyticsBingWebmaster( Site::getPreference('BING_WEBMASTER_ID') ) . $this->analyticsGoogleWebmaster( Site::getPreference('GOOGLE_WEBMASTER_ID') ) . $this->analyticsGoogleTracker( Site::getPreference('GOOGLE_ANALYTICS_ID') ) . $this->analyticsPiwikTracker( Site::getPreference('PIWIK_URL'), Site::getPreference('PIWIK_SITE_ID') ) . $this->analyticsStatcounterTracker( Site::getPreference('STATCOUNTER_PROJECT_ID'), Site::getPreference('STATCOUNTER_SECURITY_ID') ); } } /** * Create the verification code for Google Webmaster Tools. * * @param string $verification_id * * @return string */ protected function analyticsBingWebmaster($verification_id) { // Only need to add this to the home page. if (WT_SCRIPT_NAME === 'index.php' && $verification_id) { return ''; } else { return ''; } } /** * Create the verification code for Google Webmaster Tools. * * @param string $verification_id * * @return string */ protected function analyticsGoogleWebmaster($verification_id) { // Only need to add this to the home page. if (WT_SCRIPT_NAME === 'index.php' && $verification_id) { return ''; } else { return ''; } } /** * Create the tracking code for Google Analytics. * * See https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced * * @param string $analytics_id * * @return string */ protected function analyticsGoogleTracker($analytics_id) { if ($analytics_id) { // Add extra dimensions (i.e. filtering categories) $dimensions = (object) array( 'dimension1' => $this->tree ? $this->tree->getName() : '-', 'dimension2' => $this->tree ? Auth::accessLevel($this->tree) : '-', ); return '' . ''; } else { return ''; } } /** * Create the tracking code for Piwik Analytics. * * @param string $url - The domain/path to Piwik * @param string $site_id - The Piwik site identifier * * @return string */ protected function analyticsPiwikTracker($url, $site_id) { $url = preg_replace(array('/^https?:\/\//', '/\/$/'), '', $url); if ($url && $site_id) { return ''; } else { return ''; } } /** * Create the tracking code for Statcounter. * * @param string $project_id - The statcounter project ID * @param string $security_id - The statcounter security ID * * @return string */ protected function analyticsStatcounterTracker($project_id, $security_id) { if ($project_id && $security_id) { return ''; } else { return ''; } } /** * Create the top of the . * * @return string */ public function bodyHeader() { return '' . '
' . $this->headerContent() . $this->primaryMenuContainer($this->primaryMenu()) . '
' . '
' . $this->flashMessagesContainer(FlashMessages::getMessages()); } /** * Create the top of the (for popup windows). * * @return string */ public function bodyHeaderPopupWindow() { return '' . '
' . $this->flashMessagesContainer(FlashMessages::getMessages()); } /** * Create a contact link for a user. * * @param User $user * * @return string */ public function contactLink(User $user) { $method = $user->getPreference('contactmethod'); switch ($method) { case 'none': return ''; case 'mailto': return '' . $user->getRealNameHtml() . ''; default: return "" . $user->getRealNameHtml() . ''; } } /** * Create contact link for both technical and genealogy support. * * @param User $user * * @return string */ protected function contactLinkEverything(User $user) { return I18N::translate('For technical support or genealogy questions contact %s.', $this->contactLink($user)); } /** * Create contact link for genealogy support. * * @param User $user * * @return string */ protected function contactLinkGenealogy(User $user) { return I18N::translate('For help with genealogy questions contact %s.', $this->contactLink($user)); } /** * Create contact link for technical support. * * @param User $user * * @return string */ protected function contactLinkTechnical(User $user) { return I18N::translate('For technical support and information contact %s.', $this->contactLink($user)); } /** * Create contact links for the page footer. * * @return string */ protected function contactLinks() { $contact_user = User::find($this->tree->getPreference('CONTACT_USER_ID')); $webmaster_user = User::find($this->tree->getPreference('WEBMASTER_USER_ID')); if ($contact_user && $contact_user === $webmaster_user) { return $this->contactLinkEverything($contact_user); } elseif ($contact_user && $webmaster_user) { return $this->contactLinkGenealogy($contact_user) . '
' . $this->contactLinkTechnical($webmaster_user); } elseif ($contact_user) { return $this->contactLinkGenealogy($contact_user); } elseif ($webmaster_user) { return $this->contactLinkTechnical($webmaster_user); } else { return ''; } } /** * Create a cookie warning. * * @return string */ public function cookieWarning() { if ( empty($_SERVER['HTTP_DNT']) && empty($_COOKIE['cookie']) && (Site::getPreference('GOOGLE_ANALYTICS_ID') || Site::getPreference('PIWIK_SITE_ID') || Site::getPreference('STATCOUNTER_PROJECT_ID')) ) { return ''; } else { return ''; } } /** * Create the tag. * * @return string */ public function doctype() { return ''; } /** * HTML link to a "favorites icon". * * @return string */ protected function favicon() { return '' . '' . ''; } /** * Add markup to a flash message. * * @param \stdClass $message * * @return string */ protected function flashMessageContainer(\stdClass $message) { return $this->htmlAlert($message->text, $message->status, true); } /** * Create a container for messages that are "flashed" to the session * on one request, and displayed on another. If there are many messages, * the container may need a max-height and scroll-bar. * * @param \stdClass[] $messages * * @return string */ protected function flashMessagesContainer(array $messages) { $html = ''; foreach ($messages as $message) { $html .= $this->flashMessageContainer($message); } if ($html) { return '
' . $html . '
'; } else { return ''; } } /** * Close the main content and create the
tag. * * @return string */ public function footerContainer() { return '
'; } /** * Close the main content. * Note that popup windows are deprecated * * @return string */ public function footerContainerPopupWindow() { return '
'; } /** * Create the contents of the