Admin
2 months ago
Builder
2 months ago
Customizer
2 months ago
Exceptions
2 months ago
Helpers
2 months ago
Integrations
2 months ago
Migrations
2 months ago
ReviewAlerts
2 months ago
Services
2 months ago
Settings
2 months ago
Support
2 months ago
Traits
2 months ago
Utils
2 months ago
AuthorizationStatusCheck.php
2 months ago
BusinessDataCache.php
2 months ago
Clear_Cache.php
2 months ago
Container.php
2 months ago
DisplayElements.php
2 months ago
Email_Notification.php
2 months ago
Error_Reporter.php
2 months ago
Feed.php
2 months ago
FeedCache.php
2 months ago
FeedCacheUpdater.php
2 months ago
FeedDisplay.php
2 months ago
Feed_Locator.php
2 months ago
Parser.php
2 months ago
PostAggregator.php
2 months ago
RemoteRequest.php
2 months ago
SBR_Education.php
2 months ago
SBR_Settings.php
2 months ago
ServiceContainer.php
2 months ago
SinglePostCache.php
2 months ago
TemplateRenderer.php
2 months ago
Tooltip_Wizard.php
2 months ago
Util.php
2 months ago
Util.php
1672 lines
| 1 | <?php |
| 2 | |
| 3 | // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
| 4 | // Note: Table name interpolation is safe (uses internal constants, not user input). |
| 5 | |
| 6 | namespace SmashBalloon\Reviews\Common; |
| 7 | |
| 8 | use SmashBalloon\Reviews\Common\Builder\SBR_Sources; |
| 9 | use SmashBalloon\Reviews\Common\Customizer\DB; |
| 10 | use SmashBalloon\Reviews\Common\Helpers\SBR_Error_Handler; |
| 11 | use SmashBalloon\Reviews\Pro\Integrations\Providers\EDD; |
| 12 | |
| 13 | class Util |
| 14 | { |
| 15 | public static function isProduction() |
| 16 | { |
| 17 | return SBR_PRODUCTION; |
| 18 | } |
| 19 | |
| 20 | public static function UTMCampaign() |
| 21 | { |
| 22 | return ''; |
| 23 | } |
| 24 | |
| 25 | /** |
| 26 | * Get feature flags from config file |
| 27 | * |
| 28 | * @return array |
| 29 | */ |
| 30 | public static function get_feature_flags() |
| 31 | { |
| 32 | $config_file = SBR_PLUGIN_DIR . 'config/feature-flags.php'; |
| 33 | if (file_exists($config_file)) { |
| 34 | return include $config_file; |
| 35 | } |
| 36 | return []; |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * Check if a provider is disabled via feature flags |
| 41 | * |
| 42 | * @param string $provider_type Provider type to check |
| 43 | * @return bool |
| 44 | */ |
| 45 | public static function is_provider_disabled($provider_type) |
| 46 | { |
| 47 | $flags = self::get_feature_flags(); |
| 48 | $disabled = isset($flags['disabled_providers']) ? $flags['disabled_providers'] : []; |
| 49 | return in_array($provider_type, $disabled, true); |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Resolve EDD's pluginRequired / pluginRequiredMessage for the customizer |
| 54 | * provider tile. Strict: in Pro the gate requires both EDD core AND the |
| 55 | * EDD Reviews extension — otherwise the modal would let users add a source |
| 56 | * the integration can't actually capture new reviews for. |
| 57 | * |
| 58 | * Free builds may not ship class/Pro/Integrations/Providers/EDD.php, so |
| 59 | * fall back to the prior core-only check there. Free never reaches this |
| 60 | * tile in the disabled-from-extension state anyway (EDD shows as an |
| 61 | * upsell, not a regular provider), but the fallback keeps parity with |
| 62 | * pre-existing behavior. |
| 63 | * |
| 64 | * @return array Two-key map: pluginRequired (bool), pluginRequiredMessage (string) |
| 65 | */ |
| 66 | private static function get_edd_provider_status() |
| 67 | { |
| 68 | if (class_exists(EDD::class)) { |
| 69 | return [ |
| 70 | 'pluginRequired' => ! EDD::is_active_static(), |
| 71 | 'pluginRequiredMessage' => EDD::plugin_required_message(), |
| 72 | ]; |
| 73 | } |
| 74 | |
| 75 | return [ |
| 76 | 'pluginRequired' => ! ( class_exists('Easy_Digital_Downloads') || defined('EDD_VERSION') ), |
| 77 | 'pluginRequiredMessage' => __('Enable Easy Digital Downloads plugin to use it as a source', 'reviews-feed'), |
| 78 | ]; |
| 79 | } |
| 80 | |
| 81 | public static function get_providers() |
| 82 | { |
| 83 | $campaign = self::sbr_is_pro() ? 'reviews-pro' : 'reviews-free'; |
| 84 | |
| 85 | $providers = [ |
| 86 | [ |
| 87 | 'type' => 'google', |
| 88 | 'name' => 'Google', |
| 89 | 'heading' => __('Place ID', 'reviews-feed'), |
| 90 | 'placeholder' => __('Enter Place ID', 'reviews-feed'), |
| 91 | 'docLink' => 'https://smashballoon.com/doc/creating-a-google-api-key/?utm_campaign=' . $campaign . '&utm_source=settings&utm_medium=docs' |
| 92 | ], |
| 93 | [ |
| 94 | 'type' => 'facebook', |
| 95 | 'name' => 'Facebook' |
| 96 | ], |
| 97 | [ |
| 98 | 'type' => 'tripadvisor', |
| 99 | 'name' => 'TripAdvisor', |
| 100 | 'heading' => __('Page URL', 'reviews-feed'), |
| 101 | 'placeholder' => __('https://tripadvisor.com/...', 'reviews-feed'), |
| 102 | 'apiKey' => true, |
| 103 | 'mandatoryApiKey' => true, |
| 104 | 'docLink' => 'https://smashballoon.com/doc/creating-a-tripadvisor-api-key/?utm_campaign=' . $campaign . '&utm_source=settings&utm_medium=docs' |
| 105 | ], |
| 106 | [ |
| 107 | 'type' => 'yelp', |
| 108 | 'name' => 'Yelp', |
| 109 | 'heading' => __('Page URL', 'reviews-feed'), |
| 110 | 'placeholder' => __('https://yelp.com/...', 'reviews-feed'), |
| 111 | 'docLink' => 'https://smashballoon.com/doc/creating-a-yelp-api-key/?utm_campaign=' . $campaign . '&utm_source=settings&utm_medium=docs' |
| 112 | ], |
| 113 | [ |
| 114 | 'type' => 'trustpilot', |
| 115 | 'name' => 'TrustPilot', |
| 116 | 'heading' => __('Page URL', 'reviews-feed'), |
| 117 | 'placeholder' => __('https://trustpilot.com/review/...', 'reviews-feed'), |
| 118 | 'onlyDetails' => true |
| 119 | ], |
| 120 | [ |
| 121 | 'type' => 'wordpress.org', |
| 122 | 'name' => 'WordPress.org', |
| 123 | 'heading' => __('Page URL', 'reviews-feed'), |
| 124 | 'placeholder' => __('https://wordpress.org/...', 'reviews-feed'), |
| 125 | 'onlyDetails' => true |
| 126 | ], |
| 127 | [ |
| 128 | 'type' => 'woocommerce', |
| 129 | 'name' => 'WooCommerce', |
| 130 | 'heading' => __('Product', 'reviews-feed'), |
| 131 | 'placeholder' => __('Select a product', 'reviews-feed'), |
| 132 | 'onlyDetails' => true, |
| 133 | 'isLocal' => true, |
| 134 | 'pluginRequired' => ! ( class_exists('WooCommerce') || function_exists('WC') ), |
| 135 | 'pluginRequiredMessage' => __('Enable WooCommerce plugin to use it as a source', 'reviews-feed'), |
| 136 | ], |
| 137 | array_merge( |
| 138 | [ |
| 139 | 'type' => 'edd', |
| 140 | 'name' => 'Easy Digital Downloads', |
| 141 | 'heading' => __('Download', 'reviews-feed'), |
| 142 | 'placeholder' => __('Select a download', 'reviews-feed'), |
| 143 | 'onlyDetails' => true, |
| 144 | 'isLocal' => true, |
| 145 | ], |
| 146 | self::get_edd_provider_status() |
| 147 | ), |
| 148 | [ |
| 149 | 'type' => 'airbnb', |
| 150 | 'name' => 'Airbnb', |
| 151 | 'heading' => __('Listing URL', 'reviews-feed'), |
| 152 | 'placeholder' => __('https://www.airbnb.com/rooms/...', 'reviews-feed'), |
| 153 | 'onlyDetails' => true |
| 154 | ], |
| 155 | [ |
| 156 | 'type' => 'booking', |
| 157 | 'name' => 'Booking.com', |
| 158 | 'heading' => __('Hotel URL', 'reviews-feed'), |
| 159 | 'placeholder' => __('https://www.booking.com/hotel/...', 'reviews-feed'), |
| 160 | 'onlyDetails' => true |
| 161 | ], |
| 162 | [ |
| 163 | 'type' => 'aliexpress', |
| 164 | 'name' => 'AliExpress', |
| 165 | 'heading' => __('Product URL', 'reviews-feed'), |
| 166 | 'placeholder' => __('https://www.aliexpress.com/item/...', 'reviews-feed'), |
| 167 | 'onlyDetails' => true |
| 168 | ] |
| 169 | ]; |
| 170 | |
| 171 | // Filter out disabled providers |
| 172 | $providers = array_filter($providers, function ($provider) { |
| 173 | return ! self::is_provider_disabled($provider['type']); |
| 174 | }); |
| 175 | |
| 176 | return array_values($providers); |
| 177 | } |
| 178 | |
| 179 | /** |
| 180 | * Used as a listener for the account connection process. If |
| 181 | * data is returned from the account connection processed it's used |
| 182 | * to generate the list of possible sources to chose from. |
| 183 | * |
| 184 | * @return array|bool |
| 185 | * |
| 186 | * @since 1.0 |
| 187 | */ |
| 188 | public static function maybe_source_connection_data() |
| 189 | { |
| 190 | $nonce = !empty($_GET['cff_con']) ? sanitize_key($_GET['cff_con']) : ''; |
| 191 | if (!wp_verify_nonce($nonce, 'cff_con')) { |
| 192 | return false; |
| 193 | } |
| 194 | |
| 195 | if ( |
| 196 | isset($_GET['cff_access_token']) |
| 197 | && isset($_GET['cff_final_response']) |
| 198 | && $_GET['cff_final_response'] == 'true' |
| 199 | ) { |
| 200 | $access_token = sanitize_text_field(wp_unslash($_GET['cff_access_token'])); |
| 201 | $return = Util::retrieve_available_pages($access_token); |
| 202 | |
| 203 | if ($return) { |
| 204 | return $return; |
| 205 | } else { |
| 206 | return array('error' => __('Unable to connect to Facebook to retrieve account information.', 'reviews-feed')); |
| 207 | } |
| 208 | } |
| 209 | return false; |
| 210 | } |
| 211 | |
| 212 | /** |
| 213 | * Uses the Facebook API to retrieve a list of pages for the |
| 214 | * access token |
| 215 | * |
| 216 | * @param string $access_token |
| 217 | * |
| 218 | * @return array|bool |
| 219 | * |
| 220 | * @since 1.0 |
| 221 | */ |
| 222 | public static function retrieve_available_pages($access_token) |
| 223 | { |
| 224 | //Get User Info |
| 225 | $user_url = 'https://graph.facebook.com/me?fields=name,id,picture&access_token=' . urlencode($access_token); |
| 226 | $user_id_data = wp_remote_retrieve_body(wp_remote_get($user_url)); |
| 227 | $user_id_data_arr = json_decode($user_id_data, true); |
| 228 | |
| 229 | $url = 'https://graph.facebook.com/me/accounts?fields=access_token,name,id,overall_star_rating,rating_count&limit=500&access_token=' . urlencode($access_token); |
| 230 | $pages_data = wp_remote_retrieve_body(wp_remote_get($url)); |
| 231 | $pages_data_arr = json_decode($pages_data, true); |
| 232 | |
| 233 | |
| 234 | if (isset($pages_data_arr['data'])) { |
| 235 | $return = [ |
| 236 | 'user' => $user_id_data_arr, |
| 237 | 'pages' => $pages_data_arr['data'], |
| 238 | ]; |
| 239 | |
| 240 | return $return; |
| 241 | } elseif (isset($pages_data_arr['error'])) { |
| 242 | return $pages_data_arr; |
| 243 | } else { |
| 244 | return [ |
| 245 | 'error' => [ |
| 246 | 'code' => 'HTTP Request', |
| 247 | 'message' => __('Your server could not complete a remote request to Facebook\'s API. Your host may be blocking access or |
| 248 | there may be a problem with your server.', 'reviews-feed') |
| 249 | ] |
| 250 | ]; |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | public static function currentPageIs($page) |
| 255 | { |
| 256 | $current_screen = get_current_screen(); |
| 257 | return $current_screen !== null && !empty($current_screen) && strpos($current_screen->id, $page) !== false; |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Check Notices for no Provider API KEY |
| 262 | * |
| 263 | * |
| 264 | * @return boolean |
| 265 | * |
| 266 | * @since 1.0 |
| 267 | */ |
| 268 | public static function check_notice_provider_nokey($api_limits) |
| 269 | { |
| 270 | $noapi_providers = ['wordpress.org', 'trustpilot']; |
| 271 | $is_true = $api_limits == $noapi_providers ? false : true; |
| 272 | |
| 273 | foreach ($noapi_providers as $provider) { |
| 274 | if ($api_limits == [$provider]) { |
| 275 | $is_true = false; |
| 276 | } |
| 277 | } |
| 278 | return $is_true; |
| 279 | } |
| 280 | |
| 281 | /** |
| 282 | * Returns a list of notices to be displayed in the SB Reviews Pages |
| 283 | * |
| 284 | * |
| 285 | * @return array |
| 286 | * |
| 287 | * @since 1.0 |
| 288 | */ |
| 289 | public static function get_plugin_notices() |
| 290 | { |
| 291 | $notices = []; |
| 292 | |
| 293 | $api_limits = get_option('sbr_apikeys_limit', []); |
| 294 | $should_show_notice = is_array($api_limits) && sizeof($api_limits) > 0 && Util::check_notice_provider_nokey($api_limits); |
| 295 | if ($should_show_notice) { |
| 296 | array_push($notices, [ |
| 297 | 'type' => 'error', |
| 298 | 'heading' => __('New reviews will not display until an API key is entered for your sources.', 'reviews-feed'), |
| 299 | 'description' => __('Due to API limitations your feeds will not show new reviews until you enter an API key on the settings page.', 'reviews-feed'), |
| 300 | 'actions' => [ |
| 301 | [ |
| 302 | 'type' => 'primary', |
| 303 | 'text' => __('How to create an API key', 'reviews-feed'), |
| 304 | 'link' => admin_url('admin.php?page=sbr-settings') |
| 305 | ], |
| 306 | [ |
| 307 | 'type' => 'secondary', |
| 308 | 'text' => __('Go to Settings page', 'reviews-feed'), |
| 309 | 'link' => admin_url('admin.php?page=sbr-settings') |
| 310 | ] |
| 311 | ] |
| 312 | ]); |
| 313 | } |
| 314 | |
| 315 | $noAPIKeyProviders = ['trustpilot', 'wordpress.org']; |
| 316 | $noAPIProviderxists = count(array_intersect($noAPIKeyProviders, $api_limits)) ? true : false; |
| 317 | |
| 318 | if ($noAPIProviderxists) { |
| 319 | array_push($notices, [ |
| 320 | 'type' => 'error', |
| 321 | 'heading' => __('You have reached the number of allowed sources.', 'reviews-feed'), |
| 322 | 'description' => __('Due to API limitations your feeds will not show new reviews because you have reached the number of allowed sources.', 'reviews-feed'), |
| 323 | ]); |
| 324 | } |
| 325 | |
| 326 | return $notices; |
| 327 | } |
| 328 | |
| 329 | /** |
| 330 | * Get Smahballoon Plugins Info |
| 331 | * |
| 332 | * @since 1.0 |
| 333 | */ |
| 334 | public static function get_plugins_info() |
| 335 | { |
| 336 | $installed_plugins = get_plugins(); |
| 337 | $campaign = self::sbr_is_pro() ? 'reviews-pro' : 'reviews-free'; |
| 338 | |
| 339 | $plugins_list = [ |
| 340 | 'facebook' => [ |
| 341 | 'free' => 'custom-facebook-feed/custom-facebook-feed.php', |
| 342 | 'pro' => 'custom-facebook-feed-pro/custom-facebook-feed.php', |
| 343 | 'link' => 'https://smashballoon.com/custom-facebook-feed/?utm_campaign=' . $campaign . '&utm_source=about-us&utm_medium=marketing' |
| 344 | ], |
| 345 | 'instagram' => [ |
| 346 | 'free' => 'instagram-feed/instagram-feed.php', |
| 347 | 'pro' => 'instagram-feed-pro/instagram-feed.php', |
| 348 | 'link' => 'https://smashballoon.com/instagram-feed/?utm_campaign=' . $campaign . '&utm_source=about-us&utm_medium=marketing' |
| 349 | ], |
| 350 | 'twitter' => [ |
| 351 | 'free' => 'custom-twitter-feeds/custom-twitter-feed.php', |
| 352 | 'pro' => 'custom-twitter-feeds-pro/custom-twitter-feed.php', |
| 353 | 'link' => 'https://smashballoon.com/custom-twitter-feeds/?utm_campaign=' . $campaign . '&utm_source=about-us&utm_medium=marketing' |
| 354 | ], |
| 355 | 'youtube' => [ |
| 356 | 'free' => 'feeds-for-youtube/youtube-feed.php', |
| 357 | 'pro' => 'youtube-feed-pro/youtube-feed.php', |
| 358 | 'link' => 'https://smashballoon.com/youtube-feed/?utm_campaign=' . $campaign . '&utm_source=about-us&utm_medium=marketing' |
| 359 | ] |
| 360 | ]; |
| 361 | |
| 362 | foreach ($plugins_list as $name => $plugin) { |
| 363 | $type = 'none'; |
| 364 | $activated = 'none'; |
| 365 | if (isset($installed_plugins[$plugin['free']])) { |
| 366 | $type = 'free'; |
| 367 | $activated = is_plugin_active($plugin['free']); |
| 368 | } |
| 369 | if (isset($installed_plugins[$plugin['pro']])) { |
| 370 | $type = 'pro'; |
| 371 | $activated = is_plugin_active($plugin['pro']); |
| 372 | } |
| 373 | $plugins_list[$name]['activated'] = $activated; |
| 374 | $plugins_list[$name]['type'] = $type; |
| 375 | } |
| 376 | |
| 377 | return [ |
| 378 | 'facebook' => [ |
| 379 | 'plugin' => $plugins_list['facebook']['pro'], |
| 380 | 'link' => $plugins_list['facebook']['link'], |
| 381 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/custom-facebook-feed.zip', |
| 382 | 'title' => __('Custom Facebook Feed', 'reviews-feed'), |
| 383 | 'description' => __('Add Facebook posts from your timeline, albums and much more.', 'reviews-feed'), |
| 384 | 'icon' => 'fb-icon.svg', |
| 385 | 'activated' => $plugins_list['facebook']['activated'], |
| 386 | 'type' => $plugins_list['facebook']['type'], |
| 387 | ], |
| 388 | 'instagram' => [ |
| 389 | 'plugin' => $plugins_list['instagram']['pro'], |
| 390 | 'link' => $plugins_list['instagram']['link'], |
| 391 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/instagram-feed.zip', |
| 392 | 'title' => __('Instagram Feed', 'reviews-feed'), |
| 393 | 'description' => __('A quick and elegant way to add your Instagram posts to your website. ', 'reviews-feed'), |
| 394 | 'icon' => 'insta-icon.svg', |
| 395 | 'activated' => $plugins_list['instagram']['activated'], |
| 396 | 'type' => $plugins_list['instagram']['type'], |
| 397 | ], |
| 398 | 'twitter' => [ |
| 399 | 'plugin' => $plugins_list['twitter']['pro'], |
| 400 | 'link' => $plugins_list['twitter']['link'], |
| 401 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/custom-twitter-feeds.zip', |
| 402 | 'title' => __('Custom Twitter Feeds', 'reviews-feed'), |
| 403 | 'description' => __('A customizable way to display tweets from your Twitter account. ', 'reviews-feed'), |
| 404 | 'icon' => 'twitter-icon.svg', |
| 405 | 'activated' => $plugins_list['twitter']['activated'], |
| 406 | 'type' => $plugins_list['twitter']['type'], |
| 407 | ], |
| 408 | 'youtube' => [ |
| 409 | 'plugin' => $plugins_list['youtube']['pro'], |
| 410 | 'link' => $plugins_list['youtube']['link'], |
| 411 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/feeds-for-youtube.zip', |
| 412 | 'title' => __('Feeds for YouTube', 'reviews-feed'), |
| 413 | 'description' => __('A simple yet powerful way to display videos from YouTube. ', 'reviews-feed'), |
| 414 | 'icon' => 'youtube-icon.svg', |
| 415 | 'activated' => $plugins_list['youtube']['activated'], |
| 416 | 'type' => $plugins_list['youtube']['type'], |
| 417 | ] |
| 418 | ]; |
| 419 | } |
| 420 | |
| 421 | /** |
| 422 | * Get Smahballoon Recommended Plugins Info |
| 423 | * |
| 424 | * @since 1.0 |
| 425 | */ |
| 426 | public static function get_smashballoon_recommended_plugins_info() |
| 427 | { |
| 428 | $installed_plugins = get_plugins(); |
| 429 | return [ |
| 430 | 'wpforms' => [ |
| 431 | 'plugin' => 'wpforms-lite/wpforms.php', |
| 432 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/wpforms-lite.zip', |
| 433 | 'title' => __('WPForms', 'reviews-feed'), |
| 434 | 'description' => __('The most beginner friendly drag & drop WordPress forms plugin allowing you to create beautiful contact forms, subscription forms, payment forms, and more in minutes, not hours!', 'reviews-feed'), |
| 435 | 'icon' => 'plugin-wpforms.png', |
| 436 | 'installed' => isset($installed_plugins['wpforms-lite/wpforms.php']), |
| 437 | 'activated' => is_plugin_active('wpforms-lite/wpforms.php'), |
| 438 | ], |
| 439 | 'monsterinsights' => [ |
| 440 | 'plugin' => 'google-analytics-for-wordpress/googleanalytics.php', |
| 441 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip', |
| 442 | 'title' => __('MonsterInsights', 'reviews-feed'), |
| 443 | 'description' => __('MonsterInsights makes it “effortless” to properly connect your WordPress site with Google Analytics, so you can start making data-driven decisions to grow your business.', 'reviews-feed'), |
| 444 | 'icon' => 'plugin-mi.png', |
| 445 | 'installed' => isset($installed_plugins['google-analytics-for-wordpress/googleanalytics.php']), |
| 446 | 'activated' => is_plugin_active('google-analytics-for-wordpress/googleanalytics.php'), |
| 447 | ], |
| 448 | 'optinmonster' => [ |
| 449 | 'plugin' => 'optinmonster/optin-monster-wp-api.php', |
| 450 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/optinmonster.zip', |
| 451 | 'title' => __('OptinMonster', 'reviews-feed'), |
| 452 | 'description' => __('Our high-converting optin forms like Exit-Intent® popups, Fullscreen Welcome Mats, and Scroll boxes help you dramatically boost conversions and get more email subscribers.', 'reviews-feed'), |
| 453 | 'icon' => 'plugin-om.png', |
| 454 | 'installed' => isset($installed_plugins['optinmonster/optin-monster-wp-api.php']), |
| 455 | 'activated' => is_plugin_active('optinmonster/optin-monster-wp-api.php'), |
| 456 | ], |
| 457 | 'wp_mail_smtp' => [ |
| 458 | 'plugin' => 'wp-mail-smtp/wp_mail_smtp.php', |
| 459 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip', |
| 460 | 'title' => __('WP Mail SMTP', 'reviews-feed'), |
| 461 | 'description' => __('Make sure your website\'s emails reach the inbox. Our goal is to make email deliverability easy and reliable. Trusted by over 1 million websites.', 'reviews-feed'), |
| 462 | 'icon' => 'plugin-smtp.png', |
| 463 | 'installed' => isset($installed_plugins['wp-mail-smtp/wp_mail_smtp.php']), |
| 464 | 'activated' => is_plugin_active('wp-mail-smtp/wp_mail_smtp.php'), |
| 465 | ], |
| 466 | 'rafflepress' => [ |
| 467 | 'plugin' => 'rafflepress/rafflepress.php', |
| 468 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/rafflepress.zip', |
| 469 | 'title' => __('RafflePress', 'reviews-feed'), |
| 470 | 'description' => __('Turn your visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with powerful viral giveaways & contests.', 'reviews-feed'), |
| 471 | 'icon' => 'plugin-rp.png', |
| 472 | 'installed' => isset($installed_plugins['rafflepress/rafflepress.php']), |
| 473 | 'activated' => is_plugin_active('rafflepress/rafflepress.php'), |
| 474 | ], |
| 475 | 'aioseo' => [ |
| 476 | 'plugin' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', |
| 477 | 'download_plugin' => 'https://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip', |
| 478 | 'title' => __('All in One SEO Pack', 'reviews-feed'), |
| 479 | 'description' => __('Out-of-the-box SEO for WordPress. Features like XML Sitemaps, SEO for custom post types, SEO for blogs, business sites, or ecommerce sites, and much more.', 'reviews-feed'), |
| 480 | 'icon' => 'plugin-seo.png', |
| 481 | 'installed' => isset($installed_plugins['all-in-one-seo-pack/all_in_one_seo_pack.php']), |
| 482 | 'activated' => is_plugin_active('all-in-one-seo-pack/all_in_one_seo_pack.php'), |
| 483 | ] |
| 484 | ]; |
| 485 | } |
| 486 | /** |
| 487 | * Get other active plugins of Smash Balloon |
| 488 | * |
| 489 | * @since 4.4.0 |
| 490 | */ |
| 491 | public static function get_sb_active_plugins_info() |
| 492 | { |
| 493 | // get the WordPress's core list of installed plugins |
| 494 | if (!function_exists('get_plugins')) { |
| 495 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 496 | } |
| 497 | $installed_plugins = get_plugins(); |
| 498 | |
| 499 | $is_facebook_installed = false; |
| 500 | $facebook_plugin = 'custom-facebook-feed/custom-facebook-feed.php'; |
| 501 | if (isset($installed_plugins['custom-facebook-feed-pro/custom-facebook-feed.php'])) { |
| 502 | $is_facebook_installed = true; |
| 503 | $facebook_plugin = 'custom-facebook-feed-pro/custom-facebook-feed.php'; |
| 504 | } elseif (isset($installed_plugins['custom-facebook-feed/custom-facebook-feed.php'])) { |
| 505 | $is_facebook_installed = true; |
| 506 | } |
| 507 | |
| 508 | $is_instagram_installed = false; |
| 509 | $instagram_plugin = 'instagram-feed/instagram-feed.php'; |
| 510 | if (isset($installed_plugins['instagram-feed-pro/instagram-feed.php'])) { |
| 511 | $is_instagram_installed = true; |
| 512 | $instagram_plugin = 'instagram-feed-pro/instagram-feed.php'; |
| 513 | } elseif (isset($installed_plugins['instagram-feed/instagram-feed.php'])) { |
| 514 | $is_instagram_installed = true; |
| 515 | } |
| 516 | |
| 517 | $is_twitter_installed = false; |
| 518 | $twitter_plugin = 'custom-twitter-feeds/custom-twitter-feed.php'; |
| 519 | if (isset($installed_plugins['custom-twitter-feeds-pro/custom-twitter-feed.php'])) { |
| 520 | $is_twitter_installed = true; |
| 521 | $twitter_plugin = 'custom-twitter-feeds-pro/custom-twitter-feed.php'; |
| 522 | } elseif (isset($installed_plugins['custom-twitter-feeds/custom-twitter-feed.php'])) { |
| 523 | $is_twitter_installed = true; |
| 524 | } |
| 525 | |
| 526 | $is_youtube_installed = false; |
| 527 | $youtube_plugin = 'feeds-for-youtube/youtube-feed.php'; |
| 528 | if (isset($installed_plugins['youtube-feed-pro/youtube-feed-pro.php'])) { |
| 529 | $is_youtube_installed = true; |
| 530 | $youtube_plugin = 'youtube-feed-pro/youtube-feed-pro.php'; |
| 531 | } elseif (isset($installed_plugins['feeds-for-youtube/youtube-feed.php'])) { |
| 532 | $is_youtube_installed = true; |
| 533 | } |
| 534 | |
| 535 | $is_social_wall_installed = isset($installed_plugins['social-wall/social-wall.php']) ? true : false; |
| 536 | $social_wall_plugin = 'social-wall/social-wall.php'; |
| 537 | |
| 538 | |
| 539 | return array( |
| 540 | 'is_facebook_installed' => $is_facebook_installed, |
| 541 | 'is_instagram_installed' => $is_instagram_installed, |
| 542 | 'is_twitter_installed' => $is_twitter_installed, |
| 543 | 'is_youtube_installed' => $is_youtube_installed, |
| 544 | 'is_social_wall_installed' => $is_social_wall_installed, |
| 545 | 'facebook_plugin' => $facebook_plugin, |
| 546 | 'instagram_plugin' => $instagram_plugin, |
| 547 | 'twitter_plugin' => $twitter_plugin, |
| 548 | 'youtube_plugin' => $youtube_plugin, |
| 549 | 'social_wall_plugin' => $social_wall_plugin, |
| 550 | 'installed_plugins' => $installed_plugins |
| 551 | ); |
| 552 | } |
| 553 | |
| 554 | /** |
| 555 | * SBR Get Whitespace |
| 556 | * |
| 557 | * @since 1.0 |
| 558 | * |
| 559 | * @param int $times |
| 560 | * |
| 561 | * @return string |
| 562 | */ |
| 563 | public static function get_whitespace($times) |
| 564 | { |
| 565 | return str_repeat(' ', $times); |
| 566 | } |
| 567 | |
| 568 | /** |
| 569 | * Get Site and Server Info |
| 570 | * |
| 571 | * @since 1.0 |
| 572 | * |
| 573 | * @return string |
| 574 | */ |
| 575 | public static function get_site_n_server_info() |
| 576 | { |
| 577 | $allow_url_fopen = ini_get('allow_url_fopen') ? "Yes" : "No"; |
| 578 | $php_curl = is_callable('curl_init') ? "Yes" : "No"; |
| 579 | $php_json_decode = function_exists("json_decode") ? "Yes" : "No"; |
| 580 | $php_ssl = in_array('https', stream_get_wrappers()) ? "Yes" : "No"; |
| 581 | |
| 582 | $output = '## SITE/SERVER INFO: ##' . "</br>"; |
| 583 | $output .= 'Plugin Version:' . self::get_whitespace(11) . SBR_MENU_SLUG . "</br>"; |
| 584 | $output .= 'Site URL:' . self::get_whitespace(17) . site_url() . "</br>"; |
| 585 | $output .= 'Home URL:' . self::get_whitespace(17) . home_url() . "</br>"; |
| 586 | $output .= 'WordPress Version:' . self::get_whitespace(8) . get_bloginfo('version') . "</br>"; |
| 587 | $output .= 'PHP Version:' . self::get_whitespace(14) . PHP_VERSION . "</br>"; |
| 588 | $output .= 'Web Server Info:' . self::get_whitespace(10) . esc_html($_SERVER['SERVER_SOFTWARE']) . "</br>"; |
| 589 | $output .= 'PHP allow_url_fopen:' . self::get_whitespace(6) . $allow_url_fopen . "</br>"; |
| 590 | $output .= 'PHP cURL:' . self::get_whitespace(17) . $php_curl . "</br>"; |
| 591 | $output .= 'JSON:' . self::get_whitespace(21) . $php_json_decode . "</br>"; |
| 592 | $output .= 'SSL Stream:' . self::get_whitespace(15) . $php_ssl . "</br>"; |
| 593 | $output .= "</br>"; |
| 594 | |
| 595 | return $output; |
| 596 | } |
| 597 | |
| 598 | /** |
| 599 | * Get Active Plugins |
| 600 | * |
| 601 | * @since 1.0 |
| 602 | * |
| 603 | * @return string |
| 604 | */ |
| 605 | public static function get_active_plugins_info() |
| 606 | { |
| 607 | $plugins = get_plugins(); |
| 608 | $active_plugins = get_option('active_plugins'); |
| 609 | $output = "## ACTIVE PLUGINS: ## </br>"; |
| 610 | |
| 611 | foreach ($plugins as $plugin_path => $plugin) { |
| 612 | if (in_array($plugin_path, $active_plugins)) { |
| 613 | $output .= $plugin['Name'] . ': ' . $plugin['Version'] . "</br>"; |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | $output .= "</br>"; |
| 618 | |
| 619 | return $output; |
| 620 | } |
| 621 | |
| 622 | |
| 623 | /** |
| 624 | * Get Global Settings |
| 625 | * |
| 626 | * @since 1.0 |
| 627 | * |
| 628 | * @return string |
| 629 | */ |
| 630 | public static function get_global_settings_info() |
| 631 | { |
| 632 | $output = '## GLOBAL SETTINGS: ## </br>'; |
| 633 | $sbr_settings = get_option('sbr_settings', array()); |
| 634 | if (! is_array($sbr_settings)) { |
| 635 | $sbr_settings = array(); |
| 636 | } |
| 637 | |
| 638 | $plugin_status = new AuthorizationStatusCheck(); |
| 639 | |
| 640 | $statuses = $plugin_status->get_statuses(); |
| 641 | |
| 642 | if (Util::sbr_is_pro()) { |
| 643 | $output .= 'License key: '; |
| 644 | if (isset($sbr_settings['license_key'])) { |
| 645 | $output .= esc_html($sbr_settings['license_key']); |
| 646 | } else { |
| 647 | $output .= ' Not added'; |
| 648 | } |
| 649 | |
| 650 | $output .= '</br>'; |
| 651 | $output .= 'License Tier: '; |
| 652 | if (isset($statuses['license_tier'])) { |
| 653 | $output .= esc_html($statuses['license_tier']); |
| 654 | } else { |
| 655 | $output .= ' Not Set'; |
| 656 | } |
| 657 | $output .= '</br>'; |
| 658 | $output .= 'License status: '; |
| 659 | if (isset($sbr_settings['license_status'])) { |
| 660 | $output .= $sbr_settings['license_status']; |
| 661 | } else { |
| 662 | $output .= ' Inactive'; |
| 663 | } |
| 664 | $output .= '</br>'; |
| 665 | } |
| 666 | $output .= 'Preserve settings if plugin is removed: '; |
| 667 | $output .= isset($sbr_settings['preserve_settings']) && ($sbr_settings['preserve_settings']) ? 'Yes' : 'No'; |
| 668 | $output .= '</br>'; |
| 669 | $output .= 'Caching: '; |
| 670 | $output .= $statuses['license_tier'] === 3 ? 'Twice daily' : 'daily'; |
| 671 | |
| 672 | $output .= '</br>'; |
| 673 | $output .= 'GDPR: '; |
| 674 | $output .= isset($sbr_settings['gdpr']) ? $sbr_settings['gdpr'] : ' Not setup'; |
| 675 | $output .= '</br>'; |
| 676 | $output .= 'Optimize Images: '; |
| 677 | $output .= isset($sbr_settings['optimize_images']) && $sbr_settings['optimize_images'] === true ? 'Enabled' : 'Disabled'; |
| 678 | $output .= '</br>'; |
| 679 | $output .= 'Usage Tracking: '; |
| 680 | $output .= isset($sbr_settings['usagetracking']) && $sbr_settings['usagetracking'] === true ? 'Enabled' : 'Disabled'; |
| 681 | $output .= '</br>'; |
| 682 | $output .= 'Enqueue in Head: '; |
| 683 | $output .= isset($sbr_settings['enqueue_js_in_header']) && $sbr_settings['enqueue_js_in_header'] === true ? 'Enabled' : 'Disabled'; |
| 684 | $output .= '</br>'; |
| 685 | $output .= 'Admin Error Notice: '; |
| 686 | $output .= isset($sbr_settings['admin_error_notices']) && $sbr_settings['admin_error_notices'] === true ? 'Enabled' : 'Disabled'; |
| 687 | $output .= '</br>'; |
| 688 | $output .= 'Feed Issue Email Reports: '; |
| 689 | $output .= isset($sbr_settings['feed_issue_reports']) && $sbr_settings['feed_issue_reports'] === true ? 'Enabled' : 'Disabled'; |
| 690 | $output .= '</br>'; |
| 691 | $output .= '</br>'; |
| 692 | return $output; |
| 693 | } |
| 694 | |
| 695 | /** |
| 696 | * Get Feeds Settings |
| 697 | * |
| 698 | * @since 1.0 |
| 699 | * |
| 700 | * @return string |
| 701 | */ |
| 702 | public static function get_sources_settings_info() |
| 703 | { |
| 704 | $output = '## SOURCES: ## </br>'; |
| 705 | $source_list = SBR_Sources::get_sources_list(); |
| 706 | foreach ($source_list as $feed) { |
| 707 | $output .= $feed['name'] . ' ( ' . strtoupper($feed['provider']) . ' => ' . $feed['account_id'] . ' )'; |
| 708 | $output .= '</br>'; |
| 709 | } |
| 710 | $output .= '</br>'; |
| 711 | |
| 712 | return $output; |
| 713 | } |
| 714 | |
| 715 | /** |
| 716 | * Get Feeds Settings |
| 717 | * |
| 718 | * @since 1.0 |
| 719 | * |
| 720 | * @return string |
| 721 | */ |
| 722 | public static function get_api_settings_info() |
| 723 | { |
| 724 | $output = '## API KEYS: ## </br>'; |
| 725 | $api_keys = get_option('sbr_apikeys', []); |
| 726 | |
| 727 | foreach ($api_keys as $id => $api) { |
| 728 | $output .= ucfirst($id) . ' => ' . $api; |
| 729 | $output .= '</br>'; |
| 730 | } |
| 731 | $output .= '</br>'; |
| 732 | |
| 733 | return $output; |
| 734 | } |
| 735 | |
| 736 | |
| 737 | |
| 738 | /** |
| 739 | * Get Feeds Settings |
| 740 | * |
| 741 | * @since 1.0 |
| 742 | * |
| 743 | * @return string |
| 744 | */ |
| 745 | public static function get_feeds_settings_info() |
| 746 | { |
| 747 | $output = '## FEEDS: ## </br>'; |
| 748 | |
| 749 | $feeds_list = DB::get_feeds_list(); |
| 750 | |
| 751 | $i = 0; |
| 752 | foreach ($feeds_list as $feed) { |
| 753 | if ($i >= 25) { |
| 754 | break; |
| 755 | } |
| 756 | $output .= $feed['feed_name']; |
| 757 | if (isset($feed['settings'])) { |
| 758 | $output .= '</br>'; |
| 759 | if (!empty($feed['sourcesList'])) { |
| 760 | foreach ($feed['sourcesList'] as $id => $source) { |
| 761 | $output .= esc_html($source['name']); |
| 762 | $output .= ' (' . esc_html(ucfirst($source['name'])) . ' => ' . esc_html($source['account_id']) . ')'; |
| 763 | $output .= '</br>'; |
| 764 | } |
| 765 | } |
| 766 | } |
| 767 | $output .= '</br>'; |
| 768 | if (isset($feed['location_summary']) && count($feed['location_summary']) > 0) { |
| 769 | $first_feed = $feed['location_summary'][0]; |
| 770 | if (!empty($first_feed['link'])) { |
| 771 | $output .= esc_html($first_feed['link']) . '?sb_debug'; |
| 772 | $output .= '</br>'; |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | if ($i < (count($feeds_list) - 1)) { |
| 777 | $output .= '</br>'; |
| 778 | } |
| 779 | $i++; |
| 780 | } |
| 781 | $output .= '</br>'; |
| 782 | |
| 783 | return $output; |
| 784 | } |
| 785 | |
| 786 | /** |
| 787 | * Get Posts Table Info |
| 788 | * |
| 789 | * @since 1.0 |
| 790 | * |
| 791 | * @return string |
| 792 | */ |
| 793 | public static function get_posts_table_info() |
| 794 | { |
| 795 | $output = '## POSTS: ## </br>'; |
| 796 | |
| 797 | global $wpdb; |
| 798 | $table_name = $wpdb->prefix . 'sbr_posts'; |
| 799 | $feeds_posts_table_name = $wpdb->prefix . 'sbr_reviews_posts'; |
| 800 | |
| 801 | if ($wpdb->get_var("show tables like '$feeds_posts_table_name'") !== $feeds_posts_table_name) { |
| 802 | $output .= 'no feeds posts table</br>'; |
| 803 | } else { |
| 804 | $last_result = $wpdb->get_results("SELECT * FROM $feeds_posts_table_name ORDER BY id DESC LIMIT 1;"); |
| 805 | if (is_array($last_result) && isset($last_result[0])) { |
| 806 | $output .= '## FEEDS POSTS TABLE ##</br>'; |
| 807 | foreach ($last_result as $column) { |
| 808 | foreach ($column as $key => $value) { |
| 809 | $output .= esc_html($key) . ': ' . esc_html($value) . '</br>'; |
| 810 | } |
| 811 | } |
| 812 | } else { |
| 813 | $output .= 'feeds posts has no rows'; |
| 814 | $output .= '</br>'; |
| 815 | } |
| 816 | } |
| 817 | $output .= '</br>'; |
| 818 | if ($wpdb->get_var("show tables like '$table_name'") !== $table_name) { |
| 819 | $output .= 'no posts table</br>'; |
| 820 | } else { |
| 821 | $last_result = $wpdb->get_results("SELECT * FROM $table_name ORDER BY id DESC LIMIT 1;"); |
| 822 | if (is_array($last_result) && isset($last_result[0])) { |
| 823 | $output .= '## POSTS TABLE ##'; |
| 824 | $output .= '</br>'; |
| 825 | foreach ($last_result as $column) { |
| 826 | foreach ($column as $key => $value) { |
| 827 | $output .= esc_html($key) . ': ' . esc_html($value) . '</br>'; |
| 828 | } |
| 829 | } |
| 830 | } else { |
| 831 | $output .= 'posts has no rows</br>'; |
| 832 | } |
| 833 | } |
| 834 | $output .= '</br>'; |
| 835 | |
| 836 | return $output; |
| 837 | } |
| 838 | |
| 839 | /** |
| 840 | * List of possible languages/translations |
| 841 | * |
| 842 | * @since 1.0 |
| 843 | * |
| 844 | * @return array |
| 845 | */ |
| 846 | public static function get_translation_languages($include_default = false) |
| 847 | { |
| 848 | $languages = [ |
| 849 | 'default' => 'Default', |
| 850 | '' => 'No Translation', |
| 851 | 'en' => 'English', |
| 852 | 'af' => 'Afrikaans', |
| 853 | 'am' => 'Amharic', |
| 854 | 'ar' => 'Arabic', |
| 855 | 'az' => 'Azerbaijani', |
| 856 | 'be' => 'Belarusian', |
| 857 | 'bg' => 'Bulgarian', |
| 858 | 'bn' => 'Bengali', |
| 859 | 'bs' => 'Bosnian', |
| 860 | 'ca' => 'Catalan', |
| 861 | 'cs' => 'Czech', |
| 862 | 'da' => 'Danish', |
| 863 | 'de' => 'German', |
| 864 | 'el' => 'Greek', |
| 865 | 'en-AU' => 'English (Australian)', |
| 866 | 'en-GB' => 'English (Great Britain)', |
| 867 | 'es' => 'Spanish', |
| 868 | 'es-419' => 'Spanish (Latin America)', |
| 869 | 'et' => 'Estonian', |
| 870 | 'eu' => 'Basque', |
| 871 | 'fa' => 'Farsi', |
| 872 | 'fi' => 'Finnish', |
| 873 | 'fil' => 'Filipino', |
| 874 | 'fr' => 'French', |
| 875 | 'fr-CA' => 'French (Canada)', |
| 876 | 'gl' => 'Galician', |
| 877 | 'gu' => 'Gujarati', |
| 878 | 'hi' => 'Hindi', |
| 879 | 'hr' => 'Croatian', |
| 880 | 'hu' => 'Hungarian', |
| 881 | 'hy' => 'Armenian', |
| 882 | 'id' => 'Indonesian', |
| 883 | 'is' => 'Icelandic', |
| 884 | 'it' => 'Italian ', |
| 885 | 'iw' => 'Hebrew', |
| 886 | 'ja' => 'Japanese', |
| 887 | 'ka' => 'Georgian', |
| 888 | 'kk' => 'Kazakh', |
| 889 | 'km' => 'Khmer', |
| 890 | 'kn' => 'Kannada', |
| 891 | 'ko' => 'Korean', |
| 892 | 'ky' => 'Kyrgyz', |
| 893 | 'lo' => 'Lao', |
| 894 | 'lt' => 'Lithuanian', |
| 895 | 'lv' => 'Latvian', |
| 896 | 'mk' => 'Macedonian', |
| 897 | 'ml' => 'Malayalam', |
| 898 | 'mn' => 'Mongolian', |
| 899 | 'mr' => 'Marathi', |
| 900 | 'ms' => 'Malay', |
| 901 | 'my' => 'Burmese', |
| 902 | 'ne' => 'Nepali', |
| 903 | 'nl' => 'Dutch', |
| 904 | 'no' => 'Norwegian', |
| 905 | 'pa' => 'Punjabi', |
| 906 | 'pl' => 'Polish', |
| 907 | 'pt' => 'Portuguese', |
| 908 | 'pt-BR' => 'Portuguese (Brazil)', |
| 909 | 'pt-PT' => 'Portuguese (Portugal)', |
| 910 | 'ro' => 'Romanian', |
| 911 | 'ru' => 'Russian', |
| 912 | 'si' => 'Sinhalese', |
| 913 | 'sk' => 'Slovak', |
| 914 | 'sl' => 'Slovenian', |
| 915 | 'sq' => 'Albanian', |
| 916 | 'sr' => 'Serbian', |
| 917 | 'sv' => 'Swedish', |
| 918 | 'sw' => 'Swahili', |
| 919 | 'ta' => 'Tamil', |
| 920 | 'te' => 'Telugu', |
| 921 | 'th' => 'Thai', |
| 922 | 'tr' => 'Turkish', |
| 923 | 'uk' => 'Ukrainian', |
| 924 | 'ur' => 'Urdu', |
| 925 | 'uz' => 'Uzbek', |
| 926 | 'vi' => 'Vietnamese', |
| 927 | 'zh' => 'Chinese', |
| 928 | 'zh-CN' => 'Chinese (Simplified)', |
| 929 | 'zh-HK' => 'Chinese (Hong Kong)', |
| 930 | 'zh-TW' => 'Chinese (Traditional)', |
| 931 | 'zu' => 'Zulu' |
| 932 | ]; |
| 933 | if ($include_default === false) { |
| 934 | array_shift($languages); |
| 935 | } |
| 936 | |
| 937 | //Detect if WPMl is active then add the option |
| 938 | if (defined('ICL_SITEPRESS_VERSION') && Util::sbr_is_pro()) { |
| 939 | $position = $include_default ? 2 : 1; |
| 940 | $languages = array_merge( |
| 941 | array_slice($languages, 0, $position), |
| 942 | ['wpml' => 'Automatically by WPML'], |
| 943 | array_slice($languages, $position) |
| 944 | ); |
| 945 | } |
| 946 | |
| 947 | return $languages; |
| 948 | } |
| 949 | |
| 950 | /** |
| 951 | * Get Language for API call |
| 952 | * |
| 953 | * @since 1.0 |
| 954 | * |
| 955 | * @return string |
| 956 | */ |
| 957 | |
| 958 | public static function get_settings_language($settings) |
| 959 | { |
| 960 | $args = isset($settings['localization']) && $settings['localization'] !== 'default' |
| 961 | ? $settings |
| 962 | : wp_parse_args(get_option('sbr_settings', []), sbr_plugin_settings_defaults()); |
| 963 | |
| 964 | return $args['localization']; |
| 965 | } |
| 966 | |
| 967 | /** |
| 968 | * Get Language for API call |
| 969 | * |
| 970 | * @since 1.0 |
| 971 | * |
| 972 | * @return string |
| 973 | */ |
| 974 | public static function get_api_call_language($settings) |
| 975 | { |
| 976 | $language = Util::sbr_is_pro() |
| 977 | ? \SmashBalloon\Reviews\Pro\Helpers\SBR_WPML::get_current_language(Util::get_settings_language($settings)) |
| 978 | : Util::get_settings_language($settings); |
| 979 | |
| 980 | /** |
| 981 | * Filter the language code sent to the provider API (e.g. Google Places). |
| 982 | * Lets a site map an unsupported locale to a supported one, e.g. a WPML |
| 983 | * `es-mx` site forcing `es-419` for Latin American Spanish. SMASH-1617. |
| 984 | * Read the current WPML language inside the callback (apply_filters |
| 985 | * 'wpml_current_language') if you need per-page context. |
| 986 | * |
| 987 | * @since 2.6.6 |
| 988 | * @param string $language Resolved language code (or 'default'). |
| 989 | */ |
| 990 | return apply_filters('sbr_google_api_language', $language); |
| 991 | } |
| 992 | |
| 993 | /** |
| 994 | * Map a locale / WPML language code to a code the Google Places API accepts. |
| 995 | * |
| 996 | * Google only honours codes from its supported list (get_translation_languages); |
| 997 | * an unsupported value (e.g. WPML's `es-mx`) makes Google return reviews |
| 998 | * untranslated. This normalises common regional codes to a supported one. |
| 999 | * Spanish is special-cased: Spain dialects -> `es`, any other Spanish variant |
| 1000 | * (es-mx, es-ar, …) -> `es-419` (Latin America) — region-stripping alone would |
| 1001 | * wrongly land on Spain Spanish. Returns null when nothing supported matches, |
| 1002 | * so callers can fall back (never send a bogus code). SMASH-1617. |
| 1003 | * |
| 1004 | * @since 2.6.6 |
| 1005 | * @param string|null $code Raw locale / WPML code (e.g. 'es-mx', 'pt-br', 'es_MX'). |
| 1006 | * @return string|null A Google-supported code, or null if unmappable. |
| 1007 | */ |
| 1008 | public static function map_wpml_to_google_language($code) |
| 1009 | { |
| 1010 | if (! is_string($code) || $code === '') { |
| 1011 | return null; |
| 1012 | } |
| 1013 | |
| 1014 | $allowed = self::get_translation_languages(); |
| 1015 | |
| 1016 | // Already a supported code (exact match) — keep existing behaviour. |
| 1017 | if (isset($allowed[$code]) && $code !== 'default' && $code !== '') { |
| 1018 | return $code; |
| 1019 | } |
| 1020 | |
| 1021 | $norm = strtolower(str_replace('_', '-', $code)); |
| 1022 | |
| 1023 | // Spanish: Spain -> es; every other variant (es-mx, es-ar, …) -> es-419. |
| 1024 | if ($norm === 'es' || $norm === 'es-es') { |
| 1025 | return 'es'; |
| 1026 | } |
| 1027 | if (strpos($norm, 'es-') === 0) { |
| 1028 | return 'es-419'; |
| 1029 | } |
| 1030 | |
| 1031 | // Case-insensitive match for region variants Google does list (pt-br -> pt-BR). |
| 1032 | foreach (array_keys($allowed) as $supported) { |
| 1033 | if (strtolower($supported) === $norm) { |
| 1034 | return $supported; |
| 1035 | } |
| 1036 | } |
| 1037 | |
| 1038 | // Strip the region and fall back to the base language if supported (fr-fr -> fr). |
| 1039 | $base = strtok($norm, '-'); |
| 1040 | if ($base !== false && isset($allowed[$base])) { |
| 1041 | return $base; |
| 1042 | } |
| 1043 | |
| 1044 | return null; |
| 1045 | } |
| 1046 | |
| 1047 | /** |
| 1048 | * Is Plugin Pro |
| 1049 | * |
| 1050 | * @since 1.0 |
| 1051 | * |
| 1052 | * @return boolean |
| 1053 | */ |
| 1054 | public static function sbr_is_pro() |
| 1055 | { |
| 1056 | return defined('SBR_PRO') && SBR_PRO === true; |
| 1057 | } |
| 1058 | |
| 1059 | /** |
| 1060 | * Check if user has Pro Plus tier |
| 1061 | * |
| 1062 | * @since 2.5.0 |
| 1063 | * |
| 1064 | * @return boolean |
| 1065 | */ |
| 1066 | public static function sbr_is_pro_plus() |
| 1067 | { |
| 1068 | if (!self::sbr_is_pro()) { |
| 1069 | return false; |
| 1070 | } |
| 1071 | |
| 1072 | // Read from sbr_statuses where license_tier is written during license activation |
| 1073 | // This is consistent with AuthorizationStatusCheck::get_license_tier() |
| 1074 | $statuses = get_option('sbr_statuses', []); |
| 1075 | $license_tier = $statuses['license_tier'] ?? 0; |
| 1076 | |
| 1077 | // Handle All Access Bundle special case (same as AuthorizationStatusCheck) |
| 1078 | if ( |
| 1079 | isset($statuses['license_info']['item_name']) |
| 1080 | && $statuses['license_info']['item_name'] === 'All Access Bundle - All Plugins Unlimited' |
| 1081 | ) { |
| 1082 | $license_tier = 3; |
| 1083 | } |
| 1084 | |
| 1085 | // Tiers: 1 = Pro Basic, 2 = Pro Plus, 3 = Elite |
| 1086 | // Pro Plus and Elite (tiers 2 and 3) have full access |
| 1087 | return (int) $license_tier >= 2; |
| 1088 | } |
| 1089 | |
| 1090 | |
| 1091 | /** |
| 1092 | * Get List of Upsell Modal Content |
| 1093 | * |
| 1094 | * @since 1.0 |
| 1095 | * |
| 1096 | * @return array |
| 1097 | */ |
| 1098 | public static function upsell_modal_content() |
| 1099 | { |
| 1100 | // Pro users (including Pro Plus) don't need provider upsell modals |
| 1101 | // Note: Review Alert Pro Plus upsells are handled separately in SBR_ReviewAlert_Builder |
| 1102 | if (Util::sbr_is_pro()) { |
| 1103 | return []; |
| 1104 | } |
| 1105 | |
| 1106 | // Free users get all upsell modals |
| 1107 | return [ |
| 1108 | 'facebookProvider' => [ |
| 1109 | 'heading' => __('Upgrade to Pro to display Facebook reviews', 'reviews-feed'), |
| 1110 | 'description' => __('Upgrade to our "Plus" tier to display reviews from the well known social media platform.', 'reviews-feed'), |
| 1111 | 'image' => 'upsell-facebook.png', |
| 1112 | 'buttons' => [ |
| 1113 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=facebook-modal&utm_content=LiteUsers50OFF', |
| 1114 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=facebook-modal&utm_content=Upgrade', |
| 1115 | # 'demo' => 'https://smashballoon.com/reviews-feed/demo/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=responsive-modal&utm_content=ViewDemo' |
| 1116 | ], |
| 1117 | |
| 1118 | 'includeContent' => true |
| 1119 | ], |
| 1120 | 'trustpilotProvider' => [ |
| 1121 | 'heading' => __('Upgrade to Pro to display TrustPilot reviews', 'reviews-feed'), |
| 1122 | 'description' => __('Upgrade to our "Plus" tier to display reviews from the well known business review site.', 'reviews-feed'), |
| 1123 | 'image' => 'upsell-trustpilot.png', |
| 1124 | 'buttons' => [ |
| 1125 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=trustpilot-modal&utm_content=LiteUsers50OFF', |
| 1126 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=trustpilot-modal&utm_content=Upgrade' |
| 1127 | ], |
| 1128 | 'includeContent' => true |
| 1129 | ], |
| 1130 | 'tripadvisorProvider' => [ |
| 1131 | 'heading' => __('Upgrade to Pro to display TripAdvisor reviews', 'reviews-feed'), |
| 1132 | 'description' => __('Upgrade to our "Elite" tier to display reviews from the well known travel advice site.', 'reviews-feed'), |
| 1133 | 'image' => 'upsell-tripadvisor.png', |
| 1134 | 'buttons' => [ |
| 1135 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=tripadvisor-modal&utm_content=LiteUsers50OFF', |
| 1136 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=tripadvisor-modal&utm_content=Upgrade' |
| 1137 | ], |
| 1138 | 'includeContent' => true |
| 1139 | ], |
| 1140 | 'wordpress.orgProvider' => [ |
| 1141 | 'heading' => __('Upgrade to Pro to display WordPress.org reviews', 'reviews-feed'), |
| 1142 | 'description' => __('Upgrade to our "Elite" tier to display reviews for plugins and themes.', 'reviews-feed'), |
| 1143 | 'image' => 'upsell-wordpress.org.png', |
| 1144 | 'buttons' => [ |
| 1145 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=wordpressorg-modal&utm_content=LiteUsers50OFF', |
| 1146 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=wordpressorg-modal&utm_content=Upgrade' |
| 1147 | ], |
| 1148 | 'includeContent' => true |
| 1149 | ], |
| 1150 | 'woocommerceProvider' => [ |
| 1151 | 'heading' => __('Upgrade to Pro to display WooCommerce reviews', 'reviews-feed'), |
| 1152 | 'description' => __('Upgrade to our "Plus" tier to display product reviews from your WooCommerce store.', 'reviews-feed'), |
| 1153 | 'image' => 'upsell-woocommerce.png', |
| 1154 | 'buttons' => [ |
| 1155 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=woocommerce-modal&utm_content=LiteUsers50OFF', |
| 1156 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=woocommerce-modal&utm_content=Upgrade' |
| 1157 | ], |
| 1158 | 'includeContent' => true |
| 1159 | ], |
| 1160 | 'eddProvider' => [ |
| 1161 | 'heading' => __('Upgrade to Pro to display Easy Digital Downloads reviews', 'reviews-feed'), |
| 1162 | 'description' => __('Upgrade to our "Plus" tier to display download reviews from your EDD store.', 'reviews-feed'), |
| 1163 | 'image' => 'upsell-woocommerce.png', |
| 1164 | 'buttons' => [ |
| 1165 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=edd-modal&utm_content=LiteUsers50OFF', |
| 1166 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=edd-modal&utm_content=Upgrade' |
| 1167 | ], |
| 1168 | 'includeContent' => true |
| 1169 | ], |
| 1170 | 'airbnbProvider' => [ |
| 1171 | 'heading' => __('Upgrade to Pro to display Airbnb reviews', 'reviews-feed'), |
| 1172 | 'description' => __('Upgrade to our "Plus" tier to display reviews from the popular accommodation platform.', 'reviews-feed'), |
| 1173 | 'image' => 'upsell-airbnb.png', |
| 1174 | 'buttons' => [ |
| 1175 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=airbnb-modal&utm_content=LiteUsers50OFF', |
| 1176 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=airbnb-modal&utm_content=Upgrade' |
| 1177 | ], |
| 1178 | 'includeContent' => true |
| 1179 | ], |
| 1180 | 'bookingProvider' => [ |
| 1181 | 'heading' => __('Upgrade to Pro to display Booking.com reviews', 'reviews-feed'), |
| 1182 | 'description' => __('Upgrade to our "Plus" tier to display reviews from the leading travel booking site.', 'reviews-feed'), |
| 1183 | 'image' => 'upsell-booking.png', |
| 1184 | 'buttons' => [ |
| 1185 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=booking-modal&utm_content=LiteUsers50OFF', |
| 1186 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=booking-modal&utm_content=Upgrade' |
| 1187 | ], |
| 1188 | 'includeContent' => true |
| 1189 | ], |
| 1190 | 'aliexpressProvider' => [ |
| 1191 | 'heading' => __('Upgrade to Pro to display AliExpress reviews', 'reviews-feed'), |
| 1192 | 'description' => __('Upgrade to our "Plus" tier to display product reviews from the global marketplace.', 'reviews-feed'), |
| 1193 | 'image' => 'upsell-aliexpress.png', |
| 1194 | 'buttons' => [ |
| 1195 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=aliexpress-modal&utm_content=LiteUsers50OFF', |
| 1196 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=aliexpress-modal&utm_content=Upgrade' |
| 1197 | ], |
| 1198 | 'includeContent' => true |
| 1199 | ], |
| 1200 | 'carouselModal' => [ |
| 1201 | 'heading' => __('Upgrade to Pro to get Carousel layout', 'reviews-feed'), |
| 1202 | 'description' => __('An eye-catching rotating slider of your videos to add extra content in minimal space on your website.', 'reviews-feed'), |
| 1203 | 'image' => 'upsell-carousel.png', |
| 1204 | 'buttons' => [ |
| 1205 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=carousel-modal&utm_content=LiteUsers50OFF', |
| 1206 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=carousel-modal&utm_content=Upgrade' |
| 1207 | ], |
| 1208 | 'includeContent' => true |
| 1209 | ], |
| 1210 | 'moreReviewsModal' => [ |
| 1211 | 'heading' => __('Upgrade to Pro to display more reviews', 'reviews-feed'), |
| 1212 | 'description' => __('More layout settings to customize the look and feel of your reviews even more.', 'reviews-feed'), |
| 1213 | 'image' => 'upsell-morereviews.png', |
| 1214 | 'buttons' => [ |
| 1215 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=num-reviews-modal&utm_content=LiteUsers50OFF', |
| 1216 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=num-reviews-modal&utm_content=Upgrade' |
| 1217 | ], |
| 1218 | 'includeContent' => true |
| 1219 | ], |
| 1220 | 'averageRatingModal' => [ |
| 1221 | 'heading' => __('Upgrade to Pro to display average rating', 'reviews-feed'), |
| 1222 | 'description' => __('Boost social proof to make more sales conversions with the number of ratings and an average rating.', 'reviews-feed'), |
| 1223 | 'image' => 'upsell-averagerating.png', |
| 1224 | 'buttons' => [ |
| 1225 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=average-rating-modal&utm_content=LiteUsers50OFF', |
| 1226 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=average-rating-modal&utm_content=Upgrade' |
| 1227 | ], |
| 1228 | 'includeContent' => true |
| 1229 | ], |
| 1230 | 'loadMoreModal' => [ |
| 1231 | 'heading' => __('Upgrade to Pro to add load more functionality', 'reviews-feed'), |
| 1232 | 'description' => __('Overwhelm (in a good way) your visitors with additional reviews loaded on the page with a click.', 'reviews-feed'), |
| 1233 | 'image' => 'upsell-loadmore.png', |
| 1234 | 'buttons' => [ |
| 1235 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=load-more-modal&utm_content=LiteUsers50OFF', |
| 1236 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=load-more-modal&utm_content=Upgrade' |
| 1237 | ], |
| 1238 | 'includeContent' => true |
| 1239 | ], |
| 1240 | 'reviewsMediaModal' => [ |
| 1241 | 'heading' => __('Upgrade to Pro to add images', 'reviews-feed'), |
| 1242 | 'description' => __('Display images from Yelp and Tripadvisor reviews.', 'reviews-feed'), |
| 1243 | 'image' => 'upsell-reviewsmedia.png', |
| 1244 | 'buttons' => [ |
| 1245 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=lite-upgrade-footer-coupon&utm_content=LiteUsers50OFF', |
| 1246 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=template-modal&utm_content=Upgrade' |
| 1247 | ], |
| 1248 | 'includeContent' => true |
| 1249 | ], |
| 1250 | 'authorImageModal' => [ |
| 1251 | 'heading' => __('Upgrade to Pro to display author images', 'reviews-feed'), |
| 1252 | 'description' => __('Build brand trust with positive reviews from real customers.', 'reviews-feed'), |
| 1253 | 'image' => 'upsell-authorimage.png', |
| 1254 | 'buttons' => [ |
| 1255 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=author-avatar-modal&utm_content=LiteUsers50OFF', |
| 1256 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=author-avatar-modal&utm_content=Upgrade' |
| 1257 | ], |
| 1258 | 'includeContent' => true |
| 1259 | ], |
| 1260 | 'filtersModal' => [ |
| 1261 | 'heading' => __('Upgrade to Pro to filter your reviews', 'reviews-feed'), |
| 1262 | 'description' => __('Show only the most positive reviews and build brand trust with review filtering.', 'reviews-feed'), |
| 1263 | 'image' => 'upsell-filters.png', |
| 1264 | 'buttons' => [ |
| 1265 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=star-filter-modal&utm_content=LiteUsers50OFF', |
| 1266 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=star-filter-modal&utm_content=Upgrade' |
| 1267 | ], |
| 1268 | 'includeContent' => true |
| 1269 | ], |
| 1270 | 'moderationModal' => [ |
| 1271 | 'heading' => __('Upgrade to Pro to moderate your reviews', 'reviews-feed'), |
| 1272 | 'description' => __('Take complete control of what reviews show in the feed using keyword filters and a visual moderation system.', 'reviews-feed'), |
| 1273 | 'image' => 'upsell-moderation.png', |
| 1274 | 'buttons' => [ |
| 1275 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=moderation-modal&utm_content=LiteUsers50OFF', |
| 1276 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=moderation-modal&utm_content=Upgrade' |
| 1277 | ], |
| 1278 | 'includeContent' => true |
| 1279 | ], |
| 1280 | 'templateModal' => [ |
| 1281 | 'heading' => __('Upgrade to Pro to get one-click templates!', 'reviews-feed'), |
| 1282 | 'description' => __('Quickly create and preview new feeds with pre-configured options based on popular feed types.', 'reviews-feed'), |
| 1283 | 'image' => 'upsell-template.png', |
| 1284 | 'buttons' => [ |
| 1285 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=template-modal&utm_content=LiteUsers50OFF', |
| 1286 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=template-modal&utm_content=Upgrade' |
| 1287 | ], |
| 1288 | 'includeContent' => true |
| 1289 | ], |
| 1290 | 'responsiveModal' => [ |
| 1291 | 'heading' => __('Upgrade to Pro for responsive layouts', 'reviews-feed'), |
| 1292 | 'description' => __('Take control of your feed layouts by customizing number of reviews & columns', 'reviews-feed'), |
| 1293 | 'image' => 'upsell-responsive.png', |
| 1294 | 'buttons' => [ |
| 1295 | 'lite' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=all-feeds&utm_medium=responsive-modal&utm_content=LiteUsers50OFF', |
| 1296 | 'upgrade' => 'https://smashballoon.com/reviews-feed/reviews-lite-upgrade/?utm_campaign=reviews-free&utm_source=customizer&utm_medium=responsive-modal&utm_content=Upgrade' |
| 1297 | ], |
| 1298 | 'includeContent' => true |
| 1299 | ], |
| 1300 | // Review Alert Upsell Modals |
| 1301 | 'reviewAlertFeature' => [ |
| 1302 | 'heading' => __('Upgrade to Pro for Review Alerts', 'reviews-feed'), |
| 1303 | 'description' => __('Display eye-catching review popups that cycle through your best reviews to boost social proof and conversions.', 'reviews-feed'), |
| 1304 | 'image' => 'upsell-review-alert.png', |
| 1305 | 'buttons' => [ |
| 1306 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-feature-modal&utm_content=LiteUsers50OFF', |
| 1307 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-feature-modal&utm_content=Upgrade' |
| 1308 | ], |
| 1309 | 'includeContent' => true |
| 1310 | ], |
| 1311 | 'reviewAlertRecentReviews' => [ |
| 1312 | 'heading' => __('Upgrade to Pro for Recent Reviews popup', 'reviews-feed'), |
| 1313 | 'description' => __('Cycle through your individual reviews one by one to showcase real customer feedback and build trust.', 'reviews-feed'), |
| 1314 | 'image' => 'upsell-review-alert.png', |
| 1315 | 'buttons' => [ |
| 1316 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-recent-reviews-modal&utm_content=LiteUsers50OFF', |
| 1317 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-recent-reviews-modal&utm_content=Upgrade' |
| 1318 | ], |
| 1319 | 'includeContent' => true |
| 1320 | ], |
| 1321 | 'reviewAlertVariations' => [ |
| 1322 | 'heading' => __('Upgrade to Pro for more popup styles', 'reviews-feed'), |
| 1323 | 'description' => __('Unlock V2 and V3 style variations for your notification popups with unique layouts and designs.', 'reviews-feed'), |
| 1324 | 'image' => 'upsell-review-alert.png', |
| 1325 | 'buttons' => [ |
| 1326 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-variations-modal&utm_content=LiteUsers50OFF', |
| 1327 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-variations-modal&utm_content=Upgrade' |
| 1328 | ], |
| 1329 | 'includeContent' => true |
| 1330 | ], |
| 1331 | 'reviewAlertDarkTheme' => [ |
| 1332 | 'heading' => __('Upgrade to Pro for dark theme popups', 'reviews-feed'), |
| 1333 | 'description' => __('Match your site\'s dark mode with elegant dark-themed notification popups.', 'reviews-feed'), |
| 1334 | 'image' => 'upsell-review-alert.png', |
| 1335 | 'buttons' => [ |
| 1336 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-dark-theme-modal&utm_content=LiteUsers50OFF', |
| 1337 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-dark-theme-modal&utm_content=Upgrade' |
| 1338 | ], |
| 1339 | 'includeContent' => true |
| 1340 | ], |
| 1341 | 'reviewAlertCustomColor' => [ |
| 1342 | 'heading' => __('Upgrade to Pro for custom popup colors', 'reviews-feed'), |
| 1343 | 'description' => __('Customize your popup accent color to perfectly match your brand identity.', 'reviews-feed'), |
| 1344 | 'image' => 'upsell-review-alert.png', |
| 1345 | 'buttons' => [ |
| 1346 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-custom-color-modal&utm_content=LiteUsers50OFF', |
| 1347 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-custom-color-modal&utm_content=Upgrade' |
| 1348 | ], |
| 1349 | 'includeContent' => true |
| 1350 | ], |
| 1351 | 'reviewAlertMultiple' => [ |
| 1352 | 'heading' => __('Upgrade to Pro Plus for multiple popups', 'reviews-feed'), |
| 1353 | 'description' => __('Create unlimited notification popups and display different popups on different pages.', 'reviews-feed'), |
| 1354 | 'image' => 'upsell-review-alert.png', |
| 1355 | 'buttons' => [ |
| 1356 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-multiple-modal&utm_content=LiteUsers50OFF', |
| 1357 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-multiple-modal&utm_content=Upgrade' |
| 1358 | ], |
| 1359 | 'includeContent' => true |
| 1360 | ], |
| 1361 | 'reviewAlertTargeting' => [ |
| 1362 | 'heading' => __('Upgrade to Pro for page targeting', 'reviews-feed'), |
| 1363 | 'description' => __('Control exactly where your notification popups appear with specific page targeting and exclusions.', 'reviews-feed'), |
| 1364 | 'image' => 'upsell-review-alert.png', |
| 1365 | 'buttons' => [ |
| 1366 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-targeting-modal&utm_content=LiteUsers50OFF', |
| 1367 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-targeting-modal&utm_content=Upgrade' |
| 1368 | ], |
| 1369 | 'includeContent' => true |
| 1370 | ], |
| 1371 | 'reviewAlertBranding' => [ |
| 1372 | 'heading' => __('Remove Smash Balloon Branding', 'reviews-feed'), |
| 1373 | 'description' => __('Present a clean, professional look by removing the \'Powered by\' badge from your notification popups.', 'reviews-feed'), |
| 1374 | 'image' => 'upsell-review-alert.png', |
| 1375 | 'buttons' => [ |
| 1376 | 'lite' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-branding-modal&utm_content=LiteUsers50OFF', |
| 1377 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-branding-modal&utm_content=Upgrade', |
| 1378 | 'learnMore' => 'https://smashballoon.com/reviews-feed/?utm_campaign=reviews-free&utm_source=review-alert&utm_medium=popup-branding-modal&utm_content=LearnMore' |
| 1379 | ], |
| 1380 | 'includeContent' => true |
| 1381 | ] |
| 1382 | ]; |
| 1383 | } |
| 1384 | |
| 1385 | /** |
| 1386 | * Get Pro Plus upsell content for Pro users |
| 1387 | * |
| 1388 | * Returns upsell modals for features that require Pro Plus tier. |
| 1389 | * |
| 1390 | * @since 2.5.0 |
| 1391 | * |
| 1392 | * @return array |
| 1393 | */ |
| 1394 | public static function get_pro_plus_upsell_content() |
| 1395 | { |
| 1396 | return [ |
| 1397 | 'reviewAlertMultiple' => [ |
| 1398 | 'heading' => __('Upgrade to Pro Plus for multiple popups', 'reviews-feed'), |
| 1399 | 'description' => __('Create unlimited notification popups and display different popups on different pages.', 'reviews-feed'), |
| 1400 | 'image' => 'upsell-review-alert.png', |
| 1401 | 'buttons' => [ |
| 1402 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-pro&utm_source=review-alert&utm_medium=popup-multiple-modal&utm_content=UpgradeToProPlus' |
| 1403 | ], |
| 1404 | 'includeContent' => false |
| 1405 | ], |
| 1406 | 'reviewAlertTargeting' => [ |
| 1407 | 'heading' => __('Upgrade to Pro Plus for page targeting', 'reviews-feed'), |
| 1408 | 'description' => __('Control exactly where your notification popups appear with specific page targeting and exclusions.', 'reviews-feed'), |
| 1409 | 'image' => 'upsell-review-alert.png', |
| 1410 | 'buttons' => [ |
| 1411 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-pro&utm_source=review-alert&utm_medium=popup-targeting-modal&utm_content=UpgradeToProPlus' |
| 1412 | ], |
| 1413 | 'includeContent' => false |
| 1414 | ], |
| 1415 | 'reviewAlertBranding' => [ |
| 1416 | 'heading' => __('Remove Smash Balloon Branding', 'reviews-feed'), |
| 1417 | 'description' => __('Present a clean, professional look by removing the \'Powered by\' badge from your notification popups.', 'reviews-feed'), |
| 1418 | 'image' => 'upsell-review-alert.png', |
| 1419 | 'buttons' => [ |
| 1420 | 'upgrade' => 'https://smashballoon.com/pricing/reviews-feed/?utm_campaign=reviews-pro&utm_source=review-alert&utm_medium=popup-branding-modal&utm_content=UpgradeToProPlus', |
| 1421 | 'learnMore' => 'https://smashballoon.com/reviews-feed/?utm_campaign=reviews-pro&utm_source=review-alert&utm_medium=popup-branding-modal&utm_content=LearnMore' |
| 1422 | ], |
| 1423 | 'includeContent' => true |
| 1424 | ] |
| 1425 | ]; |
| 1426 | } |
| 1427 | |
| 1428 | /** |
| 1429 | * Get List of Upsell Sidebar Cards |
| 1430 | * |
| 1431 | * @since 1.1 |
| 1432 | * |
| 1433 | * @return array |
| 1434 | */ |
| 1435 | public static function sidebar_upsell_cards() |
| 1436 | { |
| 1437 | if (Util::sbr_is_pro()) { |
| 1438 | return []; |
| 1439 | } |
| 1440 | return [ |
| 1441 | [ |
| 1442 | 'heading' => __('Display images', 'reviews-feed'), |
| 1443 | 'description' => __('With the Pro version enable images like avatars and review photos', 'reviews-feed'), |
| 1444 | 'image' => 'upswidget-images.png', |
| 1445 | 'modal' => 'authorImageModal' |
| 1446 | ], |
| 1447 | [ |
| 1448 | 'heading' => __('Get carousel layout', 'reviews-feed'), |
| 1449 | 'description' => __('Show your reviews in a neat carousel with Review Feed Pro', 'reviews-feed'), |
| 1450 | 'image' => 'upswidget-carousel.png', |
| 1451 | 'modal' => 'carouselModal' |
| 1452 | ], |
| 1453 | [ |
| 1454 | 'heading' => __('Change your feed style with one-click templates!', 'reviews-feed'), |
| 1455 | 'description' => __('Over 12 templates to choose from', 'reviews-feed'), |
| 1456 | 'image' => 'upswidget-templates.png', |
| 1457 | 'modal' => 'templateModal' |
| 1458 | ], |
| 1459 | [ |
| 1460 | 'heading' => __('Only show selected reviews with Moderation mode', 'reviews-feed'), |
| 1461 | 'description' => __('Hide or show only certain reviews', 'reviews-feed'), |
| 1462 | 'image' => 'upswidget-moderation.png', |
| 1463 | 'modal' => 'moderationModal' |
| 1464 | ] |
| 1465 | ]; |
| 1466 | } |
| 1467 | |
| 1468 | |
| 1469 | /** |
| 1470 | * Coerce a review's `provider`, `reviewer` and `source` into the array shapes |
| 1471 | * every reader expects ($review['provider']['name'], $review['reviewer']['name'], |
| 1472 | * $review['source']['id'], …). The relay can emit these as scalars (e.g. |
| 1473 | * `provider` => 'google', or an error-shaped payload yielding a scalar |
| 1474 | * `reviewer`/`source`), and PHP 7-era caches stored them that way in |
| 1475 | * `json_data`. On PHP 8.0+ a direct nested read on a scalar fatals with |
| 1476 | * "Cannot access offset of type string on string". |
| 1477 | * |
| 1478 | * This is the single source of truth used by SinglePostCache (both |
| 1479 | * constructors) and every raw/DB-decoded read site: the dedup key build in |
| 1480 | * PostAggregator::remove_duplicated_posts_list (front-end render, Feed.php:172) |
| 1481 | * reads source['id'] + reviewer['name'] + provider['name'] off the raw post, |
| 1482 | * parse_single_review reads reviewer/provider, and |
| 1483 | * SBR_Feed_Saver_Manager::duplicate_collection reads reviewer/source. |
| 1484 | * |
| 1485 | * SMASH-1578 guarded whole-review + source shapes at the cache loops, SMASH-1587 |
| 1486 | * added provider; this also covers a scalar reviewer/source that the |
| 1487 | * is_array($single_review)-only cache guard lets through to store()/dedup |
| 1488 | * (reachable on WPSA-63160's associative-keyed payload). Healthy array data is |
| 1489 | * left intact — missing keys are filled with empty strings (via array union), |
| 1490 | * so the dedup key degrades to an empty segment instead of crashing. |
| 1491 | * |
| 1492 | * @param mixed $review |
| 1493 | * @return mixed Untouched when not an array (callers' is_array guards handle that). |
| 1494 | */ |
| 1495 | public static function normalize_review_shape($review) |
| 1496 | { |
| 1497 | if (!is_array($review)) { |
| 1498 | return $review; |
| 1499 | } |
| 1500 | |
| 1501 | if (isset($review['provider']) && is_string($review['provider'])) { |
| 1502 | $review['provider'] = ['name' => $review['provider']]; |
| 1503 | } elseif (!isset($review['provider']) || !is_array($review['provider'])) { |
| 1504 | $review['provider'] = ['name' => '']; |
| 1505 | } |
| 1506 | if (!isset($review['reviewer']) || !is_array($review['reviewer'])) { |
| 1507 | $review['reviewer'] = []; |
| 1508 | } |
| 1509 | if (!isset($review['source']) || !is_array($review['source'])) { |
| 1510 | $review['source'] = []; |
| 1511 | } |
| 1512 | // Image containers iterated by resize_images() + add_local_image_urls(). |
| 1513 | // A scalar here would fatal the foreach on PHP 8. Coerce a present |
| 1514 | // non-array to [] (leave absent untouched — they're optional). Element |
| 1515 | // shape is guarded at the loop sites (a flat URL-string element). |
| 1516 | foreach (['media', 'reviews_photos'] as $image_key) { |
| 1517 | if (isset($review[$image_key]) && !is_array($review[$image_key])) { |
| 1518 | $review[$image_key] = []; |
| 1519 | } |
| 1520 | } |
| 1521 | |
| 1522 | // Guarantee the exact keys every reader assumes are present and string, |
| 1523 | // so a scalar/partial provider, reviewer or source degrades to empty |
| 1524 | // segments instead of "Cannot access offset…" fatals or "Undefined array |
| 1525 | // key" notices in the dedup key build / parse_single_review / preview |
| 1526 | // backfill (SMASH-1587 + PR #484 Copilot review + WPSA-63160 follow-up). |
| 1527 | $review['provider'] += ['name' => '']; |
| 1528 | $review['reviewer'] += ['name' => '', 'avatar' => '']; |
| 1529 | $review['source'] += ['id' => '', 'url' => '']; |
| 1530 | if (!is_string($review['provider']['name'])) { |
| 1531 | $review['provider']['name'] = ''; |
| 1532 | } |
| 1533 | if (!is_string($review['reviewer']['name'])) { |
| 1534 | $review['reviewer']['name'] = ''; |
| 1535 | } |
| 1536 | if (!is_string($review['source']['id'])) { |
| 1537 | // Preserve a numeric id (cast), but never (string)-cast an array/object — |
| 1538 | // that would emit an "Array to string conversion" notice (PR #482 Copilot). |
| 1539 | $review['source']['id'] = is_scalar($review['source']['id']) |
| 1540 | ? (string) $review['source']['id'] |
| 1541 | : ''; |
| 1542 | } |
| 1543 | |
| 1544 | return $review; |
| 1545 | } |
| 1546 | |
| 1547 | /** |
| 1548 | * Transform Single Review for storing purposes |
| 1549 | * |
| 1550 | * @since 1.4 |
| 1551 | * |
| 1552 | * @return array |
| 1553 | */ |
| 1554 | public static function parse_single_review($review, $provider_id, $review_id) |
| 1555 | { |
| 1556 | // Provider can arrive as a scalar slug (SMASH-1587); normalize before the |
| 1557 | // $review['provider']['name'] read below so it can't fatal on PHP 8. |
| 1558 | $review = self::normalize_review_shape($review); |
| 1559 | $name = $review['reviewer']['name']; |
| 1560 | $name_array = explode(' ', $name); |
| 1561 | $first_name = isset($review['reviewer']['first_name']) ? $review['reviewer']['first_name'] : $name_array[0]; |
| 1562 | $last_name = isset($review['reviewer']['last_name']) ? $review['reviewer']['last_name'] : (isset($name_array[1]) ? $name_array[1] : ''); |
| 1563 | |
| 1564 | $sanitized_review = [ |
| 1565 | 'time' => $review['time'], |
| 1566 | 'rating' => $review['rating'], |
| 1567 | 'provider_id' => $provider_id, |
| 1568 | 'review_id' => $review_id, |
| 1569 | 'text' => $review['text'], |
| 1570 | 'title' => isset($review['title']) ? $review['title'] : substr($review['text'], 0, 40), |
| 1571 | 'reviewer' => [ |
| 1572 | 'name' => $name, |
| 1573 | 'first_name' => $first_name, |
| 1574 | 'last_name' => $last_name, |
| 1575 | 'avatar' => $review['reviewer']['avatar'] |
| 1576 | ], |
| 1577 | 'provider' => [ |
| 1578 | 'name' => $review['provider']['name'] |
| 1579 | ], |
| 1580 | 'source' => [ |
| 1581 | 'id' => $provider_id, |
| 1582 | 'url' => '' |
| 1583 | ] |
| 1584 | ]; |
| 1585 | return $sanitized_review; |
| 1586 | } |
| 1587 | |
| 1588 | |
| 1589 | public static function is_facebook_collection_post($post) |
| 1590 | { |
| 1591 | return ( isset($post['provider']) && isset($post['provider']['name']) && $post['provider']['name'] === 'facebook' && isset($post['provider_id']) && strpos($post['provider_id'], 'collection') !== false ) === true; |
| 1592 | } |
| 1593 | |
| 1594 | /** |
| 1595 | * Convert Object to Array |
| 1596 | * |
| 1597 | * @return array |
| 1598 | * |
| 1599 | * @since 1.0 |
| 1600 | */ |
| 1601 | public static function object_to_array($data) |
| 1602 | { |
| 1603 | if (is_object($data)) { |
| 1604 | $data = json_decode(json_encode($data), true); |
| 1605 | } |
| 1606 | return $data; |
| 1607 | } |
| 1608 | |
| 1609 | /** |
| 1610 | * Convert Object to Array |
| 1611 | * |
| 1612 | * @return array |
| 1613 | * |
| 1614 | * @since 1.0 |
| 1615 | */ |
| 1616 | public static function get_free_retriever_data() |
| 1617 | { |
| 1618 | if (Util::sbr_is_pro()) { |
| 1619 | $retriever = new \SmashBalloon\Reviews\Pro\Utils\FreeRetriever(); |
| 1620 | } else { |
| 1621 | $retriever = new \SmashBalloon\Reviews\Common\Utils\FreeRetriever(); |
| 1622 | } |
| 1623 | return $retriever->get_settings(); |
| 1624 | } |
| 1625 | |
| 1626 | /** |
| 1627 | * Get Feeds Settings |
| 1628 | * |
| 1629 | * @since 1.0 |
| 1630 | * |
| 1631 | * @return string |
| 1632 | */ |
| 1633 | public static function get_settings_page_errors() |
| 1634 | { |
| 1635 | $output = '## ERROR LOGS: ## </br></br>'; |
| 1636 | $errors = SBR_Error_Handler::get_errors(); |
| 1637 | $errors = array_reverse($errors); |
| 1638 | foreach ($errors as $error) { |
| 1639 | $output .= json_encode($error); |
| 1640 | $output .= '</br></br>'; |
| 1641 | } |
| 1642 | $output .= '</br>'; |
| 1643 | |
| 1644 | return $output; |
| 1645 | } |
| 1646 | |
| 1647 | /** |
| 1648 | * Get Local Images/Avatar |
| 1649 | * Upload folder name |
| 1650 | * |
| 1651 | * @since 2.0 |
| 1652 | * |
| 1653 | * @return string |
| 1654 | */ |
| 1655 | public static function get_upload_folder_name() |
| 1656 | { |
| 1657 | $upload = wp_upload_dir(); |
| 1658 | $folder = trailingslashit($upload['basedir']) . trailingslashit('sbr-feed-images'); |
| 1659 | return $folder; |
| 1660 | } |
| 1661 | |
| 1662 | public static function should_store_local_images() |
| 1663 | { |
| 1664 | $settings = get_option('sbr_settings', sbr_plugin_settings_defaults()); |
| 1665 | if (! is_array($settings)) { |
| 1666 | $settings = sbr_plugin_settings_defaults(); |
| 1667 | } |
| 1668 | return !empty($settings['optimize_images']) ? $settings['optimize_images'] : true; |
| 1669 | } |
| 1670 | |
| 1671 | } |
| 1672 |