/** * @param WP_Post $post * @param bool $updateAll TRUE if the update is part of updateAll() - if so, defer the term count */ public function update($post, $updateAll = false) { /** @var wpdb $wpdb */ global $wpdb; $content = $post->post_content; /** * Do a quick check that there IS a recipe before we go to the expense of instantiating a DOMDocument */ if (strpos($content, 'endeasyrecipe') === false) { return; } $dom = new EasyRecipeDocument($content); if (!$dom->isEasyRecipe) { return; } $cuisineTerms = array(); $courseTerms = array(); $postID = $post->ID; if (!$updateAll) { $this->countTerms['cuisine'] = array(); $this->countTerms['course'] = array(); } /** * Read all the current cuisine/course terms for this post * We need this to decide if we need to insert a new relationship and whether we need to remove any old relationships no longer used */ $q = "SELECT {$wpdb->term_taxonomy}.term_taxonomy_id, taxonomy FROM {$wpdb->terms} JOIN {$wpdb->term_taxonomy} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id JOIN "; $q .= "{$wpdb->term_relationships} on {$wpdb->term_relationships}.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id "; $q .= "WHERE object_id = {$postID} AND taxonomy in ('course','cuisine')"; $existing = $wpdb->get_results($q); $existingUnused = array(); foreach ($existing as $exist) { $existingUnused[$exist->term_taxonomy_id] = true; $this->countTerms[$exist->taxonomy][] = $exist->term_taxonomy_id; } /** * Get the course(s) and cuisine(s) from the recipe */ $cuisines = $dom->getElementsByClassName('cuisine'); $courses = $dom->getElementsByClassName('type'); if (count($cuisines) > 0) { /** @var DOMElement $cuisine */ foreach ($cuisines as $cuisine) { $term = $cuisine->nodeValue; /** * Get the term info for the recipe's cuisine(s) - insert one of it doesn't yet exist */ if (empty($cuisineTerms[$term])) { $termInfo = term_exists($term, 'cuisine'); if (!$termInfo) { $termInfo = wp_insert_term($term, 'cuisine'); } $cuisineTerms[$term] = $termInfo['term_taxonomy_id']; } /** * Check to see if we already have the correct relationship for this cuisine term for this post */ $ttID = $cuisineTerms[$term]; if (!empty($existingUnused[$ttID])) { $existingUnused[$ttID] = false; continue; } /** * The relationship didn't exist so insert it */ $this->countTerms['cuisine'][] = $ttID; $wpdb->insert($wpdb->term_relationships, array('object_id' => $postID, 'term_taxonomy_id' => $ttID)); } } if (count($courses) > 0) { /** @var DOMElement $course */ foreach ($courses as $course) { $term = $course->nodeValue; /** * Get the term info for the recipe's course(s) - insert one of it doesn't yet exist */ if (empty($courseTerms[$term])) { $termInfo = term_exists($term, 'course'); if (!$termInfo) { $termInfo = wp_insert_term($term, 'course'); } $courseTerms[$term] = $termInfo['term_taxonomy_id']; } /** * Check to see if we already have the correct relationship for this course term for this post */ $ttID = $courseTerms[$term]; if (!empty($existingUnused[$ttID])) { $existingUnused[$ttID] = false; continue; } /** * The relationship didn't exist so insert it and mark the ttID to be counted */ $this->countTerms['course'][] = $ttID; $wpdb->insert($wpdb->term_relationships, array('object_id' => $postID, 'term_taxonomy_id' => $ttID)); } } /** * Remove any existing term relationships that are now no longer used and adjust the list of terms that need to be updated */ foreach ($existingUnused as $ttID => $unused) { if ($unused) { $wpdb->delete($wpdb->term_relationships, array('object_id' => $postID, 'term_taxonomy_id' => $ttID)); } else { if (in_array($ttID, $this->countTerms['course'])) { } } } /** * Update any term counts that we may have adjusted unless this is part of an updateAll() run */ if (!$updateAll) { 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'); } } }
/** * 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; }