| Current Path : /home/digilove/public_html/plugins/system/gsd/ |
| Current File : /home/digilove/public_html/plugins/system/gsd/gsd.php |
<?php
/**
* @package Google Structured Data
* @version 5.6.5 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use GSD\Helper;
class plgSystemGSD extends CMSPlugin
{
/**
* Auto loads the plugin language file
*
* @var boolean
*/
protected $autoloadLanguage = true;
/**
* The loaded indicator of helper
*
* @var boolean
*/
protected $init;
/**
* Application Object
*
* @var object
*/
protected $app;
/**
* JSON Helper
*
* @var class
*/
private $json;
/**
* onBeforeCompileHead event to add JSON markup to the document
*
* @return void
*/
public function onBeforeCompileHead()
{
// Load Helper
if (!$this->getHelper())
{
return;
}
if (!$this->params->get('wait_page_render', false) && $markup = $this->getMarkup())
{
Factory::getDocument()->addCustomTag($markup);
}
// Add Snippets Control
$this->addRobotSnippetControl();
}
/**
* This event is triggered after the framework has rendered the application.
*
* @return void
*/
public function onAfterRender()
{
// Load Helper
if (!$this->getHelper())
{
return;
}
// Try to remove redundant microdata
$this->removeMicrodata();
if ($this->params->get('wait_page_render', false) && $markup = $this->getMarkup())
{
$buffer = $this->app->getBody();
// If </body> exists prepend the markup
if (strpos($buffer, '</body>'))
{
$buffer = str_replace('</body>', $markup . '</body>', $buffer);
} else
// If </body> is not found append markup to document's end
{
$buffer .= $markup;
}
$this->app->setBody($buffer);
}
// Output log messages if debug is enabled
if ($this->params->get('debug', false) && Factory::getUser()->authorise('core.admin'))
{
echo LayoutHelper::render('debug', ['logs' => Helper::$log], JPATH_ADMINISTRATOR . '/components/com_gsd/layouts');
}
}
/**
* Adds Google Structured Markup to the document in JSON Format
*
* @return void
*/
private function getMarkup()
{
Helper::log($this->app->input->getArray());
// Get JSON markup for each available type
$data = [
$this->getJSONWebsite(),
$this->getJSONLogo(),
$this->getJSONSocialProfiles(),
$this->getJSONBusinessListing(),
$this->getCustomCode(),
$this->getJSONBreadcrumbs()
];
// Load and trigger plugins
Helper::event('onGSDBeforeRender', array(&$data));
// Convert data array to string
$markup = implode("\n", array_filter($data));
// Return if markup is empty
if (!$markup || empty($markup) || is_null($markup))
{
return;
}
// Minify output
if ($this->params->get('minifyjson', false))
{
$markup = Helper::minify($markup);
}
Helper::log($markup);
return '
<!-- Start: ' . Text::_("GSD") . ' -->
' . $markup . '
<!-- End: ' . Text::_("GSD") . ' -->
';
}
/**
* Route default form's prepare event to onGSDPluginForm to help our plugins manipulate the form
*
* @param Form $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*/
public function onContentPrepareForm($form, $data)
{
// Run only on backend
if (!$this->app->isClient('administrator') || !$form instanceof Form)
{
return;
}
// Load libraries
if (!$this->setup())
{
return;
}
Helper::event('onGSDPluginForm', array($form, $data));
}
/**
* Add Robots Snippet Control
* https://webmasters.googleblog.com/2019/09/more-controls-on-search.html
*
* @return void
*/
private function addRobotSnippetControl()
{
$robots = Factory::getDocument()->getMetaData('robots');
// Skip, if the existing value contains any of the following text
if (\NRFramework\Functions::strpos_arr(['noindex', 'nosnippet', 'max-'], $robots))
{
return;
}
$value = 'max-snippet:-1, max-image-preview:large, max-video-preview:-1';
$robots = empty($robots) ? $value : $robots . ', ' . $value;
Factory::getDocument()->setMetaData('robots', $robots);
}
/**
* Search and remove redundant microdata generated by 3rd party extensions.
*
* @return void
*/
private function removeMicrodata()
{
$filter = InputFilter::getInstance();
$default = [
[
'name' => 'BreadcrumbList',
'enabled' => true
]
];
$schema_types = array_map(function($item) use($filter)
{
$item = is_object($item) ? $item : (object) $item;
if ($item->enabled)
{
return $filter->clean($item->name, 'ALNUM');
}
}, (array) $this->params->get('removemicrodata', $default));
if (!$schema_types = array_filter($schema_types))
{
return;
}
Helper::log($schema_types);
\GSD\SchemaCleaner::remove($schema_types);
}
/**
* K2 event
* This event helps us to inject our form to K2 plugins tab on the item editing page
*
* Note: This block should be moved somehow to the K2 plugin.
*
* @param object &$item The item data
* @param string $type The current view
* @param string $tab The tab's name
*
* @return object The plugin's data object
*/
public function onRenderAdminForm(&$item, $type, $tab = '')
{
// Make sure we are on the right context
if (!$this->app->isClient('administrator') || $type != 'item' || $tab != 'other')
{
return;
}
// Load libraries
if (!$this->setup())
{
return;
}
$result = Helper::event('onGSDPluginForm', array($item, null));
return isset($result[0]) ? $result[0] : '';
}
/**
* Returns Breadcrumbs structured data markup
* https://developers.google.com/structured-data/breadcrumbs
*
* @return string
*/
private function getJSONBreadcrumbs()
{
if (!$this->params->get('breadcrumbs_enabled', true))
{
return;
}
$include_home = $this->params->get('include_home', true);
$home_text = $this->params->get('breadcrumbs_home', Text::_('GSD_BREADCRUMBS_HOME'));
// Generate JSON
return $this->json->setData(array(
'contentType' => 'breadcrumbs',
'crumbs' => Helper::getCrumbs($home_text, $include_home)
))->generate();
}
/**
* Returns Website Schema
*
* @return string on success, boolean on fail
*/
private function getJSONWebsite()
{
// Only on homepage
if (!Helper::isFrontPage())
{
return;
}
$site_links_search = $this->params->get('sitelinks_enabled', false);
$site_name = (bool) $this->params->get('sitename_enabled', true);
// If both Site Name and Site Links Search are disabled, return
if (!$site_links_search && !$site_name)
{
return;
}
// Get the sitelinks settings
if ($site_links_search)
{
switch ($site_links_search)
{
case '1': // com_search
$site_links_search = Helper::route('index.php?option=com_search&searchphrase=all&searchword={search_term}');
break;
case '2': // com_finder
$site_links_search = Helper::route('index.php?option=com_finder&view=search&q={search_term}');
break;
case '3': // custom URL
$site_links_search = trim($this->params->get('sitelinks_search_custom_url'));
break;
}
}
// Generate JSON
return $this->json->setData([
'contentType' => 'website',
'site_name_enabled' => $site_name,
'site_name' => Helper::getSiteName(),
'site_name_alt' => $this->params->get('sitename_name_alt'),
'site_url' => Helper::getSiteURL(),
'site_links_search' => $site_links_search
])->generate();
}
/**
* Returns Site Logo structured data markup
* https://developers.google.com/search/docs/data-types/logo
*
* @return string on success, boolean on fail
*/
private function getJSONLogo()
{
// Only on homepage
if (!Helper::isFrontPage())
{
return;
}
if (!$logo = Helper::getSiteLogo())
{
return;
}
// Generate JSON
return $this->json->setData(array(
"contentType" => "logo",
"url" => Helper::getSiteURL(),
"logo" => Helper::cleanImage($logo)
))->generate();
}
/**
* Returns Social Profiles structured data markup
* https://developers.google.com/search/docs/data-types/social-profile-links
*
* @return string on success, boolean on fail
*/
private function getJSONSocialProfiles()
{
// Only on homepage
if (!Helper::isFrontPage())
{
return;
}
$predefinedURLs = array(
$this->params->get("socialprofiles_facebook"),
$this->params->get("socialprofiles_twitter"),
$this->params->get("socialprofiles_instagram"),
$this->params->get("socialprofiles_youtube"),
$this->params->get("socialprofiles_linkedin"),
$this->params->get("socialprofiles_pinterest"),
$this->params->get("socialprofiles_soundcloud"),
$this->params->get("socialprofiles_tumblr")
);
$otherURLs = explode("\n", $this->params->get("socialprofiles_other", ''));
// Merge arrays and remove empty items
$URLs = array_filter(
array_merge(
$predefinedURLs,
$otherURLs
)
);
// Remove new line and space characters
$URLs = array_map(function($url)
{
return str_replace([' ', "\n", "\t", "\r"], '', $url);
}, $URLs);
// Return if array is empty
if (count($URLs) == 0)
{
return;
}
// Generate JSON
return $this->json->setData(array(
"contentType" => "socialprofiles",
"type" => $this->params->get("socialprofiles_type", "Organization"),
"siteurl" => Helper::getSiteURL(),
"sitename" => Helper::getSiteName(),
"links" => $URLs
))->generate();
}
/**
* Returns Local Business structured data markup
* https://developers.google.com/search/docs/data-types/local-businesses
*
* @return string on success, boolean on fail
*/
private function getJSONBusinessListing()
{
if (!$this->params->get("businesslisting_enabled", false) || !Helper::isFrontPage())
{
return;
}
$coordinates = explode(',', $this->params->get('businesslisting_latlng'));
$coordinates[0] = (isset($coordinates[0])) ? $coordinates[0] : '36.892587';
$coordinates[1] = (isset($coordinates[1])) ? $coordinates[1] : '27.287793';
$weekDays = Helper::getWeekdays();
$openingHours = array(
"businesslisting_hours_available" => $this->params->get('businesslisting_hours_available')
);
foreach ($weekDays as $weekDay)
{
$openingHours['businesslisting_' . $weekDay] = $this->params->get('businesslisting_' . $weekDay);
$openingHours['businesslisting_' . $weekDay . '_start'] = $this->params->get('businesslisting_' . $weekDay . '_start');
$openingHours['businesslisting_' . $weekDay . '_end'] = $this->params->get('businesslisting_' . $weekDay . '_end');
}
$data = array(
'contentType' => 'businesslisting',
'id' => Helper::getSiteURL(),
'name' => Helper::getSiteName(),
'image' => Helper::getSiteLogo(),
'coordinates' => $coordinates,
'type' => $this->params->get('businesslisting_type'),
'price_range' => $this->params->get('price_range', 0),
'streetAddress' => $this->params->get('businesslisting_street_address'),
'addressLocality' => $this->params->get('businesslisting_address_locality'),
'addressRegion' => $this->params->get('businesslisting_address_region'),
'postalCode' => $this->params->get('businesslisting_postal_code'),
'addressCountry' => $this->params->get('businesslisting_address_country'),
'telephone' => $this->params->get('businesslisting_telephone'),
'servesCuisine' => $this->params->get('servesCuisine'),
'openingHours' => $openingHours,
);
// Generate JSON
return $this->json->setData($data)->generate();
}
/**
* Returns Custom Code
*
* @return string The Custom Code
*/
private function getCustomCode()
{
return trim((string) $this->params->get('customcode'));
}
/**
* Load required classes and configuration
*
* @return bool
*/
private function setup()
{
// Initialize framework
if (!@include_once(JPATH_PLUGINS . '/system/nrframework/autoload.php'))
{
return;
}
// Make sure the component is installed and enabled.
if (!\NRFramework\Extension::componentIsEnabled('gsd'))
{
return;
}
// Initialize extension library
if (!@include_once(JPATH_ADMINISTRATOR . '/components/com_gsd/autoload.php'))
{
return;
}
// Load configuration options
$this->params = Helper::getParams();
return true;
}
/**
* Loads Helper files
*
* @return boolean
*/
private function getHelper()
{
// Return if is helper is already loaded
if ($this->init)
{
return true;
}
// Return if we are not in frontend
if (!$this->app->isClient('site'))
{
return false;
}
// Only on HTML documents
if (Factory::getDocument()->getType() !== 'html')
{
return false;
}
// Load libraries
if (!$this->setup())
{
return;
}
// Return if current page is an XML page
if (NRFramework\Functions::isFeed() || $this->app->input->getInt('print', 0))
{
return false;
}
// Initialize JSON Generator Class
$this->json = new \GSD\Json();
return ($this->init = true);
}
}