<?php
/**
* @package Unlimited Elements
* @author unlimited-elements.com
* @copyright (C) 2021 Unlimited Elements, All Rights Reserved.
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
*/
if ( ! defined( 'ABSPATH' ) ) exit;
class UniteCreatorAPIIntegrations{
const FORMAT_DATE = "d.m.Y";
const FORMAT_DATETIME = "d.m.Y H:i";
const FORMAT_MYSQL_DATETIME = "Y-m-d H:i:s";
const TYPE_CURRENCY_EXCHANGE = "currency_exchange";
const TYPE_GOOGLE_EVENTS = "google_events";
const TYPE_GOOGLE_REVIEWS = "google_reviews";
const TYPE_GOOGLE_SHEETS = "google_sheets";
const TYPE_WEATHER_FORECAST = "weather_forecast";
const TYPE_YOUTUBE_PLAYLIST = "youtube_playlist";
const SETTINGS_OPEN_WEATHER_API_KEY = "openweather_api_key";
const SETTINGS_EXCHANGE_RATE_API_KEY = "exchangerate_api_key";
const CURRENCY_EXCHANGE_FIELD_EMPTY_API_KEY = "currency_exchange_empty_api_key";
const CURRENCY_EXCHANGE_FIELD_CURRENCY = "currency_exchange_currency";
const CURRENCY_EXCHANGE_FIELD_PRECISION = "currency_exchange_precision";
const CURRENCY_EXCHANGE_FIELD_INCLUDE_CURRENCIES = "currency_exchange_include_currencies";
const CURRENCY_EXCHANGE_FIELD_CACHE_TIME = "currency_exchange_cache_time";
const CURRENCY_EXCHANGE_MIN_PRECISION = 2;
const CURRENCY_EXCHANGE_MAX_PRECISION = 6;
const CURRENCY_EXCHANGE_DEFAULT_PRECISION = 2;
const CURRENCY_EXCHANGE_DEFAULT_CACHE_TIME = 60;
const GOOGLE_EVENTS_FIELD_EMPTY_CREDENTIALS = "google_events_empty_credentials";
const GOOGLE_EVENTS_FIELD_TIMEZONE = "google_events_timezone";
const GOOGLE_EVENTS_FIELD_CALENDAR_ID = "google_events_calendar_id";
const GOOGLE_EVENTS_FIELD_RANGE = "google_events_range";
const GOOGLE_EVENTS_FIELD_ORDER = "google_events_order";
const GOOGLE_EVENTS_FIELD_LIMIT = "google_events_limit";
const GOOGLE_EVENTS_FIELD_CACHE_TIME = "google_events_cache_time";
const GOOGLE_EVENTS_DEFAULT_LIMIT = 250;
const GOOGLE_EVENTS_DEFAULT_CACHE_TIME = 10;
const GOOGLE_EVENTS_RANGE_UPCOMING = "upcoming";
const GOOGLE_EVENTS_RANGE_TODAY = "today";
const GOOGLE_EVENTS_RANGE_TOMORROW = "tomorrow";
const GOOGLE_EVENTS_RANGE_WEEK = "week";
const GOOGLE_EVENTS_RANGE_MONTH = "month";
const GOOGLE_EVENTS_ORDER_DATE_ASC = "date:asc";
const GOOGLE_EVENTS_ORDER_DATE_DESC = "date:desc";
const GOOGLE_REVIEWS_FIELD_EMPTY_API_KEY = "google_reviews_empty_api_key";
const GOOGLE_REVIEWS_FIELD_PLACE_ID = "google_reviews_place_id";
const GOOGLE_REVIEWS_FIELD_API_TEXT = "google_reviews_api_text";
const GOOGLE_REVIEWS_FIELD_CACHE_TIME = "google_reviews_cache_time";
const GOOGLE_REVIEWS_FIELD_LANG = "google_reviews_lang";
const GOOGLE_REVIEWS_FIELD_SHOW_DEBUG = "google_reviews_show_debug";
const GOOGLE_REVIEWS_SORT_BY = "google_reviews_sort_by";
const GOOGLE_REVIEWS_SERP_CACHE_TIME = "google_reviews_serp_cache_time";
const GOOGLE_REVIEWS_DEFAULT_CACHE_TIME = 10;
const GOOGLE_REVIEWS_CACHE_TIME_DAY = 86400; // 1 day in seconds
const GOOGLE_REVIEWS_CACHE_TIME_WEEK = 604800; // 1 week in seconds
const GOOGLE_REVIEWS_CACHE_TIME_MONTH = 2592000; // 1 month in seconds (30 days)
const GOOGLE_SHEETS_FIELD_EMPTY_CREDENTIALS = "google_sheets_empty_credentials";
const GOOGLE_SHEETS_FIELD_ID = "google_sheets_id";
const GOOGLE_SHEETS_FIELD_SHEET_ID = "google_sheets_sheet_id";
const GOOGLE_SHEETS_FIELD_CACHE_TIME = "google_sheets_cache_time";
const GOOGLE_SHEETS_DEFAULT_CACHE_TIME = 10;
const GOOGLE_SHEETS_EXCLUDE_FIRST_ROW = "google_sheets_exclude_first_row";
const WEATHER_FORECAST_FIELD_EMPTY_API_KEY = "weather_forecast_empty_api_key";
const WEATHER_FORECAST_FIELD_LOCALE = "weather_forecast_locale";
const WEATHER_FORECAST_FIELD_COUNTRY = "weather_forecast_country";
const WEATHER_FORECAST_FIELD_CITY = "weather_forecast_city";
const WEATHER_FORECAST_FIELD_UNITS = "weather_forecast_units";
const WEATHER_FORECAST_FIELD_CACHE_TIME = "weather_forecast_cache_time";
const WEATHER_FORECAST_DEFAULT_CACHE_TIME = 60;
const WEATHER_FORECAST_UNITS_METRIC = "metric";
const WEATHER_FORECAST_UNITS_IMPERIAL = "imperial";
const YOUTUBE_PLAYLIST_FIELD_EMPTY_CREDENTIALS = "youtube_playlist_empty_credentials";
const YOUTUBE_PLAYLIST_FIELD_ID = "youtube_playlist_id";
const YOUTUBE_PLAYLIST_FIELD_ORDER = "youtube_playlist_order";
const YOUTUBE_PLAYLIST_FIELD_LIMIT = "youtube_playlist_limit";
const YOUTUBE_PLAYLIST_FIELD_CACHE_TIME = "youtube_playlist_cache_time";
const YOUTUBE_PLAYLIST_DEFAULT_LIMIT = 5;
const YOUTUBE_PLAYLIST_DEFAULT_CACHE_TIME = 10;
const YOUTUBE_PLAYLIST_ORDER_DEFAULT = "default";
const YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_ASC = "date_added:asc";
const YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_DESC = "date_added:desc";
const YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_RANDOM = "date_added:random";
const YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_ASC = "date_published:asc";
const YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_DESC = "date_published:desc";
const YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_RANDOM = "date_published:random";
const ORDER_FIELD = "__order_field";
const ORDER_DIRECTION_ASC = "asc";
const ORDER_DIRECTION_DESC = "desc";
const ORDER_DIRECTION_RANDOM = "random";
private static $instance = null;
private $googleReviewsShowDebug = false;
private $params = array();
/**
* create a new instance
*
* @return void
*/
public function __construct(){
$this->init();
}
/**
* get the class instance
*
* @return self
*/
public static function getInstance(){
if(self::$instance === null)
self::$instance = new self();
return self::$instance;
}
/**
* get the api types
*
* @return array
*/
public function getTypes(){
$types = array();
if(GlobalsUnlimitedElements::$enableGoogleAPI === true){
$types[self::TYPE_GOOGLE_EVENTS] = "Google Events";
$types[self::TYPE_GOOGLE_REVIEWS] = "Google Reviews";
$types[self::TYPE_GOOGLE_SHEETS] = "Google Sheets";
$types[self::TYPE_YOUTUBE_PLAYLIST] = "Youtube Playlist";
}
if(GlobalsUnlimitedElements::$enableWeatherAPI === true)
$types[self::TYPE_WEATHER_FORECAST] = "Weather Forecast";
if(GlobalsUnlimitedElements::$enableCurrencyAPI === true)
$types[self::TYPE_CURRENCY_EXCHANGE] = "Currency Exchange";
return $types;
}
/**
* get the api data
*
* @return array
*/
public function getData($type, $params){
// add api keys
$params[self::SETTINGS_OPEN_WEATHER_API_KEY] = HelperProviderCoreUC_EL::getGeneralSetting(self::SETTINGS_OPEN_WEATHER_API_KEY);
$params[self::SETTINGS_EXCHANGE_RATE_API_KEY] = HelperProviderCoreUC_EL::getGeneralSetting(self::SETTINGS_EXCHANGE_RATE_API_KEY);
$this->params = $this->remapLegacyParams($params);
// get data
$data = array();
switch($type){
case self::TYPE_CURRENCY_EXCHANGE:
$data = $this->getCurrencyExchangeData();
break;
case self::TYPE_GOOGLE_EVENTS:
$data = $this->getGoogleEventsData();
break;
case self::TYPE_GOOGLE_REVIEWS:
$data = $this->getGoogleReviewsData();
break;
case self::TYPE_GOOGLE_SHEETS:
$data = $this->getGoogleSheetsData();
break;
case self::TYPE_WEATHER_FORECAST:
$data = $this->getWeatherForecastData();
break;
case self::TYPE_YOUTUBE_PLAYLIST:
$data = $this->getYoutubePlaylistData();
break;
default:
if(UniteFunctionsUC::isMaxDebug()){
UniteFunctionsUC::showTrace();
}
UniteFunctionsUC::throwError(__FUNCTION__ . " Error: API type \"$type\" is not implemented");
break;
}
return $data;
}
/**
* get the api data for multisource
*/
public function getDataForMultisource($type, $params){
$data = $this->getData($type, $params);
switch($type){
case self::TYPE_CURRENCY_EXCHANGE:
$data = UniteFunctionsUC::getVal($data, "rates_chosen");
break;
case self::TYPE_WEATHER_FORECAST:
$data = UniteFunctionsUC::getVal($data, "daily");
break;
case self::TYPE_GOOGLE_REVIEWS:
$data = UniteFunctionsUC::getVal($data, "reviews");
break;
}
return $data;
}
/**
* add the api data to params
*
* @return array
*/
public function addDataToParams($data, $name, $paramType = null){
$params = UniteFunctionsUC::getVal($data, $name, array());
$params = UniteFunctionsUC::clearKeysFirstUnderscore($params);
try{
$apiType = UniteFunctionsUC::getVal($params, "api_type");
//some small fix - get api type by special param type
if(empty($apiType)){
switch($paramType){
case "reviews":
$apiType = "google_reviews";
break;
}
}
$apiData = $this->getData($apiType, $params);
$params["success"] = true;
$params = array_merge($params, $apiData);
}catch(Exception $exception){
$params["success"] = false;
$params["error"] = $exception->getMessage();
}
$data[$name] = $params;
return $data;
}
/**
* get settings fields
*
* @return array
*/
public function getSettingsFields($isSingle = false){
$fields = array();
if(GlobalsUnlimitedElements::$enableGoogleAPI === true){
$fields[self::TYPE_GOOGLE_EVENTS] = $this->getGoogleEventsSettingsFields();
$fields[self::TYPE_GOOGLE_REVIEWS] = $this->getGoogleReviewsSettingsFields($isSingle);
$fields[self::TYPE_GOOGLE_SHEETS] = $this->getGoogleSheetsSettingsFields();
$fields[self::TYPE_YOUTUBE_PLAYLIST] = $this->getYoutubePlaylistSettingsFields();
}
if(GlobalsUnlimitedElements::$enableCurrencyAPI === true)
$fields[self::TYPE_CURRENCY_EXCHANGE] = $this->getCurrencyExchangeSettingsFields();
if(GlobalsUnlimitedElements::$enableWeatherAPI === true)
$fields[self::TYPE_WEATHER_FORECAST] = $this->getWeatherForecastSettingsFields();
return $fields;
}
/**
* add service settings fields
*
* @return void
*/
public function addServiceSettingsFields($settingsManager, $type, $name, $condition = null){
$fields = $this->getSettingsFields(true);
$fields = UniteFunctionsUC::getVal($fields, $type);
if(empty($fields))
return;
// add api type
$params = array();
$params["origtype"] = UniteCreatorDialogParam::PARAM_HIDDEN;
$settingsManager->addHiddenInput($name . "_api_type", $type, "API Type", $params);
// add the fields
HelperProviderUC::addSettingsFields($settingsManager, $fields, $name, $condition, true);
}
/**
* init the api integrations
*/
private function init(){
$this->includeServices();
}
/**
* include service files
*/
private function includeServices(){
$services = new UniteServicesUC();
if(GlobalsUnlimitedElements::$enableGoogleAPI === true)
$services->includeGoogleAPI();
if(GlobalsUnlimitedElements::$enableCurrencyAPI === true)
$services->includeExchangeRateAPI();
if(GlobalsUnlimitedElements::$enableWeatherAPI === true)
$services->includeOpenWeatherAPI();
}
/**
* remap legacy params
*/
private function remapLegacyParams($params){
// TODO: Remove in the next major version
$keysMap = array(
"currency_exchange:currency" => self::CURRENCY_EXCHANGE_FIELD_CURRENCY,
"currency_exchange:precision" => self::CURRENCY_EXCHANGE_FIELD_PRECISION,
"currency_exchange:include_currencies" => self::CURRENCY_EXCHANGE_FIELD_INCLUDE_CURRENCIES,
"currency_exchange:cache_time" => self::CURRENCY_EXCHANGE_FIELD_CACHE_TIME,
"google_events:calendar_id" => self::GOOGLE_EVENTS_FIELD_CALENDAR_ID,
"google_events:range" => self::GOOGLE_EVENTS_FIELD_RANGE,
"google_events:order" => self::GOOGLE_EVENTS_FIELD_ORDER,
"google_events:limit" => self::GOOGLE_EVENTS_FIELD_LIMIT,
"google_events:cache_time" => self::GOOGLE_EVENTS_FIELD_CACHE_TIME,
"google_reviews:place_id" => self::GOOGLE_REVIEWS_FIELD_PLACE_ID,
"google_reviews:cache_time" => self::GOOGLE_REVIEWS_FIELD_CACHE_TIME,
"google_reviews:lang" => self::GOOGLE_REVIEWS_FIELD_LANG,
"google_sheets:id" => self::GOOGLE_SHEETS_FIELD_ID,
"google_sheets:sheet_id" => self::GOOGLE_SHEETS_FIELD_SHEET_ID,
"google_sheets:cache_time" => self::GOOGLE_SHEETS_FIELD_CACHE_TIME,
"weather_forecast:country" => self::WEATHER_FORECAST_FIELD_COUNTRY,
"weather_forecast:city" => self::WEATHER_FORECAST_FIELD_CITY,
"weather_forecast:units" => self::WEATHER_FORECAST_FIELD_UNITS,
"weather_forecast:cache_time" => self::WEATHER_FORECAST_FIELD_CACHE_TIME,
"youtube_playlist:id" => self::YOUTUBE_PLAYLIST_FIELD_ID,
"youtube_playlist:order" => self::YOUTUBE_PLAYLIST_FIELD_ORDER,
"youtube_playlist:limit" => self::YOUTUBE_PLAYLIST_FIELD_LIMIT,
"youtube_playlist:cache_time" => self::YOUTUBE_PLAYLIST_FIELD_CACHE_TIME,
);
foreach($keysMap as $legacyKey => $key){
$value = UniteFunctionsUC::getVal($params, $key);
$legacyValue = UniteFunctionsUC::getVal($params, $legacyKey);
$params[$key] = $value === '' ? $legacyValue : $value;
}
return $params;
}
/**
* get the param value
*/
private function getParam($key, $fallback = null, $name = null){
if(!empty($name))
$key = $name."_".$key;
$paramValue = UniteFunctionsUC::getVal($this->params, $key);
if(empty($paramValue))
$paramValue = $fallback;
return $paramValue;
}
/**
* get the param value, otherwise throw an exception
*/
private function getRequiredParam($key, $label = null, $name = null){
$value = $this->getParam($key, null, $name);
if(empty($value) === false)
return $value;
if(empty($label) === true)
$label = $key;
// translators: %s is param name
UniteFunctionsUC::throwError(sprintf(__("%s is required.", "unlimited-elements-for-elementor"), $label));
}
/**
* get the cache time param
*/
private function getCacheTimeParam($key, $default = 10, $name = null){
$time = $this->getParam($key, $default, $name);
$time = intval($time);
$time = max($time, 1); // minimum is 1 minute
$time *= 60; // convert to seconds
return $time;
}
/**
* authorize google service
*/
private function authorizeGoogleService($service){
try{
$service->setAccessToken(UEGoogleAPIHelper::getFreshAccessToken());
}catch(Exception $exception){
$this->authorizeGoogleServiceWithApiKey($service);
}
}
/**
* authorize google service with api key
*/
private function authorizeGoogleServiceWithApiKey($service){
$service->setApiKey(UEGoogleAPIHelper::getApiKey());
}
/**
* has google credentials
*/
private function hasGoogleCredentials(){
try{
$token = UEGoogleAPIHelper::getFreshAccessToken();
$hasCredentials = empty($token) === false;
}catch(Exception $exception){
$key = UEGoogleAPIHelper::getApiKey();
$hasCredentials = empty($key) === false;
}
return $hasCredentials;
}
/**
* validate google api key
*/
private function validateGoogleApiKey(){
$key = UEGoogleAPIHelper::getApiKey();
if(empty($key) === true)
UniteFunctionsUC::throwError(__("Google API key is missing.", "unlimited-elements-for-elementor"));
}
/**
* validate google credentials
*/
private function validateGoogleCredentials(){
$hasCredentials = $this->hasGoogleCredentials();
if($hasCredentials === false)
UniteFunctionsUC::throwError(__("Google credentials are missing.", "unlimited-elements-for-elementor"));
}
/**
* get exchange rate api key
*/
private function getExchangeRateApiKey(){
$key = $this->getRequiredParam(self::SETTINGS_EXCHANGE_RATE_API_KEY, "Exchange Rate API key");
return $key;
}
/**
* get currency exchange settings fields
*/
private function getCurrencyExchangeSettingsFields(){
$fields = array();
$key = HelperProviderCoreUC_EL::getGeneralSetting(self::SETTINGS_EXCHANGE_RATE_API_KEY);
$fields = $this->addEmptyApiKeyField($fields, $key, self::CURRENCY_EXCHANGE_FIELD_EMPTY_API_KEY, "Exchange Rate API");
$fields = array_merge($fields, array(
array(
"id" => self::CURRENCY_EXCHANGE_FIELD_CURRENCY,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Currency Code", "unlimited-elements-for-elementor"),
// translators: %s is page url
"desc" => sprintf(__("Enter the three-letter <a href='%s' target='_blank'>currency code</a>.", "unlimited-elements-for-elementor"), "https://exchangerate-api.com/docs/supported-currencies"),
),
array(
"id" => self::CURRENCY_EXCHANGE_FIELD_PRECISION,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Rate Precision", "unlimited-elements-for-elementor"),
// translators: %1$d is a number, %2$d is a number, %3$d is a number
"desc" => sprintf(__("Optional. You can specify the number of decimals for the rate: from %1\$d to %2\$d. The default value is %3\$d.", "unlimited-elements-for-elementor"), self::CURRENCY_EXCHANGE_MIN_PRECISION, self::CURRENCY_EXCHANGE_MAX_PRECISION, self::CURRENCY_EXCHANGE_DEFAULT_PRECISION),
),
array(
"id" => self::CURRENCY_EXCHANGE_FIELD_INCLUDE_CURRENCIES,
"type" => UniteCreatorDialogParam::PARAM_TEXTAREA,
"text" => __("Include Currencies", "unlimited-elements-for-elementor"),
"desc" => __("Optional. You can specify a comma separated list of currency codes to include, otherwise all currencies will be displayed.", "unlimited-elements-for-elementor"),
),
array(
"id" => self::CURRENCY_EXCHANGE_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::CURRENCY_EXCHANGE_DEFAULT_CACHE_TIME),
"default" => self::CURRENCY_EXCHANGE_DEFAULT_CACHE_TIME,
),
));
return $fields;
}
/**
* get google events settings fields
*/
private function getGoogleEventsSettingsFields(){
$fields = array();
if(GlobalsUnlimitedElements::$enableGoogleCalendarScopes === true)
$fields = $this->addGoogleEmptyCredentialsField($fields, self::GOOGLE_EVENTS_FIELD_EMPTY_CREDENTIALS);
else
$fields = $this->addGoogleEmptyApiKeyField($fields, self::GOOGLE_EVENTS_FIELD_EMPTY_CREDENTIALS);
$fields = array_merge($fields, array(
array(
"id" => self::GOOGLE_EVENTS_FIELD_CALENDAR_ID,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Calendar ID", "unlimited-elements-for-elementor"),
"desc" => __("You can find the calendar ID on a calendar's \"Settings\" page under \"Integrate Calendar\".", "unlimited-elements-for-elementor"),
),
array(
"id" => self::GOOGLE_EVENTS_FIELD_RANGE,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Date Range", "unlimited-elements-for-elementor"),
"options" => array(
self::GOOGLE_EVENTS_RANGE_UPCOMING => __("Upcoming", "unlimited-elements-for-elementor"),
self::GOOGLE_EVENTS_RANGE_TODAY => __("Today's", "unlimited-elements-for-elementor"),
self::GOOGLE_EVENTS_RANGE_TOMORROW => __("Tomorrow's", "unlimited-elements-for-elementor"),
self::GOOGLE_EVENTS_RANGE_WEEK => __("This week", "unlimited-elements-for-elementor"),
self::GOOGLE_EVENTS_RANGE_MONTH => __("This month", "unlimited-elements-for-elementor"),
),
"default" => self::GOOGLE_EVENTS_RANGE_UPCOMING,
),
array(
"id" => self::GOOGLE_EVENTS_FIELD_ORDER,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Order By", "unlimited-elements-for-elementor"),
"options" => array(
self::GOOGLE_EVENTS_ORDER_DATE_DESC => __("Date (newest)", "unlimited-elements-for-elementor"),
self::GOOGLE_EVENTS_ORDER_DATE_ASC => __("Date (oldest)", "unlimited-elements-for-elementor"),
),
"default" => self::GOOGLE_EVENTS_ORDER_DATE_DESC,
),
array(
"id" => self::GOOGLE_EVENTS_FIELD_LIMIT,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Events Limit", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the maximum number of events: from 1 to 2500. The default value is %d.", "unlimited-elements-for-elementor"), self::GOOGLE_EVENTS_DEFAULT_LIMIT),
"default" => self::GOOGLE_EVENTS_DEFAULT_LIMIT,
),
array(
"id" => self::GOOGLE_EVENTS_FIELD_TIMEZONE,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Timezone", "unlimited-elements-for-elementor"),
"desc" => __("Example: Europe/Rome, UTC, -06:30, +08:45. Leave empty for timezone set in wp settings", "unlimited-elements-for-elementor"),
),
array(
"id" => self::GOOGLE_EVENTS_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::GOOGLE_EVENTS_DEFAULT_CACHE_TIME),
"default" => self::GOOGLE_EVENTS_DEFAULT_CACHE_TIME,
),
));
return $fields;
}
/**
* get youtube playlist settings fields
*/
private function getYoutubePlaylistSettingsFields(){
$fields = array();
if(GlobalsUnlimitedElements::$enableGoogleYoutubeScopes === true)
$fields = $this->addGoogleEmptyCredentialsField($fields, self::YOUTUBE_PLAYLIST_FIELD_EMPTY_CREDENTIALS);
else
$fields = $this->addGoogleEmptyApiKeyField($fields, self::YOUTUBE_PLAYLIST_FIELD_EMPTY_CREDENTIALS);
$fields = array_merge($fields, array(
array(
"id" => self::YOUTUBE_PLAYLIST_FIELD_ID,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Playlist ID", "unlimited-elements-for-elementor"),
// translators: %1$s is page url, %2$s is page url
"desc" => sprintf(__("You can find the playlist ID in a YouTube URL: <br />— %1\$s<br />— %2\$s", "unlimited-elements-for-elementor"), "https://youtube.com/playlist?list=<b>[YOUR_PLAYLIST_ID]</b>", "https://youtube.com/watch?v=aBC-123xYz&list=<b>[YOUR_PLAYLIST_ID]</b>"),
),
array(
"id" => self::YOUTUBE_PLAYLIST_FIELD_ORDER,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Order By", "unlimited-elements-for-elementor"),
"options" => array(
self::YOUTUBE_PLAYLIST_ORDER_DEFAULT => __("Default", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_DESC => __("Date added (newest)", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_ASC => __("Date added (oldest)", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_RANDOM => __("Date added (random)", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_DESC => __("Date published (newest)", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_ASC => __("Date published (oldest)", "unlimited-elements-for-elementor"),
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_RANDOM => __("Date published (random)", "unlimited-elements-for-elementor"),
),
"default" => self::YOUTUBE_PLAYLIST_ORDER_DEFAULT,
),
array(
"id" => self::YOUTUBE_PLAYLIST_FIELD_LIMIT,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Videos Limit", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the maximum number of videos: from 1 to 50. The default value is %d.", "unlimited-elements-for-elementor"), self::YOUTUBE_PLAYLIST_DEFAULT_LIMIT),
"default" => self::YOUTUBE_PLAYLIST_DEFAULT_LIMIT,
),
array(
"id" => self::YOUTUBE_PLAYLIST_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::YOUTUBE_PLAYLIST_DEFAULT_CACHE_TIME),
"default" => self::YOUTUBE_PLAYLIST_DEFAULT_CACHE_TIME,
),
));
return $fields;
}
/**
* get currency exchange data
*/
private function getCurrencyExchangeData(){
$data = array();
$currency = $this->getRequiredParam(self::CURRENCY_EXCHANGE_FIELD_CURRENCY, "Currency");
$precision = $this->getParam(self::CURRENCY_EXCHANGE_FIELD_PRECISION, self::CURRENCY_EXCHANGE_DEFAULT_PRECISION);
$includeCurrencies = $this->getParam(self::CURRENCY_EXCHANGE_FIELD_INCLUDE_CURRENCIES, "");
$cacheTime = $this->getCacheTimeParam(self::CURRENCY_EXCHANGE_FIELD_CACHE_TIME, self::CURRENCY_EXCHANGE_DEFAULT_CACHE_TIME);
$precision = intval($precision);
$precision = max($precision, self::CURRENCY_EXCHANGE_MIN_PRECISION);
$precision = min($precision, self::CURRENCY_EXCHANGE_MAX_PRECISION);
$includeCurrencies = strtoupper($includeCurrencies);
$includeCurrencies = explode(",", $includeCurrencies);
$includeCurrencies = array_map("trim", $includeCurrencies);
$includeCurrencies = array_filter($includeCurrencies);
$includeCurrencies = array_unique($includeCurrencies);
$exchangeService = new UEExchangeRateAPIClient($this->getExchangeRateApiKey());
$exchangeService->setCacheTime($cacheTime);
$rates = $exchangeService->getRates($currency);
foreach($rates as $rate){
$code = $rate->getCode();
$symbol = $rate->getSymbol();
$formattedRate = $rate->getRate($precision);
$data[$code] = array(
"id" => $rate->getId(),
"code" => $code,
"name" => $rate->getName(),
"symbol" => $symbol,
"flag" => $rate->getFlagUrl(),
"rate" => $formattedRate,
"value_before" => "$symbol$formattedRate",
"value_after" => "$formattedRate$symbol",
);
}
$filteredData = array();
if(empty($includeCurrencies) === true)
$filteredData = UniteFunctionsUC::assocToArray($data);
foreach($includeCurrencies as $code){
$rate = UniteFunctionsUC::getVal($data, $code);
if(empty($rate) === true)
continue;
$filteredData[] = $rate;
}
$baseCode = strtoupper($currency);
$baseRate = UniteFunctionsUC::getVal($data, $baseCode);
$data = UniteFunctionsUC::assocToArray($data);
$filteredDataJson = UniteFunctionsUC::jsonEncodeForClientSide($filteredData);
$output = array();
$output["base"] = $baseRate;
$output["rates_all"] = $data;
$output["rates_chosen"] = $filteredData;
$output["rates_chosen_json"] = $filteredDataJson;
return $output;
}
/**
* get google events data
*/
private function getGoogleEventsData(){
$data = array();
if(GlobalsUnlimitedElements::$enableGoogleCalendarScopes === true)
$this->validateGoogleCredentials();
else
$this->validateGoogleApiKey();
$calendarId = $this->getRequiredParam(self::GOOGLE_EVENTS_FIELD_CALENDAR_ID, "Calendar ID");
$eventsRange = $this->getParam(self::GOOGLE_EVENTS_FIELD_RANGE);
$eventsRange = $this->getGoogleEventsDatesRange($eventsRange);
$eventsOrder = $this->getParam(self::GOOGLE_EVENTS_FIELD_ORDER);
$eventsLimit = $this->getParam(self::GOOGLE_EVENTS_FIELD_LIMIT, self::GOOGLE_EVENTS_DEFAULT_LIMIT);
$eventsLimit = intval($eventsLimit);
$cacheTime = $this->getCacheTimeParam(self::GOOGLE_EVENTS_FIELD_CACHE_TIME, self::GOOGLE_EVENTS_DEFAULT_CACHE_TIME);
$timezone = $this->getParam(self::GOOGLE_EVENTS_FIELD_TIMEZONE);
$orderFieldMap = array(
self::GOOGLE_EVENTS_ORDER_DATE_ASC => "date",
self::GOOGLE_EVENTS_ORDER_DATE_DESC => "date",
);
$orderDirectionMap = array(
self::GOOGLE_EVENTS_ORDER_DATE_ASC => self::ORDER_DIRECTION_ASC,
self::GOOGLE_EVENTS_ORDER_DATE_DESC => self::ORDER_DIRECTION_DESC,
);
$orderField = isset($orderFieldMap[$eventsOrder]) ? $orderFieldMap[$eventsOrder] : null;
$orderDirection = isset($orderDirectionMap[$eventsOrder]) ? $orderDirectionMap[$eventsOrder] : null;
$calendarService = new UEGoogleAPICalendarService();
$calendarService->setCacheTime($cacheTime);
if(GlobalsUnlimitedElements::$enableGoogleCalendarScopes === true)
$this->authorizeGoogleService($calendarService);
else
$this->authorizeGoogleServiceWithApiKey($calendarService);
$eventsParams = array(
"singleEvents" => "true",
"orderBy" => "startTime",
"maxResults" => $eventsLimit,
);
if(isset($eventsRange["start"]) === true)
$eventsParams["timeMin"] = $eventsRange["start"];
if(isset($eventsRange["end"]) === true)
$eventsParams["timeMax"] = $eventsRange["end"];
$events = $calendarService->getEvents($calendarId, $eventsParams, $timezone);
foreach($events as $event){
$orderValue = ($orderField === "date")
? $event->getStartDate(self::FORMAT_MYSQL_DATETIME)
: null;
$data[] = array(
"id" => $event->getId(),
"start_date" => $event->getStartDate(self::FORMAT_DATETIME),
"end_date" => $event->getEndDate(self::FORMAT_DATETIME),
"title" => $event->getTitle(),
"description" => $event->getDescription(true),
"location" => $event->getLocation(),
"link" => $event->getUrl(),
self::ORDER_FIELD => $orderValue,
);
}
$data = $this->sortData($data, $orderDirection);
return $data;
}
/**
* get google events dates range
*/
private function getGoogleEventsDatesRange($key){
$currentTime = current_time("timestamp");
$startTime = null;
$endTime = null;
switch($key){
case self::GOOGLE_EVENTS_RANGE_UPCOMING:
$startTime = strtotime("now", $currentTime);
break;
case self::GOOGLE_EVENTS_RANGE_TODAY:
$startTime = strtotime("today", $currentTime);
$endTime = strtotime("tomorrow", $startTime);
break;
case self::GOOGLE_EVENTS_RANGE_TOMORROW:
$startTime = strtotime("tomorrow", $currentTime);
$endTime = strtotime("tomorrow", $startTime);
break;
case self::GOOGLE_EVENTS_RANGE_WEEK:
$startTime = strtotime("this week midnight", $currentTime);
$endTime = strtotime("next week midnight", $currentTime);
break;
case self::GOOGLE_EVENTS_RANGE_MONTH:
$startTime = strtotime("first day of this month midnight", $currentTime);
$endTime = strtotime("first day of next month midnight", $currentTime);
break;
}
$range = array(
"start" => $startTime ? uelm_date("c", $startTime) : null,
"end" => $endTime ? uelm_date("c", $endTime) : null,
);
return $range;
}
private function _________GOOGLE_REVIEWS_________(){}
/**
* get serp api key
*/
private function getSerpAPIKey(){
if(GlobalsUnlimitedElements::$enableSerpAPI == false)
return(null);
$serpKey = HelperProviderCoreUC_EL::getGeneralSetting("serpapi_key");
$serpKey = trim($serpKey);
return($serpKey);
}
/**
* is serp api enabled
*/
private function isGoogleReviewsSerpEnabled(){
$apiKey = $this->getSerpAPIKey();
if(!empty($apiKey))
return(true);
return(false);
}
/**
* get official google reviews
*/
private function getGoogleReviewsData_official($placeId){
$this->validateGoogleApiKey();
$cacheTime = $this->getCacheTimeParam(self::GOOGLE_REVIEWS_FIELD_CACHE_TIME, self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME);
$placesService = new UEGoogleAPIPlacesService();
$placesService->setCacheTime($cacheTime);
$this->authorizeGoogleServiceWithApiKey($placesService);
$reviewsLanguage = $this->getParam(self::GOOGLE_REVIEWS_FIELD_LANG);
$placeParams = array(
"fields" => "reviews",
"reviews_sort" => "newest",
"lang" => $reviewsLanguage,
);
$place = $placesService->getDetails($placeId, $placeParams, $this->googleReviewsShowDebug);
return($place);
}
/**
* get google reviews from serp service
*/
private function getGoogleReviewsData_serp($placeId){
$placesService = new UEGoogleAPIPlacesService();
$placeParams = array();
$apiKey = $this->getSerpAPIKey();
$reviewsLanguage = $this->getParam(self::GOOGLE_REVIEWS_FIELD_LANG);
$placeParams["hl"] = $reviewsLanguage;
$reviewsSortBy = $this->getParam(self::GOOGLE_REVIEWS_SORT_BY);
$placeParams["sort_by"] = $reviewsSortBy;
//get cache time option and convert to seconds
$cacheTimeOption = $this->getParam(self::GOOGLE_REVIEWS_SERP_CACHE_TIME, "week");
$cacheTime = self::GOOGLE_REVIEWS_CACHE_TIME_WEEK; // default: 1 week in seconds
switch($cacheTimeOption){
case "day":
$cacheTime = self::GOOGLE_REVIEWS_CACHE_TIME_DAY;
break;
case "week":
$cacheTime = self::GOOGLE_REVIEWS_CACHE_TIME_WEEK;
break;
case "month":
$cacheTime = self::GOOGLE_REVIEWS_CACHE_TIME_MONTH;
break;
}
$place = $placesService->getDetailsSerp($placeId, $apiKey, $placeParams, $this->googleReviewsShowDebug, $cacheTime);
return($place);
}
/**
* get google reviews data
*/
private function getGoogleReviewsData(){
$data = array();
$showDebug = $this->getParam(self::GOOGLE_REVIEWS_FIELD_SHOW_DEBUG);
if($showDebug == true)
$this->googleReviewsShowDebug = true;
try{
$serpAPIKey = $this->getSerpAPIKey();
$isSerp = !empty($serpAPIKey);
if($this->googleReviewsShowDebug == true){
$message = "Reviews API Debug";
if($isSerp == true)
$message .= "<br> Output google reviews data using serp.com API";
else
$message .= "<br> Output google reviews data using Official Google API";
echo HelperHtmlUC::getDebugWarningMessageHtml($message);
}
$placeId = $this->getRequiredParam(self::GOOGLE_REVIEWS_FIELD_PLACE_ID, "Place ID");
if($isSerp == false)
$place = $this->getGoogleReviewsData_official($placeId);
else
$place = $this->getGoogleReviewsData_serp($placeId);
//add api source
$apiSourceText = ($isSerp == true)?"serp":"official";
$data["reviews_api_type"] = $apiSourceText;
//add place info
$arrInfo = $place->getPlaceInfo();
if(!empty($arrInfo))
$data["place_info"] = $arrInfo;
//add search link
if($isSerp == true){
$arrMetaData = $place->getMetaData();
$data["api_search_link_for_debug"] = UniteFunctionsUC::getVal($arrMetaData, "json_endpoint");
$data["api_search_html_link_for_debug"] = UniteFunctionsUC::getVal($arrMetaData, "prettify_html_file");
}
//add reviews
$arrReviews = $place->getReviews();
$arrReviewsOutput = array();
foreach($arrReviews as $review){
if($isSerp == true)
$review->setSerpSource();
$arrReviewsOutput[] = array(
"id" => $review->getId(),
"date" => $review->getDate(self::FORMAT_DATETIME),
"time_ago" => $review->getTimeAgoText(),
"text" => $review->getText(true),
"rating" => $review->getRating(),
"author_name" => $review->getAuthorName(),
"author_photo" => $review->getAuthorPhotoUrl(),
);
}
$data["reviews"] = $arrReviewsOutput;
}catch(Exception $e){
if($this->googleReviewsShowDebug == true){
$message = $e->getMessage();
echo HelperHtmlUC::getErrorMessageHtml($message,"",true);
}
throw $e;
}
return $data;
}
/**
* get google reviews settings fields
*/
private function getGoogleReviewsSettingsFields($isSingle = false){
$fields = array();
$fields = $this->addGoogleEmptyApiKeyField($fields, self::GOOGLE_REVIEWS_FIELD_EMPTY_API_KEY);
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_FIELD_PLACE_ID,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Place ID", "unlimited-elements-for-elementor"),
// translators: %s is page url
"desc" => sprintf(__("You can find the place ID by using <a href='%s' target='_blank'>Place ID Finder</a>.", "unlimited-elements-for-elementor"), "https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder"),
"default"=>"ChIJmeeg4mbcQUcRIOHu3gDTJDs"
);
$isSerpEnabled = $this->isGoogleReviewsSerpEnabled();
if($isSerpEnabled == false)
$text = sprintf(__("To get more then 5 reviews, enter %s key in general settings", "unlimited-elements-for-elementor"), "<a href='https://serpapi.com' target='_blank'>serpapi.com</a>");
else
$text = sprintf(__("Fetching google reviews using %s service.", "unlimited-elements-for-elementor"), "<a href='https://serpapi.com' target='_blank'>serpapi.com</a>");
//if there is no option - no need for text
if(GlobalsUnlimitedElements::$enableSerpAPI == true){
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_FIELD_API_TEXT,
"type" => UniteCreatorDialogParam::PARAM_STATIC_TEXT,
"text" => $text,
);
}
//for serp api the cache is configurable
if($isSerpEnabled == false){
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME),
"default" => self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME,
);
}else{
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_SERP_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
"desc" => __("Select how often the reviews should be refreshed.", "unlimited-elements-for-elementor"),
"options" => array(
"day" => __("Once a day", "unlimited-elements-for-elementor"),
"week" => __("Once a week", "unlimited-elements-for-elementor"),
"month" => __("Once a month", "unlimited-elements-for-elementor"),
),
"default" => "week"
);
}
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_FIELD_LANG,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Language Code", "unlimited-elements-for-elementor"),
"desc" => __("Optional. Specify a language code. Example: de and google will translate the review.", "unlimited-elements-for-elementor"),
"default" => "",
);
if($isSerpEnabled == true){
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_SORT_BY,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Sort By", "unlimited-elements-for-elementor"),
"options" => array(
"qualityScore"=>"Most Relevant",
"newestFirst"=>"Newest",
"ratingHigh"=>"Highest Rating",
"ratingLow"=>"Lowest Rating",
),
"default" => "qualityScore"
);
}
//add fields for single mode
if($isSingle == true){
$fields[] = array(
"id" => "google_reviews_hr_beore_debug",
"type" => UniteCreatorDialogParam::PARAM_HR,
);
$fields[] = array(
"id" => self::GOOGLE_REVIEWS_FIELD_SHOW_DEBUG,
"type" => UniteCreatorDialogParam::PARAM_RADIOBOOLEAN,
"text" => __("Show Debug", "unlimited-elements-for-elementor"),
);
}
return $fields;
}
private function _________GOOGLE_SHEETS_________(){}
/**
* get google sheets settings fields
*/
public function getGoogleSheetsSettingsFields(){
$fields = array();
$fields = $this->addGoogleEmptyCredentialsField($fields, self::GOOGLE_SHEETS_FIELD_EMPTY_CREDENTIALS);
$fields = array_merge($fields, array(
array(
"id" => self::GOOGLE_SHEETS_FIELD_ID,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Spreadsheet ID", "unlimited-elements-for-elementor"),
// translators: %s is a string
"desc" => sprintf(__("You can find the spreadsheet ID in a Google Sheets URL: %s", "unlimited-elements-for-elementor"), "https://docs.google.com/spreadsheets/d/<b>[YOUR_SPREADSHEET_ID]</b>/edit#gid=0"),
),
array(
"id" => self::GOOGLE_SHEETS_FIELD_SHEET_ID,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Sheet ID", "unlimited-elements-for-elementor"),
// translators: %s is page url
"desc" => sprintf(__("Optional. You can find the sheet ID in a Google Sheets URL: %s", "unlimited-elements-for-elementor"), "https://docs.google.com/spreadsheets/d/aBC-123_xYz/edit#gid=<b>[YOUR_SHEET_ID]</b>"),
),
array(
"id" => self::GOOGLE_SHEETS_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::GOOGLE_SHEETS_DEFAULT_CACHE_TIME),
"default" => self::GOOGLE_SHEETS_DEFAULT_CACHE_TIME,
),
array(
"id" => self::GOOGLE_SHEETS_EXCLUDE_FIRST_ROW,
"type" => UniteCreatorDialogParam::PARAM_RADIOBOOLEAN,
"text" => __("Exclude First Row", "unlimited-elements-for-elementor"),
// translators: %s is a string
"desc" => __("You can exclude first row from Google Sheet Table", "unlimited-elements-for-elementor"),
),
));
return $fields;
}
/**
* get google sheets data
*/
public function getGoogleSheetsData($params = null, $name = null){
if(!empty($params))
$this->params = $params;
$data = array();
$this->validateGoogleCredentials();
$spreadsheetId = $this->getRequiredParam(self::GOOGLE_SHEETS_FIELD_ID, "Spreadsheet ID", $name);
$spreadsheetId = $this->getSpreadsheetIdByUrl($spreadsheetId);
$sheetId = $this->getParam(self::GOOGLE_SHEETS_FIELD_SHEET_ID, 0, $name);
$sheetId = $this->getSheetIdByUrl($sheetId);
$sheetId = intval($sheetId);
$cacheTime = $this->getCacheTimeParam(self::GOOGLE_SHEETS_FIELD_CACHE_TIME, self::GOOGLE_SHEETS_DEFAULT_CACHE_TIME,$name);
$sheetsService = new UEGoogleAPISheetsService();
$sheetsService->setCacheTime($cacheTime);
$this->authorizeGoogleService($sheetsService);
// get sheet title for the range
$spreadsheet = $sheetsService->getSpreadsheet($spreadsheetId);
$range = null;
foreach($spreadsheet->getSheets() as $sheet){
if($sheet->getId() === $sheetId){
$range = $sheet->getTitle();
break;
}
}
// get spreadsheet values
/*$spreadsheet = $sheetsService->getSpreadsheetValues($spreadsheetId, $range);
$values = $spreadsheet->getValues();*/
$spreadsheet = $sheetsService->getSpreadsheetValuesWithLinksAndAttributes($spreadsheetId, $range);
$values = $spreadsheet->getValuesWithLinksAndAttributes();
$headers = $values[0]; // extract first row as headers
$excludeFirstRow = $this->getParam(self::GOOGLE_SHEETS_EXCLUDE_FIRST_ROW,0, $name);
if($excludeFirstRow == true)
unset($values[0]);
foreach($values as $rowIndex => $row){
$attributes = array("id" => $rowIndex + 1);
foreach($headers as $columnIndex => $header){
if(empty($row[$columnIndex]))
$attributes[$header] = ' ';
else
$attributes[$header] = $row[$columnIndex];
}
$data[] = $attributes;
}
return $data;
}
/**
* get spreadsheetId by url
*/
private function getSpreadsheetIdByUrl($spreadsheetId) {
$pattern = '~spreadsheets/d/([^/]+)~';
if (preg_match($pattern, $spreadsheetId, $matches)) {
$spreadsheetId = $matches[1];
return $spreadsheetId;
}
return $spreadsheetId;
}
/**
* get sheetId by url
*/
private function getSheetIdByUrl($sheetId) {
$pattern = '/#gid=([^&]+)/';
if (preg_match($pattern, $sheetId, $matches)) {
$sheetId = $matches[1];
return $sheetId;
}
return $sheetId;
}
private function _________WEATHER_________(){}
/**
* get open weather api key
*/
private function getOpenWeatherApiKey(){
$key = $this->getRequiredParam(self::SETTINGS_OPEN_WEATHER_API_KEY, "OpenWeather API key");
return $key;
}
/**
* get weather forecast settings fields
*/
private function getWeatherForecastSettingsFields(){
$fields = array();
$key = HelperProviderCoreUC_EL::getGeneralSetting(self::SETTINGS_OPEN_WEATHER_API_KEY);
$fields = $this->addEmptyApiKeyField($fields, $key, self::WEATHER_FORECAST_FIELD_EMPTY_API_KEY, "OpenWeather API");
$fields = array_merge($fields, array(
array(
"id" => self::WEATHER_FORECAST_FIELD_COUNTRY,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Country Code", "unlimited-elements-for-elementor"),
// translators: %s is page url
"desc" => sprintf(__("Specify the two-letter <a href='%s' target='_blank'>country code</a>.", "unlimited-elements-for-elementor"), "https://en.wikipedia.org/wiki/ISO_3166-2#Current_codes"),
"default" => "GB",
),
array(
"id" => self::WEATHER_FORECAST_FIELD_CITY,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("City Name", "unlimited-elements-for-elementor"),
"default" => "London",
),
array(
"id" => self::WEATHER_FORECAST_FIELD_UNITS,
"type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
"text" => __("Units", "unlimited-elements-for-elementor"),
"options" => array(
self::WEATHER_FORECAST_UNITS_METRIC => __("Metric", "unlimited-elements-for-elementor"),
self::WEATHER_FORECAST_UNITS_IMPERIAL => __("Imperial", "unlimited-elements-for-elementor"),
),
"default" => self::WEATHER_FORECAST_UNITS_METRIC,
),
array(
"id" => self::WEATHER_FORECAST_FIELD_LOCALE,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Language Code", "unlimited-elements-for-elementor"),
"default" => "",
"desc" => __("2 digits of language code. for example: 'fr' (french) for the list of all codes: <a href='https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes'>Press Here</a>. Leave empty for auto select. ", "unlimited-elements-for-elementor"),
),
array(
"id" => self::WEATHER_FORECAST_FIELD_CACHE_TIME,
"type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
"text" => __("Cache Time", "unlimited-elements-for-elementor"),
// translators: %d is a number
"desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::CURRENCY_EXCHANGE_DEFAULT_CACHE_TIME),
"default" => self::WEATHER_FORECAST_DEFAULT_CACHE_TIME,
),
));
return $fields;
}
/**
* get weather forecast data
*/
private function getWeatherForecastData(){
$country = $this->getRequiredParam(self::WEATHER_FORECAST_FIELD_COUNTRY, "Country");
$city = $this->getRequiredParam(self::WEATHER_FORECAST_FIELD_CITY, "City");
$units = $this->getRequiredParam(self::WEATHER_FORECAST_FIELD_UNITS, "Units");
$cacheTime = $this->getCacheTimeParam(self::WEATHER_FORECAST_FIELD_CACHE_TIME, self::WEATHER_FORECAST_DEFAULT_CACHE_TIME);
$locale = $this->getParam(self::WEATHER_FORECAST_FIELD_LOCALE, "");
$weatherService = new UEOpenWeatherAPIClient($this->getOpenWeatherApiKey());
$weatherService->setCacheTime($cacheTime);
$forecasts = $weatherService->getForecasts($country, $city, $units, $locale);
$currentForecast = UniteFunctionsUC::getVal($forecasts, "current");
$hourlyForecasts = UniteFunctionsUC::getVal($forecasts, "hourly");
$dailyForecasts = UniteFunctionsUC::getVal($forecasts, "daily");
$data = array(
"current" => $this->getWeatherForecastCurrentItem($currentForecast),
"hourly" => $this->getWeatherForecastHourlyItems($hourlyForecasts),
"daily" => $this->getWeatherForecastDailyItems($dailyForecasts),
);
return $data;
}
/**
* get weather forecasts basic item
*/
private function getWeatherForecastBasicItem($forecast){
$item = array(
"id" => $forecast->getId(),
"date" => $forecast->getDate(self::FORMAT_MYSQL_DATETIME),
"dow_full" => $forecast->getDate("l"),
"dow_short" => $forecast->getDate("D"),
"state" => $forecast->getState(),
"description" => $forecast->getDescription(),
"icon_name" => $forecast->getIconName(),
"icon_url" => $forecast->getIconUrl(),
"wind_speed" => $forecast->getWindSpeed(),
"wind_degree" => $forecast->getWindDegrees(),
"wind_gust" => $forecast->getWindGust(),
"pressure" => $forecast->getPressure(),
"humidity" => $forecast->getHumidity(),
"cloudiness" => $forecast->getCloudiness(),
"rain" => $forecast->getRain(),
"snow" => $forecast->getSnow(),
"uvi" => $forecast->getUvi(),
);
return $item;
}
/**
* get weather forecasts sun time item
*/
private function getWeatherForecastSunTimeItem($forecast){
$item = array(
"sunrise" => $forecast->getSunrise(),
"sunset" => $forecast->getSunset(),
);
return $item;
}
/**
* get weather forecasts inline temperature item
*/
private function getWeatherForecastInlineTemperatureItem($forecast){
$item = array(
"temp" => $forecast->getTemperature(),
"feels_like" => $forecast->getFeelsLike(),
);
return $item;
}
/**
* get weather forecast current item
*/
private function getWeatherForecastCurrentItem($forecast){
$item = array_merge(
$this->getWeatherForecastBasicItem($forecast),
$this->getWeatherForecastSunTimeItem($forecast),
$this->getWeatherForecastInlineTemperatureItem($forecast)
);
return $item;
}
/**
* get weather forecasts hourly items
*/
private function getWeatherForecastHourlyItems($forecasts){
$items = array();
foreach($forecasts as $forecast){
$extra = array(
"date_hours" => $forecast->getDate("H:00"),
);
$items[] = array_merge(
$this->getWeatherForecastBasicItem($forecast),
$this->getWeatherForecastInlineTemperatureItem($forecast),
$extra
);
}
return $items;
}
/**
* get weather forecasts daily items
*/
private function getWeatherForecastDailyItems($forecasts){
$items = array();
foreach($forecasts as $forecast){
$items[] = array_merge(
$this->getWeatherForecastBasicItem($forecast),
$this->getWeatherForecastSunTimeItem($forecast),
array(
"temp_min" => $forecast->getMinTemperature(),
"temp_max" => $forecast->getMaxTemperature(),
"temp_morning" => $forecast->getMorningTemperature(),
"temp_day" => $forecast->getDayTemperature(),
"temp_evening" => $forecast->getEveningTemperature(),
"temp_night" => $forecast->getNightTemperature(),
"feels_like_morning" => $forecast->getMorningFeelsLike(),
"feels_like_day" => $forecast->getDayFeelsLike(),
"feels_like_evening" => $forecast->getEveningFeelsLike(),
"feels_like_night" => $forecast->getNightFeelsLike(),
)
);
}
return $items;
}
private function _________OTHERS_________(){}
/**
* get youtube playlist data
*/
private function getYoutubePlaylistData(){
$data = array();
if(GlobalsUnlimitedElements::$enableGoogleYoutubeScopes === true)
$this->validateGoogleCredentials();
else
$this->validateGoogleApiKey();
$playlistId = $this->getRequiredParam(self::YOUTUBE_PLAYLIST_FIELD_ID, "Playlist ID");
$itemsOrder = $this->getParam(self::YOUTUBE_PLAYLIST_FIELD_ORDER);
$itemsLimit = $this->getParam(self::YOUTUBE_PLAYLIST_FIELD_LIMIT, self::YOUTUBE_PLAYLIST_DEFAULT_LIMIT);
$itemsLimit = intval($itemsLimit);
$cacheTime = $this->getCacheTimeParam(self::YOUTUBE_PLAYLIST_FIELD_CACHE_TIME, self::YOUTUBE_PLAYLIST_DEFAULT_CACHE_TIME);
$orderFieldMap = array(
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_ASC => "date",
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_DESC => "date",
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_RANDOM => "date",
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_ASC => "video_date",
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_DESC => "video_date",
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_RANDOM => "video_date",
);
$orderDirectionMap = array(
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_ASC => self::ORDER_DIRECTION_ASC,
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_DESC => self::ORDER_DIRECTION_DESC,
self::YOUTUBE_PLAYLIST_ORDER_DATE_ADDED_RANDOM => self::ORDER_DIRECTION_RANDOM,
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_ASC => self::ORDER_DIRECTION_ASC,
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_DESC => self::ORDER_DIRECTION_DESC,
self::YOUTUBE_PLAYLIST_ORDER_DATE_PUBLISHED_RANDOM => self::ORDER_DIRECTION_RANDOM,
);
$orderField = isset($orderFieldMap[$itemsOrder]) ? $orderFieldMap[$itemsOrder] : null;
$orderDirection = isset($orderDirectionMap[$itemsOrder]) ? $orderDirectionMap[$itemsOrder] : null;
$youtubeService = new UEGoogleAPIYouTubeService();
$youtubeService->setCacheTime($cacheTime);
if(GlobalsUnlimitedElements::$enableGoogleYoutubeScopes === true)
$this->authorizeGoogleService($youtubeService);
else
$this->authorizeGoogleServiceWithApiKey($youtubeService);
$items = $youtubeService->getPlaylistItems($playlistId, array("maxResults" => $itemsLimit));
foreach($items as $item){
$orderValue = ($orderField === "date")
? $item->getDate(self::FORMAT_MYSQL_DATETIME)
: $item->getVideoDate(self::FORMAT_MYSQL_DATETIME);
$data[] = array(
"id" => $item->getId(),
"date" => $item->getDate(self::FORMAT_DATETIME),
"title" => $item->getTitle(),
"description" => $item->getDescription(true),
"image" => $item->getImageUrl(UEGoogleAPIPlaylistItem::IMAGE_SIZE_MAX),
"video_id" => $item->getVideoId(),
"video_date" => $item->getVideoDate(self::FORMAT_DATETIME),
"video_link" => $item->getVideoUrl(),
self::ORDER_FIELD => $orderValue,
);
}
$data = $this->sortData($data, $orderDirection);
return $data;
}
/**
* sort the data
*/
private function sortData($data, $direction){
$field = self::ORDER_FIELD;
usort($data, function($a, $b) use ($field, $direction){
if(isset($a[$field]) === false || isset($b[$field]) === false)
return 0;
if($a[$field] == $b[$field])
return 0;
switch($direction){
case self::ORDER_DIRECTION_RANDOM:
// phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand
$results = array(mt_rand(-1, 1), mt_rand(-1, 1));
break;
case self::ORDER_DIRECTION_DESC:
$results = array(1, -1);
break;
default: // asc
$results = array(-1, 1);
break;
}
if(is_numeric($a[$field]) && is_numeric($b[$field]))
return ($a[$field] < $b[$field]) ? $results[0] : $results[1];
return (strcmp($a[$field], $b[$field]) <= 0) ? $results[0] : $results[1];
});
foreach($data as &$values){
unset($values[$field]);
}
return $data;
}
/**
* add empty api key field
*/
private function addEmptyApiKeyField($fields, $key, $id, $name){
if(empty($key) === true){
$fields[] = array(
"id" => $id,
"type" => UniteCreatorDialogParam::PARAM_STATIC_TEXT,
// translators: %s is key name
"text" => sprintf(__("%s key is missing. Please add the key in the \"General Settings > Integrations\".", "unlimited-elements-for-elementor"), $name),
);
}
return $fields;
}
/**
* add google empty api key field
*/
private function addGoogleEmptyApiKeyField($fields, $id){
$key = UEGoogleAPIHelper::getApiKey();
$fields = $this->addEmptyApiKeyField($fields, $key, $id, "Google API");
return $fields;
}
/**
* add google empty credentials field
*/
private function addGoogleEmptyCredentialsField($fields, $id){
$hasCredentials = $this->hasGoogleCredentials();
if($hasCredentials === false){
$fields[] = array(
"id" => $id,
"type" => UniteCreatorDialogParam::PARAM_STATIC_TEXT,
"text" => __("Google credentials are missing. Please connect to Google or add an API key in the \"General Settings > Integrations\".", "unlimited-elements-for-elementor"),
);
}
return $fields;
}
/**
* output google reviews refresh button
*/
private function outputGoogleReviewsRefreshButton(){
// Check if user is admin
if(!current_user_can('manage_options'))
return;
$placeId = $this->getParam(self::GOOGLE_REVIEWS_FIELD_PLACE_ID);
if(empty($placeId))
return;
$ajaxUrl = admin_url('admin-ajax.php');
$nonce = wp_create_nonce('uc_refresh_google_reviews');
$widgetID = "uc_google_reviews_" . md5($placeId);
$html = '<div class="uc-google-reviews-refresh-wrapper" style="margin: 10px 0; padding: 10px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px;">';
$html .= '<button type="button" class="uc-google-reviews-refresh-btn" ';
$html .= 'data-widget-id="' . esc_attr($widgetID) . '" ';
$html .= 'data-place-id="' . esc_attr($placeId) . '" ';
$html .= 'data-nonce="' . esc_attr($nonce) . '" ';
$html .= 'data-ajax-url="' . esc_attr($ajaxUrl) . '" ';
$html .= 'style="padding: 8px 16px; background: #0073aa; color: #fff; border: none; border-radius: 3px; cursor: pointer; font-size: 14px;">';
$html .= __('Manual Refresh Reviews', 'unlimited-elements-for-elementor');
$html .= '</button>';
$html .= '<span class="uc-google-reviews-refresh-status" style="margin-left: 10px; display: none;"></span>';
$html .= '</div>';
echo $html;
}
}