--- a/broadstreet/Broadstreet/Config.php
+++ b/broadstreet/Broadstreet/Config.php
@@ -140,4 +140,4 @@
}
}
-define('BROADSTREET_VERSION', '1.52.1');
+define('BROADSTREET_VERSION', '1.52.2');
--- a/broadstreet/broadstreet.php
+++ b/broadstreet/broadstreet.php
@@ -3,8 +3,8 @@
Plugin Name: Broadstreet
Plugin URI: http://broadstreetads.com
Description: Integrate Broadstreet business directory and adserving power into your site
-Version: 1.52.1
-Tested up to: 6.6.1
+Version: 1.52.2
+Tested up to: 6.9
Author: Broadstreet
Author URI: http://broadstreetads.com
*/
--- a/broadstreet/trunk/Broadstreet/Ajax.php
+++ b/broadstreet/trunk/Broadstreet/Ajax.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * This file contains a class which provides the AJAX callback functions required
+ * for Broadstreet.
+ *
+ * @author Broadstreet Ads <labs@broadstreetads.com>
+ */
+
+/**
+ * A class containing functions for the AJAX functionality in Broadstreet. These
+ * aren't executed directly by any Broadstreet code -- they are registered with
+ * the Wordpress hooks in Broadstreet_Core::_registerHooks(), and called as needed
+ * by the front-end and Wordpress. All of these methods output JSON.
+ */
+class Broadstreet_Ajax
+{
+ /**
+ * Save a boolean value of whether to index comments on the next rebuild
+ */
+ public static function saveSettings()
+ {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ // Sanitize the API key before storing it
+ $api_key = sanitize_text_field($_POST['api_key']);
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $api_key);
+
+ // Sanitize network_id as an integer
+ $network_id = isset($_POST['network_id']) ? intval($_POST['network_id']) : -1;
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_NETWORK_ID, $network_id);
+
+ // Sanitize business_enabled as a boolean
+ $business_enabled = ($_POST['business_enabled'] === 'true');
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_BIZ_ENABLED, $business_enabled);
+
+ $api = Broadstreet_Utility::getBroadstreetClient();
+ $message = 'OK';
+
+ try
+ {
+ $networks = $api->getNetworks();
+ $key_valid = true;
+
+ if($network_id == -1)
+ {
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_NETWORK_ID, $networks[0]->id);
+ }
+
+ //Broadstreet_Utility::refreshZoneCache();
+ }
+ catch(Exception $ex)
+ {
+ $networks = array();
+ $key_valid = false;
+ $message = $ex->__toString();
+
+ # Clear any options that aren't valid following the failed API key config
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_BIZ_ENABLED, FALSE);
+ }
+
+ die(json_encode(array('success' => true, 'key_valid' => $key_valid, 'networks' => $networks, 'message' => $message)));
+ }
+
+ /**
+ *
+ */
+ public static function saveZoneSettings()
+ {
+ // Verify nonce (passed as URL parameter) and check user permissions
+ // Note: Using $_GET since nonce is in URL, not in php://input JSON body
+ if (!isset($_GET['nonce']) || !wp_verify_nonce($_GET['nonce'], 'broadstreet_ajax_nonce')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Security check failed')));
+ }
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ $settings = json_decode(file_get_contents("php://input"));
+
+ if($settings)
+ {
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_PLACEMENTS, $settings);
+ $success = true;
+ }
+ else
+ {
+ $success = false;
+ }
+
+ die(json_encode(array('success' => true)));
+ }
+
+ public static function createAdvertiser()
+ {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ $api_key = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_API_KEY);
+ $network_id = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_NETWORK_ID);
+
+ $api = Broadstreet_Utility::getBroadstreetClient();
+ $advertiser = $api->createAdvertiser($network_id, stripslashes($_POST['name']));
+
+ die(json_encode(array('success' => true, 'advertiser' => $advertiser)));
+ }
+
+ public static function getSponsorPostMeta() {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('edit_posts')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ $post_id = isset($_GET['post_id']) ? intval($_GET['post_id']) : 0;
+ die(json_encode(array('success' => true, 'meta' => Broadstreet_Utility::getAllPostMeta($post_id))));
+ }
+
+ public static function importFacebook()
+ {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('edit_posts')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ try
+ {
+ $profile = Broadstreet_Utility::importBusiness($_POST['id'], $_POST['post_id']);
+ die(json_encode(array('success' => (bool)$profile, 'profile' => $profile)));
+ }
+ catch(Broadstreet_ServerException $ex)
+ {
+ die(json_encode(array('success' => false, 'message' => ($ex->error ? $ex->error->message : 'Server error. This issue has been reported to the folks at Broadstreet.'))));
+ }
+ }
+
+ public static function register()
+ {
+ // Verify nonce and check user permissions
+ check_ajax_referer('broadstreet_ajax_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_die(json_encode(array('success' => false, 'message' => 'Unauthorized')));
+ }
+
+ $api = Broadstreet_Utility::getBroadstreetClient(true);
+
+ try
+ {
+ # Register the user by email address
+ $resp = $api->register($_POST['email']);
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_API_KEY, $resp->access_token);
+
+ # Create a network for the new user
+ $resp = $api->createNetwork(get_bloginfo('name'));
+ Broadstreet_Utility::setOption(Broadstreet_Core::KEY_NETWORK_ID, $resp->id);
+
+ die(json_encode(array('success' => true, 'network' => $resp)));
+ }
+ catch(Exception $ex)
+ {
+ die(json_encode(array('success' => false, 'error' => $ex->__toString())));
+ }
+ }
+}
No newline at end of file
--- a/broadstreet/trunk/Broadstreet/Benchmark.php
+++ b/broadstreet/trunk/Broadstreet/Benchmark.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * This file contains a class for measuring performance of the search requests
+ * and internal functionality.
+ *
+ * @author Broadstreet Ads <labs@broadstreetads.com>
+ */
+
+/**
+ * A class for helping to measure and log performance. Essentially, acts as
+ * a easy to use timer
+ */
+class Broadstreet_Benchmark
+{
+ private static $_timers = array();
+
+ /**
+ * Start a timer for a given description. Writes the starting point to the
+ * log automatically.
+ * @param string $timer_description A unique string that describes this timer
+ */
+ public static function start($timer_description = 'Anonymous Timer')
+ {
+ self::$_timers[$timer_description] = microtime(true);
+ Broadstreet_Log::add('info', "Starting benchmark: $timer_description");
+ }
+
+ /**
+ * The name of a timer that has already been started. Writes the stopping
+ * point and result to the log automatically
+ * @param string $timer_description The description of a timer that has
+ * already been started
+ * @return The number of seconds elapsed if the timer exists, false if it
+ * doesn't
+ */
+ public static function stop($timer_description)
+ {
+ if(array_key_exists($timer_description, self::$_timers))
+ {
+ $start = self::$_timers[$timer_description];
+ $stop = microtime(true);
+ $seconds = round($stop - $start, 6);
+
+ Broadstreet_Log::add('info', "Stopped benchmark: $seconds seconds for '$timer_description'");
+ return $seconds;
+ }
+ else
+ {
+ Broadstreet_Log::add('warn', "Unknown benchmark 'stopped': $timer_description");
+ return FALSE;
+ }
+ }
+}
--- a/broadstreet/trunk/Broadstreet/Cache.php
+++ b/broadstreet/trunk/Broadstreet/Cache.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Contains a class for caching things programmatically in Wordpress.
+ * Great for caching things that are a little expensive, like pulling a
+ * Twitter feed or something else.
+ *
+ * Usage:
+ * # $bigthing is some object that took a long time to get/compute with
+ * # get_bigthing. We want to cache it for an hour or so.
+ *
+ * if(!($bigthing = WPEasyCache::get('bigthing', FALSE)))
+ * {
+ * $bigthing = get_bigthing();
+ * WPEasyCache::set('bigthing', $bigthing, 60*60); # Expire in 1 hour
+ * }
+ *
+ * # Do some stuff with $bigthing
+ *
+ * @author Kenny Katzgrau, Katzgrau LLC <kenny@katgrau.com> www.katzgau.com
+ * @link https://github.com/katzgrau/WP-Easy-Cache
+ */
+
+/**
+ * WPEasyCache - A class for quickly caching strings n' things (or any object)
+ * in Wordpress. Uses the Wordpress options functions as the backend.
+ */
+class Broadstreet_Cache
+{
+ const CACHE_PREFIX = 'WPEASYCACHE_';
+ const MAX_KEY_LENGTH = 32;
+
+ private static $_isWPLoaded = FALSE;
+
+ /**
+ * Get an item from the cache by key
+ * @param string $key The name the name of the cache item
+ * @param bool $force Force a value if it exists, even if it's expired
+ * @param mixed $default
+ * @return mixed
+ */
+ public static function get($key, $default = FALSE, $force = FALSE)
+ {
+ $key = self::_prepareKey($key);
+ $value = self::_getOption($key, FALSE);
+
+ # No value at all? return the default
+ if($value === FALSE) return $default;
+
+ # Now we must have a value. Unserialize and check expiration.
+ $value = @json_decode($value);
+
+ # Uh oh, couldn't unserialize
+ if(!is_object($value)) throw new Exception("$key value wasn't decodable.");
+
+ $expire = $value->expire;
+ $value = $value->value;
+
+ # No expiration?
+ if($expire === FALSE) return $value;
+
+ # Expired?
+ if($force || (time() < $expire))
+ return $value;
+ else
+ return $default;
+ }
+
+ /**
+ * Set a cache key item
+ * @param string $key
+ * @param mixed $value
+ * @param int $expire Number of seconds to expire in. Default is no expiration (FALSE)
+ */
+ public static function set($key, $value, $expire = FALSE)
+ {
+ $key = self::_prepareKey($key);
+ $cache = array (
+ 'value' => $value,
+ 'expire' => ($expire === FALSE ? $expire : time() + $expire)
+ );
+
+ $cache = json_encode($cache);
+
+ self::_setOption($key, $cache);
+ }
+
+ public static function delete($key)
+ {
+ throw new Exception("Not implemented yet");
+ }
+
+ public static function flush()
+ {
+ throw new Exception("Not implemented yet");
+ }
+
+ /**
+ * Prepare a string to be used as a cache key
+ * @param string $key
+ */
+ private static function _prepareKey($key)
+ {
+ if(!is_string($key))
+ throw new Exception('Key must be a string');
+
+ $key = preg_replace('/[^a-zA-Z0-9-_.]/s', '#', $key);
+
+ if(strlen($key) > self::MAX_KEY_LENGTH)
+ $key = substr($key, 0, self::MAX_KEY_LENGTH);
+
+ $key = self::CACHE_PREFIX . $key;
+
+ return $key;
+ }
+
+ /**
+ * Sets a Wordpress option
+ * @param string $name The name of the option to set
+ * @param string $value The value of the option to set
+ */
+ private static function _setOption($name, $value)
+ {
+ self::_checkWP();
+
+ if (get_option($name) !== FALSE)
+ {
+ update_option($name, $value);
+ }
+ else
+ {
+ add_option($name, $value);
+ }
+ }
+
+ /**
+ * Gets a Wordpress option
+ * @param string $name The name of the option
+ * @param mixed $default The default value to return if one doesn't exist
+ * @return string The value if the option does exist
+ */
+ private static function _getOption($name, $default = FALSE)
+ {
+ self::_checkWP();
+
+ $value = get_option($name);
+ if( $value !== FALSE ) return $value;
+ return $default;
+ }
+
+ /**
+ * Check to see if Wordpress is laoded, throw an exception if it isn't
+ * @throws Exception
+ */
+ private static function _checkWP()
+ {
+ if(self::$_isWPLoaded) return;
+
+ if(!function_exists('get_option'))
+ throw new Exception ('Wordpress must be fully loaded before using ' . __CLASS__);
+
+ self::$_isWPLoaded = TRUE;
+ }
+
+}
No newline at end of file
--- a/broadstreet/trunk/Broadstreet/Config.php
+++ b/broadstreet/trunk/Broadstreet/Config.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * This file contains a class which holds Broadstreet's configuration information
+ *
+ * @author Broadstreet Ads <labs@broadstreetads.com>
+ */
+
+/**
+ * A class which acts as the source and accessor of all of Broadstreet's configuration
+ * information.
+ */
+class Broadstreet_Config
+{
+ /**
+ * Load up all of Broadstreet's configuration values. This currently where
+ * configuration otpions should be set too..
+ */
+ public function setConfig()
+ {
+ $config = array();
+ # Set config values below
+
+ $config['zone_cache_ttl_seconds'] = 60*10; // 15 minutes
+ $config['network_cache_ttl_seconds'] = 60*30; // 30 minutes
+
+ $config['log'] = array (
+
+ 'level' => Broadstreet_Log::OFF,
+ 'directory' => dirname(__FILE__) . '/Logs'
+
+ );
+
+ # End config
+ $this->_config = $config;
+ }
+
+ /**
+ * The instance of this config class
+ * @var Broadstreet_Config
+ */
+ private static $_instance = NULL;
+
+ /**
+ * The config array for this class
+ * @var array
+ */
+ private $_config = NULL;
+
+ /**
+ * The constructor for this class
+ */
+ public function __construct()
+ {
+ $this->setConfig();
+ }
+
+ /**
+ * Set a configuration value
+ * @param string $key The key to store the variable as
+ * @param string $value The value to store for the key
+ * @return mixed The value that was set
+ */
+ public static function set($key, $value)
+ {
+ return self::_getInstance()->setValue($key, $value);
+ }
+
+ /**
+ *
+ * @param string $key The key of the config value to retrieve. If the
+ * config item is nested in subarrays, you can use dot-separated strings
+ * to specifykey items. For example, given a config setup like:
+ *
+ * $config['example-config'] = array (
+ * 'test' = array (
+ * port => '12345',
+ * host => 'localhost'
+ * )
+ * )
+ *
+ * I could use Broadstreet_Config::get('example-config.test.port') to get
+ * the port.
+ * @param string $default A value to return if the key wasn't found
+ * @return string The configuration value
+ */
+ public static function get($key = FALSE, $default = FALSE)
+ {
+ return self::_getInstance()->getValue($key, $default);
+ }
+
+ /**
+ * Set an internal config value. This is not meant to be called directly
+ * outside of this class.
+ * @param string $key The key to store the variable as
+ * @param string $value The value to store for the key
+ * @return mixed The value that was set
+ */
+ public function setValue($key, $value)
+ {
+ return $this->_config[$key] = $value;
+ }
+
+ /**
+ * The internal method for getting a config value. This method is not meant
+ * to be accessed directly outside of this class, so use Broadstreet_Config::get()
+ * instead.
+ * @param string $key The config value name
+ * @param string $default A value to return if the key wasn't found
+ * @return string The configuration value
+ */
+ public function getValue($key = FALSE, $default = FALSE)
+ {
+ if($key === FALSE)
+ return $this->_config;
+
+ $config = $this->_config;
+ $keys = explode('.', $key);
+
+ foreach($keys as $key)
+ {
+ if(array_key_exists($key, $config))
+ $config = $config[$key];
+ else
+ return $default;
+ }
+
+ return $config;
+ }
+
+ /**
+ * Return the instance of this class
+ * @return Broadstreet_Config
+ */
+ private static function _getInstance()
+ {
+ if(self::$_instance === NULL)
+ self::$_instance = new self();
+
+ return self::$_instance;
+ }
+}
+
+define('BROADSTREET_VERSION', '1.52.2');
--- a/broadstreet/trunk/Broadstreet/Core.php
+++ b/broadstreet/trunk/Broadstreet/Core.php
@@ -0,0 +1,1516 @@
+<?php
+/**
+ * This file acts as the 'Controller' of the application. It contains a class
+ * that will load the required hooks, and the callback functions that those
+ * hooks execute.
+ *
+ * @author Broadstreet Ads <labs@broadstreetads.com>
+ */
+
+require_once dirname(__FILE__) . '/Ajax.php';
+require_once dirname(__FILE__) . '/Cache.php';
+require_once dirname(__FILE__) . '/Config.php';
+require_once dirname(__FILE__) . '/Benchmark.php';
+require_once dirname(__FILE__) . '/Log.php';
+require_once dirname(__FILE__) . '/Model.php';
+require_once dirname(__FILE__) . '/Net.php';
+require_once dirname(__FILE__) . '/Utility.php';
+require_once dirname(__FILE__) . '/View.php';
+require_once dirname(__FILE__) . '/Widget.php';
+require_once dirname(__FILE__) . '/Exception.php';
+require_once dirname(__FILE__) . '/Vendor/Broadstreet.php';
+
+if (! class_exists('Broadstreet_Core')):
+
+/**
+ * This class contains the core code and callback for the behavior of Wordpress.
+ * It is instantiated and executed directly by the Broadstreet plugin loader file
+ * (which is most likely at the root of the Broadstreet installation).
+ */
+class Broadstreet_Core
+{
+ CONST KEY_API_KEY = 'Broadstreet_API_Key';
+ CONST KEY_NETWORK_ID = 'Broadstreet_Network_Key';
+ CONST KEY_BIZ_ENABLED = 'Broadstreet_Biz_Enabled';
+ CONST KEY_INSTALL_REPORT = 'Broadstreet_Installed';
+ CONST KEY_SHOW_OFFERS = 'Broadstreet_Offers';
+ CONST KEY_PLACEMENTS = 'Broadstreet_Placements';
+ CONST BIZ_POST_TYPE = 'bs_business';
+ CONST BIZ_TAXONOMY = 'business_category';
+ CONST BIZ_SLUG = 'businesses';
+
+ public static $_disableAds = false;
+ public static $_rssCount = 0;
+ public static $_rssIndex = 0;
+
+ /**
+ * Default values for sponsored meta fields
+ */
+ public static $_sponsoredDefaults = array (
+ 'bs_sponsor_advertiser_id' => '',
+ 'bs_sponsor_advertisement_id' => '',
+ 'bs_sponsor_is_sponsored' => ''
+ );
+
+ /**
+ * Default values for sponsored meta fields
+ */
+ public static $_visibilityDefaults = array (
+ 'bs_ads_disabled' => ''
+ );
+
+ /**
+ * Default values for the businesses meta fields
+ * @var type
+ */
+ public static $_businessDefaults = array (
+ 'bs_advertiser_id' => '',
+ 'bs_advertisement_id' => '',
+ 'bs_advertisement_html' => '',
+ 'bs_update_source' => '',
+ 'bs_facebook_id' => '',
+ 'bs_facebook_hashtag' => '',
+ 'bs_twitter_id' => '',
+ 'bs_twitter_hashtag' => '',
+ 'bs_phone_number' => '',
+ 'bs_address_1' => '',
+ 'bs_address_2' => '',
+ 'bs_city' => '',
+ 'bs_state' => '',
+ 'bs_postal' => '',
+ 'bs_latitude' => '',
+ 'bs_longitude' => '',
+ 'bs_phone' => '',
+ 'bs_hours' => '',
+ 'bs_website' => '',
+ 'bs_menu' => '',
+ 'bs_publisher_review' => '',
+ 'bs_twitter' => '',
+ 'bs_facebook' => '',
+ 'bs_gplus' => '',
+ 'bs_images' => array(),
+ 'bs_yelp' => '',
+ 'bs_video' => '',
+ 'bs_offer' => '',
+ 'bs_offer_link' => '',
+ 'bs_monday_open' => '', 'bs_monday_close' => '',
+ 'bs_tuesday_open' => '', 'bs_tuesday_close' => '',
+ 'bs_wednesday_open' => '', 'bs_wednesday_close' => '',
+ 'bs_thursday_open' => '', 'bs_thursday_close' => '',
+ 'bs_friday_open' => '', 'bs_friday_close' => '',
+ 'bs_saturday_open' => '', 'bs_saturday_close' => '',
+ 'bs_sunday_open' => '', 'bs_sunday_close' => '',
+ 'bs_featured_business' => '0'
+ );
+
+ public static $globals = null;
+
+ /**
+ * The constructor
+ */
+ public function __construct()
+ {
+ Broadstreet_Log::add('debug', "Broadstreet initializing..");
+ }
+
+ /**
+ * Get the Broadstreet environment loaded and register Wordpress hooks
+ */
+ public function execute()
+ {
+ $this->_registerHooks();
+ }
+
+ /**
+ * Get a Broadstreet client
+ */
+ public function getBroadstreetClient()
+ {
+ return Broadstreet_Utility::getBroadstreetClient();
+ }
+
+ /**
+ * Register Wordpress hooks required for Broadstreet
+ */
+ private function _registerHooks()
+ {
+ Broadstreet_Log::add('debug', "Registering hooks..");
+
+ # -- Below is core functionality --
+ add_action('admin_menu', array($this, 'adminCallback' ));
+ add_action('admin_enqueue_scripts', array($this, 'adminStyles'));
+ add_action('admin_init', array($this, 'adminInitCallback' ));
+ add_action('wp_enqueue_scripts', array($this, 'addCDNScript' ));
+ add_filter('script_loader_tag', array($this, 'finalizeZoneTag' ));
+ add_action('init', array($this, 'businessIndexSidebar' ));
+ add_action('admin_notices', array($this, 'adminWarningCallback'));
+ add_action('widgets_init', array($this, 'registerWidget'));
+ add_shortcode('broadstreet', array($this, 'shortcode'));
+ add_filter('image_size_names_choose', array($this, 'addImageSizes'));
+ add_action('wp_footer', array($this, 'addPoweredBy'));
+ # -- Ad injection
+ add_action('wp_body_open', array($this, 'addAdsPageTop' ));
+ add_filter('the_content', array($this, 'addAdsContent'), 20);
+ add_filter('the_content_feed', array($this, 'addRSSMacros'), 20);
+ add_action('loop_end', array($this, 'addAdsLoopEnd'), 20);
+ #add_action('comment_form_before', array($this, 'addAdsBeforeComments'), 1);
+ add_filter('comments_template', array($this, 'addAdsBeforeComments'), 20);
+
+ if (Broadstreet_Utility::getOption(self::KEY_API_KEY)) {
+ add_action('post_updated', array($this, 'saveSponsorPostMeta'), 20);
+ add_action('transition_post_status', array($this, 'monitorForScheduledPostStatus'), 20, 10, 3);
+ }
+
+ add_action('post_updated', array($this, 'saveAdVisibilityMeta'), 20);
+
+ // only fires on newspack
+ add_action('get_template_part_template-parts/header/entry', array($this, 'addNewspackAfterTitleAd'));
+ add_action('after_header', array($this, 'addNewspackHeaderAd'));
+ add_action('before_footer', array($this, 'addNewspackFooterAd'));
+ add_filter('rest_pre_echo_response', array($this, 'addNewspackNewsletterMeta'));
+
+ // only fires on wpp
+ // add_action('get_template_part_loop-templates/content-single-camp', array($this, 'getTrackerContent'));
+
+ # -- Below are all business-related hooks
+ if(Broadstreet_Utility::isBusinessEnabled())
+ {
+ add_action('init', array($this, 'createPostTypes'));
+ add_action('wp_enqueue_scripts', array($this, 'addPostStyles'));
+ add_action('pre_get_posts', array($this, 'modifyPostListing'));
+ add_filter('the_content', array($this, 'postTemplate'), 20);
+ add_filter('the_posts', array($this, 'businessQuery'));
+ add_filter('comment_form_defaults', array($this, 'commentForm'));
+ add_action('save_post', array($this, 'savePostMeta'));
+ add_shortcode('businesses', array($this, 'businesses_shortcode'));
+ }
+
+ # - Below are partly business-related
+ add_action('add_meta_boxes', array($this, 'addMetaBoxes'));
+
+ # RSS Zones, 1.0 and 2.0
+ add_action('rss2_item', array($this, 'addRSSZone'));
+ add_action('rss_item', array($this, 'addRSSZone'));
+
+
+
+ # -- Below is administration AJAX functionality
+ add_action('wp_ajax_bs_save_settings', array('Broadstreet_Ajax', 'saveSettings'));
+ add_action('wp_ajax_create_advertiser', array('Broadstreet_Ajax', 'createAdvertiser'));
+ add_action('wp_ajax_import_facebook', array('Broadstreet_Ajax', 'importFacebook'));
+ add_action('wp_ajax_register', array('Broadstreet_Ajax', 'register'));
+ add_action('wp_ajax_save_zone_settings', array('Broadstreet_Ajax', 'saveZoneSettings'));
+ add_action('wp_ajax_get_sponsored_meta', array('Broadstreet_Ajax', 'getSponsorPostMeta'));
+
+ add_action('rest_api_init', function () {
+ # /wp-json/broadstreet/v1/targets
+ register_rest_route('broadstreet/v1', '/targets', array(
+ 'methods' => 'GET',
+ 'callback' => function($request) {
+ return Broadstreet_Utility::getAvailableTargets();
+ },
+ 'permission_callback' => '__return_true', # public
+ ));
+
+ # /wp-json/broadstreet/v1/refresh
+ register_rest_route('broadstreet/v1', '/refresh', array(
+ 'methods' => 'GET',
+ 'callback' => function($request) {
+ $info = Broadstreet_Utility::getNetwork(true);
+ return [
+ 'success' => $info ? true : false
+ ];
+ },
+ 'permission_callback' => '__return_true', #public
+ ));
+ });
+ }
+
+
+ public function getTrackerContent($content = '') {
+ $code = Broadstreet_Utility::getTrackerCode();
+
+ if (!strstr($content, 'template-parts/')) {
+ return $content . $code;
+ } else {
+ echo $code;
+ return;
+ }
+ }
+
+ public function addRSSZone() {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ $home_url = get_home_url();
+
+ $in_rss_feed = property_exists($placement_settings, 'in_rss_feed') && $placement_settings->in_rss_feed;
+ if ($in_rss_feed) {
+ $rss_interval = intval($placement_settings->in_rss_feed_interval);
+ if (!$rss_interval) {
+ $rss_interval = 1;
+ }
+
+ $index = self::$_rssIndex;
+ $time = time();
+
+ if ((self::$_rssCount + 1) % $rss_interval == 0) {
+ echo "<source url="$home_url"><![CDATA[{$index}?ds=true&seed=$time]]></source>";
+ self::$_rssIndex++;
+ } else {
+ $index = '-1';
+ echo "<source url="$home_url"><![CDATA[{$index}?ds=true&seed=$time]]></source>";
+ }
+
+ self::$_rssCount++;
+ }
+ }
+
+ public function addNewspackNewsletterMeta($data) {
+ if (is_array($data) && isset($data['mjml'])) {
+ $cachebuster = time();
+ $data['mjml'] = preg_replace('/BROADSTREET_RANDOM/i', $cachebuster, $data['mjml']);
+ }
+ return $data;
+ }
+
+ public function addNewspackAfterTitleAd() {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (property_exists($placement_settings, 'newspack_before_title') && $placement_settings->newspack_before_title) {
+ echo Broadstreet_Utility::getZoneCode($placement_settings->newspack_before_title);
+ }
+ }
+
+ public function addNewspackHeaderAd($slug) {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (property_exists($placement_settings, 'newspack_after_header') && $placement_settings->newspack_after_header) {
+ $padding = '25';
+ if (property_exists($placement_settings, 'newspack_after_header_padding') && $placement_settings->newspack_after_header_padding) {
+ $padding = $placement_settings->newspack_after_header_padding;
+ }
+ echo '<section class="newspack-broadstreet-header" style="text-align:center; padding: ' . $padding . 'px;">' . Broadstreet_Utility::getZoneCode($placement_settings->newspack_after_header) . '</section>';
+ }
+ }
+
+ public function addNewspackFooterAd($slug) {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (property_exists($placement_settings, 'newspack_before_footer') && $placement_settings->newspack_before_footer) {
+ $padding = '25';
+ if (property_exists($placement_settings, 'newspack_before_footer_padding') && $placement_settings->newspack_before_footer_padding) {
+ $padding = $placement_settings->newspack_before_footer_padding;
+ }
+ echo '<section class="newspack-broadstreet-footer" style="text-align:center; padding: ' . $padding . 'px;">' . Broadstreet_Utility::getZoneCode($placement_settings->newspack_before_footer) . '</section>';
+ }
+ }
+
+ public function addAdsPageTop() {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (property_exists($placement_settings, 'above_page') && $placement_settings->above_page) {
+ echo Broadstreet_Utility::getZoneCode($placement_settings->above_page);
+ }
+
+ if (property_exists($placement_settings, 'amp_sticky') && $placement_settings->amp_sticky) {
+ echo "<amp-sticky-ad layout='nodisplay'>" . Broadstreet_Utility::getZoneCode($placement_settings->amp_sticky, array('layout' => false)) . "</amp-sticky-ad>";
+ }
+
+ }
+
+ public function addRSSMacros($content) {
+ $content = str_replace('%%timestamp%%', time(), $content);
+ return $content;
+ }
+
+ public function addAdsContent($content) {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ $above_content = property_exists($placement_settings, 'above_content') && $placement_settings->above_content;
+ $below_content = property_exists($placement_settings, 'below_content') && $placement_settings->below_content;
+ $in_content = property_exists($placement_settings, 'in_content') && $placement_settings->in_content;
+
+ $content = str_replace('%%timestamp%%', time(), $content);
+
+ if (is_single()) {
+
+ if ($in_content) {
+
+ $in_content_paragraph = property_exists($placement_settings, 'in_content_paragraph') ? $placement_settings->in_content_paragraph : '4';
+ if (!$in_content_paragraph) {
+ $in_content_paragraph = '4';
+ }
+
+ try {
+ $in_content_paragraph = array_map('intval', array_map('trim', explode(',', $in_content_paragraph)));
+ } catch (Exception $e) {
+ // user error
+ $in_content_paragraph = array(4);
+ }
+
+ /* Now handle in-content */
+ if (!stristr($content, '[broadstreet zone') && !stristr($content, '<broadstreet-zone') && !stristr($content, 'broadstreetads')) { # last one is for <amp-ad>
+ /* Split the content into paragraphs, clear out anything that is only whitespace */
+ /* The first lookbehind makes sure we don't match empty paragraphs,
+ the last lookahead makes sure we don't match special blocks that wrap a paragraph */
+ $pieces = preg_split('#(?<!<p>)</p>(?!s*</div>)#', $content);
+
+ if (count($pieces) <= 1 && ($above_content || $below_content)) {
+ # One paragraph
+ #return "$contentnn" . $in_story_zone;
+ }
+
+ # each insertion increases the offset of the next paragraph
+ $replacements = 0;
+ for ($i = 0; $i < count($in_content_paragraph); $i++) {
+ $in_story_zone = Broadstreet_Utility::getWrappedZoneCode($placement_settings, apply_filters('bs_ads_in_content_zone_id', $placement_settings->in_content), array('place' => $i));
+ if ((count($pieces) - $replacements) > $in_content_paragraph[$i]) {
+ array_splice($pieces, $in_content_paragraph[$i] + $replacements++, 0, "</p>" . $in_story_zone);
+ }
+ }
+ /* It's magic, :snort: :snort:
+ - Mr. Bean: https://www.youtube.com/watch?v=x0yQg8kHVcI */
+ $content = implode("nn", $pieces);
+ }
+
+ }
+
+ if ($above_content) {
+ $content = Broadstreet_Utility::getWrappedZoneCode($placement_settings, $placement_settings->above_content) . $content;
+ }
+
+ if ($below_content) {
+ $content = $content . Broadstreet_Utility::getWrappedZoneCode($placement_settings, $placement_settings->below_content);
+ }
+ }
+
+ $content = $this->getTrackerContent($content);
+
+ return $content;
+ }
+
+ public function addAdsBeforeComments($template) {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (is_single()) {
+ if (property_exists($placement_settings, 'before_comments') && $placement_settings->before_comments) {
+ echo Broadstreet_Utility::getMaxWidthWrap($placement_settings, Broadstreet_Utility::getWrappedZoneCode($placement_settings, $placement_settings->before_comments));
+ }
+ }
+
+ return $template;
+ }
+
+ public function addAdsLoopEnd() {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (is_archive() && in_the_loop()) {
+ if (property_exists($placement_settings, 'inbetween_archive') && $placement_settings->inbetween_archive) {
+ echo Broadstreet_Utility::getMaxWidthWrap($placement_settings, Broadstreet_Utility::getWrappedZoneCode($placement_settings, $placement_settings->inbetween_archive));
+ }
+ }
+ }
+
+ /**
+ * Handler used for creating the business category taxonomy
+ */
+ public function addBusinessTaxonomy() {
+ # Add new "Locations" taxonomy to Posts
+ register_taxonomy(self::BIZ_TAXONOMY, self::BIZ_POST_TYPE, array(
+ # Hierarchical taxonomy (like categories)
+ 'hierarchical' => true,
+ # This array of options controls the labels displayed in the WordPress Admin UI
+ 'labels' => array(
+ 'name' => _x( 'Business Categories', 'taxonomy general name' ),
+ 'singular_name' => _x( 'Business Category', 'taxonomy singular name' ),
+ 'search_items' => __( 'Search Businesses by Category' ),
+ 'all_items' => __( 'All Business Categories' ),
+ 'parent_item' => __( 'Parent Category' ),
+ 'parent_item_colon' => __( 'Parent Category:' ),
+ 'edit_item' => __( 'Edit Business Category' ),
+ 'update_item' => __( 'Update Business Category' ),
+ 'add_new_item' => __( 'Add New Business Category' ),
+ 'new_item_name' => __( 'New Business Category Type' ),
+ 'menu_name' => __( 'Categories' ),
+ ),
+ # Control the slugs used for this taxonomy
+ 'rewrite' => array(
+ 'slug' => 'business-categories', // This controls the base slug that will display before each term
+ 'with_front' => false, // Don't display the category base before "/locations/"
+ 'hierarchical' => true // This will allow URL's like "/locations/boston/cambridge/"
+ ),
+ ));
+ }
+
+ /**
+ * Callback for adding an extra broadstreet-friendly image size
+ * @param array $sizes
+ * @return array
+ */
+ public function addImageSizes($sizes)
+ {
+ $sizes['bs-biz-size'] = __('Broadstreet Business');
+ return $sizes;
+ }
+
+ /**
+ * Handler for adding the Broadstreet business meta data boxes on the post
+ * create/edit page
+ */
+ public function addMetaBoxes()
+ {
+ add_meta_box(
+ 'broadstreet_sectionid',
+ __( 'Broadstreet Zone Info', 'broadstreet_textdomain' ),
+ array($this, 'broadstreetInfoBox'),
+ 'post'
+ );
+
+ add_meta_box(
+ 'broadstreet_sectionid',
+ __( 'Broadstreet Zone Info', 'broadstreet_textdomain'),
+ array($this, 'broadstreetInfoBox'),
+ 'page'
+ );
+
+ $screens = get_post_types();
+ if (Broadstreet_Utility::getOption(self::KEY_API_KEY)) {
+ foreach ( $screens as $screen ) {
+ add_meta_box(
+ 'broadstreet_sposnor_sectionid',
+ __( '<span class="dashicons dashicons-performance"></span> Sponsored Content', 'broadstreet_textdomain'),
+ array($this, 'broadstreetSponsoredBox'),
+ $screen,
+ 'side',
+ 'high'
+ );
+ }
+ }
+
+ foreach ( $screens as $screen ) {
+ add_meta_box(
+ 'broadstreet_visibility_sectionid',
+ __( '<span class="dashicons dashicons-format-image"></span> Broadstreet Options', 'broadstreet_textdomain'),
+ array($this, 'broadstreetAdVisibilityBox'),
+ $screen,
+ 'side'
+ );
+ }
+
+ if(Broadstreet_Utility::isBusinessEnabled())
+ {
+ add_meta_box(
+ 'broadstreet_sectionid',
+ __( 'Business Details', 'broadstreet_textdomain'),
+ array($this, 'broadstreetBusinessBox'),
+ self::BIZ_POST_TYPE,
+ 'normal'
+ );
+ }
+ }
+
+ public function addPostStyles()
+ {
+ if(get_post_type() == self::BIZ_POST_TYPE && !is_admin())
+ {
+ wp_enqueue_style ('Broadstreet-styles-listings', Broadstreet_Utility::getCSSBaseURL() . 'listings.css?v=' . BROADSTREET_VERSION);
+ }
+ }
+
+ // Update CSS within in Admin
+ function adminStyles() {
+ wp_enqueue_style('broadstreet-admin-styles', Broadstreet_Utility::getCSSBaseURL() . 'admin.css');
+ }
+
+ /**
+ * Add powered-by notice
+ */
+ public function addPoweredBy()
+ {
+ if (self::$_disableAds || Broadstreet_Utility::isAMPEndpoint()) {
+ return;
+ }
+
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (!property_exists($placement_settings, 'load_in_head')
+ || !$placement_settings->load_in_head) {
+ $code = Broadstreet_Utility::getInitCode();
+ echo "<script data-cfasync='false'>$code</script>";
+ }
+ }
+
+ public function writeInitCode()
+ {
+ $code = '';
+
+ # while we're in the post, capture the disabled status of the ads
+ if (is_singular()) {
+ self::$_disableAds = Broadstreet_Utility::getPostMeta(get_queried_object_id(), 'bs_ads_disabled') == '1';
+ }
+
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ if (property_exists($placement_settings, 'use_old_tags') && $placement_settings->use_old_tags) {
+ if (property_exists($placement_settings, 'cdn_whitelabel') && strlen($placement_settings->adserver_whitelabel) > 0) {
+ $code .= "broadstreet.setWhitelabel('//{$placement_settings->adserver_whitelabel}/');";
+ }
+ }
+
+ if (self::$_disableAds) {
+ return;
+ }
+
+ if (property_exists($placement_settings, 'load_in_head')
+ && $placement_settings->load_in_head) {
+ $code .= Broadstreet_Utility::getInitCode();
+ }
+
+ wp_add_inline_script('broadstreet-init', "$code", 'after');
+ }
+
+ /**
+ * Manipulate our cdn tags to include anti-cloudflare stuff, because they think they own
+ * all of the internet's javascript
+ * @param $tag
+ * @param string $handle
+ * @param bool $src
+ * @return mixed
+ */
+ public function finalizeZoneTag($tag, $handle = '', $src = false)
+ {
+ if (is_admin()) {
+ return $tag;
+ }
+
+ // add cloudflare attrs. but seriously, f cloudflare
+ if (strstr($tag, 'broadstreet-init')) {
+ $tag = str_replace('<script', "<script async data-cfasync='false'", $tag);
+ }
+
+ return $tag;
+ }
+
+ public function addCDNScript()
+ {
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+
+ $old = false;
+ if (property_exists($placement_settings, 'use_old_tags') && $placement_settings->use_old_tags) {
+ $old = true;
+ }
+
+ # Add Broadstreet ad zone CDN
+ if(!is_admin() && !Broadstreet_Utility::isAMPEndpoint())
+ {
+ $file = 'init-2.min.js?v=' . BROADSTREET_VERSION;
+ if ($old) {
+ $file = 'init.js';
+ }
+
+ $placement_settings = Broadstreet_Utility::getPlacementSettings();
+ $host = 'cdn.broadstreetads.com';
+ if (property_exists($placement_settings, 'cdn_whitelabel') && strlen($placement_settings->cdn_whitelabel) > 0) {
+ $host = $placement_settings->cdn_whitelabel;
+ }
+ # except for cdn whitelabels
+ # if (is_ssl() && property_exists($placement_settings, 'cdn_whitelabel') && $placement_settings->cdn_whitelabel) {
+ # $host = 'street-production.s3.amazonaws.com';
+ # }
+
+ # For site-wide analytics.
+ $adserver_host = 'flux.broadstreet.ai';
+ if (property_exists($placement_settings, 'adserver_whitelabel') && strlen($placement_settings->adserver_whitelabel) > 0) {
+ $adserver_host = $placement_settings->adserver_whitelabel;
+ }
+ if (property_exists($placement_settings, 'enable_analytics') && strlen($placement_settings->enable_analytics)) {
+ $network_id = Broadstreet_Utility::getOption(Broadstreet_Core::KEY_NETWORK_ID);
+ wp_register_script('broadstreet-analytics', "//$adserver_host/emit/$network_id.js", array(), '1.0.0', array('strategy' => 'async'));
+ wp_enqueue_script('broadstreet-analytics');
+ }
+
+ wp_register_script('broadstreet-init', "//$host/$file");
+ $this->writeInitCode();
+ wp_enqueue_script('broadstreet-init');
+ }
+ }
+
+ public function businessIndexSidebar()
+ {
+ if(Broadstreet_Utility::isBusinessEnabled())
+ {
+ register_sidebar(array(
+ 'name' => __( 'Business Directory Listing Page' ),
+ 'id' => 'businesses-right-sidebar',
+ 'description' => __( 'The right rail displayed in the page when you use the [businesses] shortcode.' ),
+ 'before_widget' => '<div style="padding-bottom: 10px;" id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</div>',
+ 'before_title' => '<h3>',
+ 'after_title' => '</h3>'
+ ));
+ }
+ }
+
+ /**
+ * A callback executed whenever the user tried to access the Broadstreet admin page
+ */
+ public function adminCallback()
+ {
+ $icon_url = 'none';
+
+ add_menu_page('Broadstreet', 'Broadstreet', 'edit_pages', 'Broadstreet', array($this, 'adminMenuCallback'), $icon_url);
+ add_submenu_page('Broadstreet', 'Settings', 'Account Setup', 'edit_pages', 'Broadstreet', array($this, 'adminMenuCallback'));
+ add_submenu_page('Broadstreet', 'Zone Options', 'Zone Options', 'edit_pages', 'Broadstreet-Zone-Options', array($this, 'adminZonesMenuCallback'));
+ if(Broadstreet_Utility::isBusinessEnabled())
+ add_submenu_page('Broadstreet', 'Business Settings', 'Business Settings', 'edit_pages', 'Broadstreet-Business', array($this, 'adminMenuBusinessCallback'));
+ #add_submenu_page('Broadstreet', 'Advanced', 'Advanced', 'edit_pages', 'Broadstreet-Layout', array($this, 'adminMenuLayoutCallback'));
+ if(Broadstreet_Utility::isBusinessEnabled())
+ add_submenu_page('Broadstreet', 'Help', 'Business Directory Help', 'edit_pages', 'Broadstreet-Help', array($this, 'adminMenuHelpCallback'));
+ }
+
+ /**
+ * Emit a warning that the search index hasn't been built (if it hasn't)
+ */
+ public function adminWarningCallback()
+ {
+ if(in_array($GLOBALS['pagenow'], array('edit.php', 'post.php', 'post-new.php')))
+ {
+ $info = Broadstreet_Utility::getNetwork();
+
+ //if(!$info || !$info->cc_on_file)
+ // echo '<div class="updated"><p>You're <strong>almost ready</strong> to start using Broadstreet! Check the <a href="admin.php?page=Broadstreet">plugin page</a> to take care of the last steps. When that's done, this message will clear shortly after.</p></div>';
+
+ // Check for video security warning
+ $security_warning = get_transient('broadstreet_video_security_warning_' . get_current_user_id());
+ if ($security_warning) {
+ echo '<div class="notice notice-error is-dismissible"><p><strong>Broadstreet Security Notice:</strong> Potentially malicious content was detected and removed from the video embed field. JavaScript protocols, event handlers, and script tags are not allowed for security reasons.</p></div>';
+ delete_transient('broadstreet_video_security_warning_' . get_current_user_id());
+ }
+ }
+ }
+
+ /**
+ * A callback executed when the admin page callback is a about to be called.
+ * Use this for loading stylesheets/css.
+ */
+ public function adminInitCallback()
+ {
+ add_image_size('bs-biz-size', 600, 450, true);
+
+ # Only register javascript and css if the Broadstreet admin page is loading
+ if(isset($_SERVER['QUERY_STRING']) && strstr($_SERVER['QUERY_STRING'], 'Broadstreet'))
+ {
+ wp_enqueue_style ('Broadstreet-styles', Broadstreet_Utility::getCSSBaseURL() . 'broadstreet.css?v='. BROADSTREET_VERSION);
+ wp_enqueue_script('Broadstreet-main' , Broadstreet_Utility::getJSBaseURL().'broadstreet.js?v='. BROADSTREET_VERSION);
+ wp_enqueue_script('angular-js', Broadstreet_Utility::getJSBaseURL().'angular.min.js?v='. BROADSTREET_VERSION);
+ wp_enqueue_script('isteven-multi-js', Broadstreet_Utility::getJSBaseURL().'isteven-multi-select.js');
+ wp_enqueue_style ('isteven-multi-css', Broadstreet_Utility::getCSSBaseURL() . 'isteven-multi-select.css');
+
+ // Pass nonce to JavaScript for AJAX security
+ wp_localize_script('Broadstreet-main', 'broadstreetAjax', [
+ 'nonce' => wp_create_nonce('broadstreet_ajax_nonce')
+ ]);
+ }
+
+ # Only register on the post editing page
+ if($GLOBALS['pagenow'] == 'post.php' || $GLOBALS['pagenow'] == 'post-new.php')
+ {
+ if (Broadstreet_Utility::isBusinessEnabled()) {
+ wp_enqueue_style ('Broadstreet-vendorcss-time', Broadstreet_Utility::getVendorBaseURL() . 'timepicker/css/timePicker.css');
+ wp_enqueue_script('Broadstreet-main' , Broadstreet_Utility::getJSBaseURL().'broadstreet.js?v='. BROADSTREET_VERSION);
+ wp_enqueue_script('Broadstreet-vendorjs-time' , Broadstreet_Utility::getVendorBaseURL().'timepicker/js/jquery.timePicker.min.js');
+
+ // Pass nonce to JavaScript for AJAX security
+ wp_localize_script('Broadstreet-main', 'broadstreetAjax', [
+ 'nonce' => wp_create_nonce('broadstreet_ajax_nonce')
+ ]);
+ }
+ }
+
+ # Include thickbox on widgets page
+ if($GLOBALS['pagenow'] == 'widgets.php'
+ || (isset($_SERVER['QUERY_STRING']) && strstr($_SERVER['QUERY_STRING'], 'Broadstreet-Business')))
+ {
+ wp_enqueue_script('thickbox');
+ wp_enqueue_style( 'thickbox' );
+ }
+ }
+
+ /**
+ * The callback that is executed when the user is loading the admin page.
+ * Basically, output the page content for the admin page. The function
+ * acts just like a controller method for and MVC app. That is, it loads
+ * a view.
+ */
+ public function adminMenuCallback()
+ {
+ Broadstreet_Log::add('debug', "Admin page callback executed");
+ Broadstreet_Utility::sendInstallReportIfNew();
+
+ $data = array();
+
+ $data['service_tag'] = Broadstreet_Utility::getServiceTag();
+ $data['api_key'] = Broadstreet_Utility::getOption(self::KEY_API_KEY);
+ $data['business_enabled'] = Broadstreet_Utility::getOption(self::KEY_BIZ_ENABLED);
+ $data['network_id'] = Broadstreet_Utility::getOption(self::KEY_NETWORK_ID);
+ $data['errors'] = array();
+ $data['networks'] = array();
+ $data['key_valid'] = false;
+ $data['has_cc'] = false;
+
+ if(get_page_by_path('businesses'))
+ {
+ $data['errors'][] = 'You have a page named "businesses", which will interfere with the business directory if you plan to use it. You must delete that page.';
+ }
+
+ if(get_category_by_slug('businesses'))
+ {
+ $data['errors'][] = 'You have a category named "businesses", which will interfere with the business directory if you plan to use it. You must delete that category.';
+ }
+
+ if(!$data['api_key'])
+ {
+ $data['errors'][] = '<strong>You dont have an API key set yet!</strong><ol><li>If you already have a Broadstreet account, <a href="http://my.broadstreetads.com/access-token">get your key here</a>.</li><li>If you don't have an account with us, <a target="blank" id="one-click-signup" href="#">then use our one-click signup</a>.</li></ol>';
+ }
+ else
+ {
+ $api = $this->getBroadstreetClient();
+
+ try
+ {
+ $data['networks'] = $api->getNetworks();
+ $data['key_valid'] = true;
+ $data['network'] = Broadstreet_Utility::getNetwork(true);
+ }
+ catch(Exception $ex)
+ {
+ $data['networks'] = array();
+ $data['key_valid'] = false;
+ }
+ }
+
+ Broadstreet_View::load('admin/admin', $data);
+ }
+
+ /**
+ * The callback that is executed when the user is loading the admin page.
+ * Basically, output the page content for the admin page. The function
+ * acts just like a controller method for and MVC app. That is, it loads
+ * a view.
+ */
+ public function adminZonesMenuCallback()
+ {
+ Broadstreet_Log::add('debug', "Admin page callback executed");
+ $data = array();
+
+ $data['service_tag'] = Broadstreet_Utility::getServiceTag();
+ $data['api_key'] = Broadstreet_Utility::getOption(self::KEY_API_KEY);
+ $data['network_id'] = Broadstreet_Utility::getOption(self::KEY_NETWORK_ID);
+ $data['errors'] = array();
+ $data['networks'] = array();
+ $data['zones'] = array();
+ $data['placements'] = array();
+ $data['key_valid'] = false;
+ $data['categories'] = get_categories(array('hide_empty' => false));
+
+ if(!$data['api_key'])
+ {
+ $data['errors'][] = '<strong>You dont have an API key set yet!</strong><ol><li>If you already have a Broadstreet account, <a href="http://my.broadstreetads.com/access-token">get your key here</a>.</li><li>If you don't have an account with us, <a target="blank" id="one-click-signup" href="#">then use our one-click signup</a>.</li></ol>';
+ }
+ else
+ {
+ $api = $this->getBroadstreetClient();
+
+ try
+ {
+ Broadstreet_Utility::refreshZoneCache();
+ $data['key_valid'] = true;
+ $data['zones'] = Broadstreet_Utility::getZoneCache();
+ $data['placements'] = Broadstreet_Utility::getPlacementSettings();
+ }
+ catch(Exception $ex)
+ {
+ $data['networks'] = array();
+ $data['key_valid'] = false;
+ }
+ }
+
+ Broadstreet_View::load('admin/zones', $data);
+ }
+
+ public function adminMenuBusinessCallback() {
+
+ if (isset($_POST['featured_business_image'])) {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage($_POST['featured_business_image']);
+ } else {
+ $featured_image = Broadstreet_Utility::featuredBusinessImage();
+ }
+
+ Broadstreet_View::load('admin/businesses', array('featured_image' => $featured_image));
+ }
+
+ public function adminMenuHelpCallback()
+ {
+ Broadstreet_View::load('admin/help');
+ }
+
+ public function adminMenuLayoutCallback()
+ {
+ Broadstreet_View::load('admin/layout');
+ }
+
+ /**
+ * Handler for the broadstreet info box below a post or page
+ * @param type $post
+ */
+ public function broadstreetInfoBox($post)
+ {
+ // Use nonce for verification
+ wp_nonce_field(plugin_basename(__FILE__), 'broadstreetnoncename');
+
+ $zone_data = Broadstreet_Utility::getZoneCache();
+
+ Broadstreet_View::load('admin/infoBox', array('zones' => $zone_data));
+ }
+
+ /**
+ * Handler for the broadstreet info box below a post or page
+ * @param type $post
+ */
+ public function broadstreetBusinessBox($post)
+ {
+ // Use nonce for verification
+ wp_nonce_field(plugin_basename(__FILE__), 'broadstreetnoncename');
+
+ $meta = Broadstreet_Utility::getAllPostMeta($post->ID, self::$_businessDefaults);
+
+ $network_id = Broadstreet_Utility::getOption(self::KEY_NETWORK_ID);
+ $advertiser_id = Broadstreet_Utility::getPostMeta($post->ID, 'bs_advertiser_id');
+ $advertisement_id = Broadstreet_Utility::getPostMeta($post->ID, 'bs_advertisement_id');
+ $network_info = Broadstreet_Utility::getNetwork();
+ $show_offers = (Broadstreet_Utility::getOption(self::KEY_SHOW_OFFERS) == 'true');
+
+ $api = $this->getBroadstreetClient();
+
+ if($network_id && $advertiser_id && $advertisement_id)
+ {
+ $meta['preferred_hash_tag'] = $api->getAdvertisement($network_id, $advertiser_id, $advertisement_id)
+ ->preferred_hash_tag;
+ }
+
+ try
+ {
+ $advertisers = $api->getAdvertisers($network_id);
+ }
+ catch(Exception $ex)
+ {
+ $advertisers = array();
+ }
+
+ Broadstreet_View::load('admin/businessMetaBox', array(
+ 'meta' => $meta,
+ 'advertisers' => $advertisers,
+ 'network' => $network_info,
+ 'show_offers' => $show_offers
+ ));
+ }
+
+ /**
+ * Handler used for attaching post meta data to post query results
+ * @global object $wp_query
+ * @param array $posts
+ * @return array
+ */
+ public function businessQuery($posts)
+ {
+ global $wp_query;
+
+ if(@$wp_query->query_vars['post_type'] == self::BIZ_POST_TYPE
+ || @$wp_query->query_vars['taxonomy'] == self::BIZ_TAXONOMY)
+ {
+ $ids = array();
+ foreach($posts as $post) $ids[] = $post->ID;
+
+ $meta = Broadstreet_Model::getPostMeta($ids, self::$_businessDefaults);
+
+ for($i = 0; $i < count($posts); $i++)
+ {
+ if(isset($meta[$posts[$i]->ID]))
+ {
+ $posts[$i]->meta = $meta[$posts[$i]->ID];
+ }
+ }
+ }
+
+ return $posts;
+ }
+
+ /**
+ * Handler used for changing the wording of the comment form for business
+ * listings.
+ * @param array $defaults
+ * @return string
+ */
+ public function commentForm($defaults)
+ {
+ $defaults['title_reply'] = 'Leave a Review or Comment';
+ return $defaults;
+ }
+
+ public function createPostTypes()
+ {
+ register_post_type(self::BIZ_POST_TYPE,
+ array (
+ 'labels' => array(
+ 'name' => __( 'Businesses'),
+ 'singular_name' => __( 'Business'),
+ 'add_new_item' => __('Add New Business Profile', 'your_text_domain'),
+ 'edit_item' => __('Edit Business', 'your_text_domain'),
+ 'new_item' => __('New Business Profile', 'your_text_domain'),
+ 'all_items' => __('All Businesses', 'your_text_domain'),
+ 'view_item' => __('View This Business', 'your_text_domain'),
+ 'search_items' => __('Search Businesses', 'your_text_domain'),
+ 'not_found' => __('No businesses found', 'your_text_domain'),
+ 'not_found_in_trash' => __('No businesses found in Trash', 'your_text_domain'),
+ 'parent_item_colon' => '',
+ 'menu_name' => __('Businesses', 'your_text_domain')
+ ),
+ 'description' => 'Businesses for inclusion in the Broadstreet business directory',
+ 'public' => true,
+ 'has_archive' => true,
+ 'menu_position' => 5,
+ 'supports' => array('title', 'editor', '