/**
  * Explicitly allow the itemprop, datetime and link attributes otherwise WP will strip them
  *
  * @param $postID
  */
 function publishFuturePost($postID)
 {
     global $allowedposttags;
     $post = get_post($postID);
     if (strpos($post->post_content, 'easyrecipe') !== false) {
         $allowedposttags['time'] = array('itemprop' => true, 'datetime' => true);
         $allowedposttags['link'] = array('itemprop' => true, 'href' => true);
         $this->settings = EasyRecipePlusSettings::getInstance();
         if ($this->settings->enableFooderific) {
             $this->fdPostStatusChanged('publish', 'future', $post);
         }
     }
 }
 /**
  * Get the post, extract the recipe and combine with the current style and output it
  *
  * @param integer $postID The post ID to print
  * @param integer $recipeIX The zero based index of the recipe in the post
  */
 public function printRecipe($postID, $recipeIX)
 {
     /** @var $wpdb wpdb */
     global $wpdb;
     $settings = EasyRecipePlusSettings::getInstance();
     /**
      * Be paranoid and force the ID to an integer
      */
     $postID = (int) $postID;
     $q = "SELECT * FROM {$wpdb->posts} WHERE ID = {$postID}";
     $post = $wpdb->get_row($q);
     if (!$post) {
         return;
     }
     /**
      * Process the [br] shortcodes and remove the spurious <br>'s that wp_auto() inserts
      */
     $content = str_replace("[br]", "<br>", $post->post_content);
     $content = preg_replace('%</div>\\s*</p></div>%im', '</div></div>', $content);
     $content = $this->plugin->possiblyConvert($postID, $post->post_type, $content);
     $postDOM = new EasyRecipePlusDocument($content);
     if (!$postDOM->isEasyRecipe) {
         return;
     }
     /**
      * If the post is formatted already then it came from the Object cache (?)
      * If that's the case we need to re-read the original
      */
     if ($postDOM->isFormatted) {
         $post = $wpdb->get_row("SELECT * FROM " . $wpdb->prefix . "posts WHERE ID = {$postID}");
         $content = str_replace("[br]", "<br>", $post->post_content);
         $content = preg_replace('%</div>\\s*</p></div>%im', '</div></div>', $content);
         $content = $this->plugin->possiblyConvert($postID, '', $content);
         $postDOM = new EasyRecipePlusDocument($content);
         if (!$postDOM->isEasyRecipe) {
             return;
         }
     }
     if (isset($_GET['style'])) {
         $styleName = $_GET['style'];
     } else {
         $styleName = $settings->printStyle;
     }
     //        $printStyleData = call_user_func(array($this->stylesClass, 'getStyleData'), $styleName, $settings->get('customTemplates'), true);
     $printStyleData = EasyRecipePlusStyles::getStyleData($styleName, $settings->customTemplates, true);
     if (get_locale() != 'en_US') {
         EasyRecipePlusTemplate::setTranslate('easyrecipe');
     }
     /**
      * Fix possibly broken times in older posts
      * Fix the Cholesterol oops in early versions
      */
     if ($postDOM->recipeVersion < '3') {
         $postDOM->fixTimes("preptime");
         $postDOM->fixTimes("cooktime");
         $postDOM->fixTimes("duration");
         $postDOM->setParentValueByClassName("cholestrol", $settings->lblCholesterol, "Cholestrol");
     }
     $postDOM->setSettings($settings);
     $data = new stdClass();
     $data->hasRating = false;
     $data->convertFractions = $settings->convertFractions;
     $settings->getLabels($data);
     $data->hasLinkback = $settings->allowLink;
     $data->title = $post->post_title;
     $data->blogname = get_option("blogname");
     $data->recipeurl = get_permalink($post->ID);
     $data->customCSS = $this->plugin->getCSS('Print');
     $data->extraPrintHeader = $settings->extraPrintHeader;
     $data->easyrecipeURL = EasyRecipePlus::$EasyRecipePlusUrl;
     $recipe = $postDOM->getRecipe($recipeIX);
     $photoURL = $postDOM->findPhotoURL($recipe);
     $data->hasPhoto = !empty($photoURL);
     $data->jqueryjs = self::JQUERYJS;
     $data->jqueryuijs = self::JQUERYUIJS;
     $data->jqueryuicss = self::JQUERYUICSS;
     if (current_user_can('edit_posts')) {
         $data->isAdmin = true;
         $data->formatDialog = $this->plugin->getFormatDialog($printStyleData, true);
         $cssLink = '<link href="' . EasyRecipePlus::$EasyRecipePlusUrl . '/css/%s?version=' . EasyRecipePlus::$pluginVersion . '" rel="stylesheet" type="text/css"/>';
         $jsLink = '<script type="text/javascript" src="' . EasyRecipePlus::$EasyRecipePlusUrl . '/js/%s?version=' . EasyRecipePlus::$pluginVersion . '"></script>';
         $data->formatCSS = sprintf($cssLink, 'easyrecipe-format-min.css');
         $data->formatJS = sprintf($jsLink, 'easyrecipe-format-min.js');
     } else {
         $data->formatDialog = '';
         $data->printJS = '<script type="text/javascript" src="' . EasyRecipePlus::$EasyRecipePlusUrl . '/js/easyrecipe-print-min.js?version=' . EasyRecipePlus::$pluginVersion . '"></script>';
     }
     $data->style = $styleName;
     if ($data->style[0] == '_') {
         $style = substr($data->style, 1);
         $data->css = "/easyrecipe-printstyle";
         $templateFile = $settings->customTemplates . "/printstyles/{$style}/style.html";
     } else {
         $data->css = EasyRecipePlus::$EasyRecipePlusUrl . "/printstyles/{$data->style}";
         $templateFile = EasyRecipePlus::$EasyRecipePlusDir . "/printstyles/{$data->style}/style.html";
     }
     $data->css .= "/style.css?version=" . EasyRecipePlus::$pluginVersion . ".{$printStyleData->version}";
     $template = new EasyRecipePlusTemplate($templateFile);
     /**
      * Brain dead IE shows "friendly" error pages (i.e. it's non-compliant) so we need to force a 200
      */
     header("HTTP/1.1 200 OK");
     /**
      * Set the character encoding explicitly
      */
     $charset = get_bloginfo('charset');
     header("Content-Type:text/html; charset={$charset}");
     echo $postDOM->formatRecipe($recipe, $template, $data);
     flush();
     exit;
 }
 /**
  * Scan all posts for recipes if $postID == 0, or a single post if $postID <> 0 and send basic details to fooderific
  * If it's a sitewide scan, data is batched up to minimize network traffic
  *
  * @param int $postID Scan all posts if this is zero, else a single post if not
  */
 function scanRun($postID = 0)
 {
     /* @var $wpdb wpdb */
     global $wpdb;
     $settings = EasyRecipePlusSettings::getInstance();
     $this->delay = $settings->scanDelay;
     $this->getRecipePlugins();
     /**
      * Read each published post (or the specific post if we're processing a specific post's update) and if it contains a recipe, then shoot the details off to fooderific.com
      * We're not interested in attachments or revisions. Also probably not interested in other types, but we don't know about custom post types so process anything else
      */
     if ($postID != 0) {
         $q = "SELECT * FROM {$wpdb->prefix}posts WHERE ID = '{$postID}' AND post_type <> 'attachment' AND post_type <> 'revision'";
         $this->batchSize = 1;
     } else {
         $q = "SELECT * FROM {$wpdb->prefix}posts WHERE post_status = 'publish' AND post_type <> 'attachment' AND post_type <> 'revision' ORDER BY ID DESC";
         $this->batchSize = self::BATCHSIZE;
         $settings->lastScanStarted = time();
         $settings->update();
     }
     $posts = $wpdb->get_results($q);
     /**
      * If this is a scan, notify fooderific that we're starting
      */
     if ($postID == 0) {
         $data = new stdClass();
         $data->action = 'start';
         $data->wpurl = get_bloginfo("wpurl");
         $data->count = count($posts);
         $args = array('body' => array('data' => serialize($data)));
         wp_remote_post(self::FOODERIFIC_URL, $args);
     }
     $this->nPostsSent = 0;
     $this->results = array();
     /**
      * Flag that we're running in scan so we don't schedule another scan on top of this one
      * Don't hold for longer than SCAN_TIMEOUT seconds so if the process crashes or has some kind of problem, it's not going to stop another scan later
      */
     set_transient(self::FOODERIFIC_SCAN, 'run', self::SCAN_TIMEOUT);
     /**
      * Also reset the run time limit to SCAN_TIMEOUT seconds so unintended loops or horribly slow processing doesn't tie this up forever
      */
     @set_time_limit(self::SCAN_TIMEOUT);
     foreach ($posts as $post) {
         $this->processPost($post);
     }
     if (count($this->results) > 0) {
         $this->nPostsSent += count($this->results);
         $args = array('body' => array('data' => serialize($this->results)));
         wp_remote_post(self::FOODERIFIC_URL, $args);
         $this->results = array();
     }
     /**
      * If this was a scan, notify fooderific that we're done
      */
     if ($postID == 0) {
         $data = new stdClass();
         $data->action = 'stop';
         $data->wpurl = get_bloginfo("wpurl");
         $data->count = $this->nPostsSent;
         $args = array('body' => array('data' => serialize($data)));
         wp_remote_post(self::FOODERIFIC_URL, $args);
     }
     delete_transient(self::FOODERIFIC_SCAN);
 }
 /**
  * Save a reference to the global settings
  * Add a reference to this instance in an array indexed by postID so that, given a postID, we can figure out which instance to use
  *
  * @param EasyRecipePlus $plugin
  */
 function __construct(EasyRecipePlus $plugin)
 {
     $this->plugin = $plugin;
     $this->settings = EasyRecipePlusSettings::getInstance();
 }
 /**
  * @static
  * @return EasyRecipePlusSettings
  */
 static function getInstance()
 {
     $freeSettings = null;
     $updateOptions = false;
     /**
      * If we haven't already instantiated settings, try to do it from the options
      */
     if (!self::$instance) {
         self::$instance = get_option('EasyRecipePlus', false);
         if (!self::$instance) {
             self::$instance = new EasyRecipePlusSettings();
             /**
              * There were no Plus settings saved
              * See if we have any free version settings and copy those if there are
              */
             $freeSettings = get_option('EasyRecipe');
             if (!empty($freeSettings)) {
                 foreach (self::$defaultSettings as $setting => $default) {
                     if (isset($freeSettings->{$setting})) {
                         self::$instance->{$setting} = $freeSettings->{$setting};
                     }
                 }
                 $updateOptions = true;
             }
             /**
              * If we're updating from a very early version, copy the old settings which are still relevant
              * Any not set in the defaults are deprecated and we can drop them
              */
             if (empty($freeSettings)) {
                 $v31Settings = get_option('ERPlusSettings');
                 if (!$v31Settings) {
                     $v31Settings = get_option('ERSettings');
                 }
                 if (!empty($v31Settings)) {
                     foreach ($v31Settings as $setting => $value) {
                         if (isset(self::$defaultSettings[$setting])) {
                             self::$instance->{$setting} = $value;
                         }
                     }
                     $updateOptions = true;
                 }
             }
         }
         /**
          * Fixup possible legacy problems where the options weren't stored as the correct class
          */
         if (!self::$instance instanceof EasyRecipePlusSettings) {
             self::$instance = new EasyRecipePlusSettings(self::$instance);
             $updateOptions = true;
         }
         /**
          * If this is the first run of the plugin after an update, see if we need to do any processing specific to this update.
          * Also do the update check if the taxonomies haven't been created yet
          *
          * TODO - determine if this is a new install -  won't need to check if so?
          */
         $updateCheck = version_compare(self::$instance->settingsVersion, EasyRecipePlus::$pluginVersion) == -1 || !self::$instance->taxonomiesCreated;
         if ($updateCheck) {
             EasyRecipePlusUpdate::check(self::$instance);
             /**
              * Save the new settings version (will be the same as the installed pluginVersion)
              */
             self::$instance->settingsVersion = EasyRecipePlus::$pluginVersion;
             $updateOptions = true;
         }
         /**
          * Do we need to fix the .tmp stuff up that happened on some installs of ER 3.2.2802?
          * Only need to check if the current version is > 2802
          * Should be able to remove this once the few sites that it affects get updated
          */
         if (version_compare(EasyRecipePlus::$pluginVersion, '3.2.2802') == 1) {
             EasyRecipePlusUpdate::check2802();
         }
         /**
          * Set any defaults which haven't been set in the current version (i.e. new settings just introduced)
          * TODO - remove any options no longer needed?
          */
         foreach (self::$defaultSettings as $setting => $default) {
             if (!isset(self::$instance->{$setting})) {
                 self::$instance->{$setting} = $default;
                 $updateOptions = true;
             }
         }
         /**
          * Update the settings if we changed them during construction
          */
         if ($updateOptions) {
             update_option('EasyRecipePlus', self::$instance);
         }
     }
     return self::$instance;
 }
 /**
  * Gets details about the site and installed plugins etc
  *
  * @return stdClass Object containing diagnostics data
  */
 function get()
 {
     global $wp_version;
     /** @var wpdb $wpdb */
     global $wpdb;
     /**
      * Get the php info.  Save anything already in the output buffer, just in case it's relevant for the site's output in show()
      */
     $this->existingOP = ob_get_clean();
     ob_start();
     phpinfo();
     $phpinfo = ob_get_contents();
     ob_end_clean();
     preg_match('%<body>(.*)</body>%si', $phpinfo, $regs);
     $this->phpinfo = $regs[1];
     /** @noinspection PhpUndefinedClassInspection */
     $this->pluginURL = EasyRecipePlus::$EasyRecipePlusUrl;
     /** @noinspection PhpUndefinedClassInspection */
     $this->pluginDir = EasyRecipePlus::$EasyRecipePlusDir;
     /**
      * Get our own settings. This is the same for all Easy Plugins and individualised by the build processs
      */
     /** @noinspection PhpUndefinedClassInspection */
     $settings = EasyRecipePlusSettings::getInstance();
     /**
      * Don't send any settings (passwords etc) that we really have no business knowing
      */
     if (isset($settings->privateSettings)) {
         foreach ($settings->privateSettings as $privateSetting) {
             if (isset($settings->{$privateSetting})) {
                 unset($settings->{$privateSetting});
             }
         }
         unset($settings->privateSettings);
     }
     $this->settings = $settings;
     $capabilities = "";
     get_currentuserinfo();
     $user = $GLOBALS['current_user'];
     if (isset($user->caps)) {
         foreach ($user->caps as $cap => $allowed) {
             if ($allowed) {
                 $capabilities .= "{$cap},";
             }
         }
     }
     $this->wpCapabilities = rtrim($capabilities, ",");
     $this->wpVersion = $wp_version;
     $this->wpSiteURL = site_url();
     $this->wpHomeURL = home_url();
     $this->wpMultiSite = is_multisite() ? 'Yes' : 'No';
     $this->mysqlVersion = $wpdb->db_version();
     $this->gmtOffset = get_option('gmt_offset');
     $this->timezone = get_option('timezone_string');
     if ($wp_version < '3.4') {
         /** @noinspection PhpDeprecationInspection */
         $themeData = get_theme_data(get_stylesheet_directory() . "/style.css");
         $this->wpTheme = $themeData["Name"];
         $this->wpThemeVersion = $themeData["Version"];
         $this->wpThemeURL = $themeData["URI"];
     } else {
         $themeData = wp_get_theme();
         $this->wpTheme = $themeData->get("Name");
         $this->wpThemeVersion = $themeData->get("Version");
         $this->wpThemeURL = $themeData->get("ThemeURI");
     }
     if (!function_exists('get_plugins')) {
         require_once ABSPATH . 'wp-admin/includes/plugin.php';
     }
     $plugins = get_plugins();
     foreach ($plugins as $pluginFile => $null) {
         $plugins[$pluginFile]["active"] = is_plugin_active($pluginFile) ? "Active" : "Inactive";
     }
     usort($plugins, array($this, "sortPlugins"));
     $this->PLUGINS = array();
     foreach ($plugins as $plugin) {
         $item = new stdClass();
         $item->name = $plugin["Title"];
         $item->active = $plugin["active"];
         $item->version = $plugin["Version"];
         $item->url = $plugin["PluginURI"];
         $this->PLUGINS[] = $item;
     }
 }
 /**
  * Update all taxonomies.
  * This should only ever be called from a cron job scheduled by EasyRecipePlusScheduler because it can potentially take quite a while
  */
 function updateAll()
 {
     /** @var wpdb $wpdb */
     global $wpdb;
     /**
      * If we are already running, don't do it again
      */
     if ($this->scheduler->isRunning()) {
         return;
     }
     /**
      * Set as running
      * Set a "timeout" of 10 minutes. This will prevent it being re-run for 10 minutes if the current run terminates abnormally for any reason
      */
     $this->scheduler->setRunning(10 * 60);
     $q = "SELECT ID FROM {$wpdb->posts} WHERE post_type NOT IN ('attachment','index','nav_menu_item')";
     $postIDs = $wpdb->get_col($q);
     $this->countTerms['cuisine'] = array();
     $this->countTerms['course'] = array();
     foreach ($postIDs as $postID) {
         $post = WP_Post::get_instance($postID);
         $this->update($post, false);
     }
     /**
      * Update any term counts that we may have adjusted
      */
     if (count($this->countTerms['cuisine']) > 0) {
         wp_update_term_count_now(array_unique(array_keys($this->countTerms['cuisine'])), 'cuisine');
     }
     if (count($this->countTerms['course']) > 0) {
         wp_update_term_count_now(array_unique(array_keys($this->countTerms['course'])), 'course');
     }
     /**
      * Mark the taxonomies as having been created
      */
     $settings = EasyRecipePlusSettings::getInstance();
     $settings->taxonomiesCreated = true;
     $settings->update();
     /**
      * Mark this job as complete
      */
     $this->scheduler->terminate();
 }