/**
  * Process any EasyRecipes in all the posts on the page
  * We need to do this here rather than in the_content hook because by then it's too late to queue up the scripts/styles we'll need
  *
  * @param $posts
  *
  * @return array
  */
 function thePosts($posts)
 {
     /* @var $wp_rewrite WP_Rewrite */
     global $wp_rewrite;
     /** @global  $wpdb wpdb */
     global $wpdb;
     /**
      * We don't want to process anything if it's a missing URL
      */
     if (is_404()) {
         return $posts;
     }
     global $shortcode_tags;
     $guestpost = null;
     $newPosts = array();
     /**
      * Process each post and replace placeholders with relevant data
      */
     foreach ($posts as $post) {
         /**
          * Have we already processed this post?
          */
         if (isset($this->easyrecipes[$post->ID])) {
             $post->post_content = $this->postContent[$post->ID];
             $newPosts[] = $post;
             continue;
         }
         /**
          * We may have to change the rating method (e.g. for Ziplist recipes) so make a local copy
          */
         $this->ratingMethod = $this->settings->ratings;
         $postDOM = new EasyRecipeDocument($post->post_content);
         if (!$postDOM->isEasyRecipe) {
             $newPosts[] = $post;
             continue;
         }
         $postDOM->setSettings($this->settings);
         /**
          * Mark this post as an easyrecipe so that the comment and rating processing know
          */
         $this->easyrecipes[$post->ID] = true;
         /**
          * Make sure we haven't already formatted this post. This can happen in preview mode where WP replaces the post_content
          * of the parent with the autosave content which we've already processed.
          * If this is the case, save the formatted code and mark this post as having been processed
          * TODO - are there implications for the object cache for themes that re-read posts?
          */
         if ($postDOM->isFormatted) {
             $this->postContent[$post->ID] = $post->post_content;
             $newPosts[] = $post;
             continue;
         }
         /**
          * Fix possibly broken times in older posts
          * Fix the Cholesterol typo oops in early versions
          */
         if ($postDOM->recipeVersion < '3') {
             $postDOM->fixTimes("preptime");
             $postDOM->fixTimes("cooktime");
             $postDOM->fixTimes("duration");
             $postDOM->setParentValueByClassName("cholestrol", $this->settings->lblCholesterol, "Cholestrol");
         }
         $data = new stdClass();
         /**
          * Get the ratings from the comment meta table if we use the EasyRecipe comment method
          * Other rating methods are handled in EasyRecipeDocument->applyStyle()
          * hasRatings is left unset for Self Rating
          */
         if ($this->ratingMethod == 'EasyRecipe') {
             $q = "SELECT COUNT(*) AS count, SUM(meta_value) AS sum FROM {$wpdb->comments} JOIN {$wpdb->commentmeta} ON {$wpdb->commentmeta}.comment_id = {$wpdb->comments}.comment_ID ";
             $q .= "WHERE comment_approved = 1 AND meta_key = 'ERRating' AND comment_post_ID = {$post->ID} AND meta_value > 0";
             $ratings = $wpdb->get_row($q);
             if ((int) $ratings->count > 0) {
                 $data->ratingCount = $ratings->count;
                 $data->ratingValue = number_format($ratings->sum / $ratings->count, 1);
                 $data->ratingPC = $data->ratingValue * 100 / 5;
                 $data->hasRating = true;
             } else {
                 $data->hasRating = false;
             }
         } else {
             if ($this->ratingMethod == 'Disabled') {
                 $data->hasRating = false;
             }
         }
         $this->settings->getLabels($data);
         $data->hasLinkback = $this->settings->allowLink;
         $data->displayPrint = $this->settings->displayPrint;
         $data->style = $this->styleName;
         $data->title = $post->post_title;
         $data->blogname = get_option("blogname");
         // TODO - do all this stuff at initialise time?
         $data->siteURL = $this->homeURL;
         /**
          * If the site isn't using permalinks then just pass the print stuff as a qurerystring param
          */
         if ($wp_rewrite->using_permalinks()) {
             $data->sitePrintURL = $data->siteURL;
         } else {
             $data->sitePrintURL = $data->siteURL . "?";
         }
         $data->postID = $post->ID;
         $data->recipeurl = get_permalink($post->ID);
         $data->convertFractions = $this->settings->convertFractions;
         if ($this->styleName[0] == '_') {
             $styleName = substr($this->styleName, 1);
             $templateFile = $this->settings->customTemplates . "/styles/{$styleName}/style.html";
         } else {
             $templateFile = self::$EasyRecipeDir . "/styles/{$this->styleName}/style.html";
         }
         $template = new EasyRecipeTemplate($templateFile);
         /**
          * Apply styles to the recipe data and return the content with recipes replace by a shortcode and also each recipe's HTML
          * Also keep a copy so we don't have to reformat in the case where the theme asks for the same post again
          *
          * This didn't work!  Some themes don't call the_content() (esp for excerpts) so we can't rely on hooking into that to supply the formatted html
          * We need to do it right here - it seems that the_posts is the only reliable place to replace the base recipe HTML with the formatted recipe HTML
          */
         /**
          * Replace the original content with the one that has the easyrecipe(s) nicely formatted and marked up
          * Also keep a copy so we don't have to reformat in the case where the theme asks for the same post again
          */
         $this->postContent[$post->ID] = $post->post_content = $postDOM->applyStyle($template, $data);
         /**
          * If we haven't already done so, hook into the_content filter to stop wpauto() messing with recipe HTML
          */
         if (empty($shortcode_tags['easyrecipe'])) {
             add_filter('the_content', array($this, 'theContent'), 0);
             add_shortcode('easyrecipe', array($this, 'replaceRecipeShortcode'));
         }
         /**
          * Some themes do a get_post() again instead of using the posts as modified by plugins
          * So make sure our modified post is in cache so the get_post() picks up the modified version not the original
          * Need to do both add and replace since add doesn't replace and replace doesn't add and we can't be sure if the cache key exists at this point
          */
         wp_cache_add($post->ID, $post, 'posts');
         wp_cache_replace($post->ID, $post, 'posts');
         $newPosts[] = $post;
     }
     return $newPosts;
 }