base = $base; // Actions. add_action( 'wp_loaded', array( $this, 'register_publish_hooks' ), 1 ); add_action( $this->base->plugin->name, array( $this, 'publish' ), 1, 2 ); } /** * Registers publish hooks against all public Post Types, * * @since 3.0.0 */ public function register_publish_hooks() { add_action( 'transition_post_status', array( $this, 'transition_post_status' ), 10, 3 ); } /** * Fired when a Post's status transitions. Called by WordPress when wp_insert_post() is called, * and wp_insert_post() is called by WordPress and the REST API whenever creating or updating a Post. * * @since 3.1.6 * * @param string $new_status New Status. * @param string $old_status Old Status. * @param WP_Post $post Post. */ public function transition_post_status( $new_status, $old_status, $post ) { // Bail if the Post Type isn't public. // This prevents the rest of this routine running on e.g. ACF Free, when saving Fields (which results in Field loss). $post_types = array_keys( $this->base->get_class( 'common' )->get_post_types() ); if ( ! in_array( $post->post_type, $post_types, true ) ) { return; } // New Post Screen loading. // Draft saved. if ( $new_status === 'auto-draft' || $new_status === 'draft' || $new_status === 'inherit' || $new_status === 'trash' ) { return; } // Remove actions registered by this Plugin. // This ensures that when Page Builders call publish or update events via AJAX, we don't run this multiple times. remove_action( 'wp_insert_post', array( $this, 'wp_insert_post_publish' ), 999 ); remove_action( 'rest_after_insert_' . $post->post_type, array( $this, 'rest_api_post_publish' ), 10 ); remove_action( 'wp_insert_post', array( $this, 'wp_insert_post_update' ), 999 ); remove_action( 'rest_after_insert_' . $post->post_type, array( $this, 'rest_api_post_update' ), 10 ); /** * = REST API = * If this is a REST API Request, we can't use the wp_insert_post action, because the metadata * is *not* included in the call to wp_insert_post(). Instead, we must use a late REST API action * that gives the REST API time to save metadata. * Note that the meta being supplied in the REST API Request must be registered with WordPress using * register_meta() * * = Gutenberg = * If Gutenberg is being used on the given Post Type, two requests are sent: * - a REST API request, comprising of Post Data and Metadata registered in Gutenberg, * - a standard request, comprising of Post Metadata registered outside of Gutenberg (i.e. add_meta_box() data) * The second request will be seen by transition_post_status() as an update. * Therefore, we set a meta flag on the first Gutenberg REST API request to defer publishing the status until * the second, standard request - at which point, all Post metadata will be available to the Plugin. * * = Classic Editor = * Metadata is included in the call to wp_insert_post(), meaning that it's saved to the Post before we use it. */ $this->base->get_class( 'log' )->add_to_debug_log( 'Post ID: #' . $post->ID ); // If transitioning from future to publish, this is a scheduled Post being published by WordPress Cron. // We don't need to know whether it's a Gutenberg, Classic Editor or REST API request. if ( $old_status === 'future' && $new_status === 'publish' ) { $this->base->get_class( 'log' )->add_to_debug_log( 'Scheduled Post being published by WordPress' ); add_action( 'wp_insert_post', array( $this, 'wp_insert_post_publish' ), 999 ); // Don't need to do anything else, so exit. return; } // Flag to determine if the current Post is a Gutenberg Post or Rest API Request. $is_gutenberg_request = $this->is_gutenberg_request(); $is_rest_api_request = $this->is_rest_api_request(); $this->base->get_class( 'log' )->add_to_debug_log( 'Gutenberg Post: ' . ( $is_gutenberg_request ? 'Yes' : 'No' ) ); $this->base->get_class( 'log' )->add_to_debug_log( 'REST API Request: ' . ( $is_rest_api_request ? 'Yes' : 'No' ) ); // If a previous request flagged that an 'update' request should be treated as a publish request (i.e. // we're using Gutenberg and request to post.php was made after the REST API), do this now. $needs_publishing = get_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_publishing', true ); if ( $needs_publishing ) { $this->base->get_class( 'log' )->add_to_debug_log( 'Gutenberg: Needs Publishing' ); // Run Publish Status Action now. delete_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_publishing' ); add_action( 'wp_insert_post', array( $this, 'wp_insert_post_publish' ), 999 ); // Don't need to do anything else, so exit. return; } // If a previous request flagged that an update request be deferred (i.e. // we're using Gutenberg and request to post.php was made after the REST API), do this now. $needs_updating = get_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_updating', true ); if ( $needs_updating ) { $this->base->get_class( 'log' )->add_to_debug_log( 'Gutenberg: Needs Updating' ); // Run Publish Status Action now. delete_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_updating' ); add_action( 'wp_insert_post', array( $this, 'wp_insert_post_update' ), 999 ); // Don't need to do anything else, so exit. return; } // Publish. if ( $new_status === 'publish' && $new_status !== $old_status ) { /** * Gutenberg Editor REST API Request * - Non-Gutenberg metaboxes are POSTed via a second, separate request to post.php, which appears * as an 'update'. Define a meta key that we'll check on the separate request later. */ if ( $is_gutenberg_request ) { $this->base->get_class( 'log' )->add_to_debug_log( 'Gutenberg: Defer Publish' ); update_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_publishing', 1 ); // Don't need to do anything else, so exit. return; } /** * REST API */ if ( $is_rest_api_request ) { $this->base->get_class( 'log' )->add_to_debug_log( 'REST API: Publish' ); add_action( 'rest_after_insert_' . $post->post_type, array( $this, 'rest_api_post_publish' ), 10, 1 ); // Don't need to do anything else, so exit. return; } /** * Classic Editor */ $this->base->get_class( 'log' )->add_to_debug_log( 'Classic Editor: Publish' ); add_action( 'wp_insert_post', array( $this, 'wp_insert_post_publish' ), 999 ); // Don't need to do anything else, so exit. return; } // Update. if ( $new_status === 'publish' && $old_status === 'publish' ) { /** * Gutenberg Editor REST API Request * - Non-Gutenberg metaboxes are POSTed via a second, separate request to post.php, which appears * as an 'update'. Define a meta key that we'll check on the separate request later. */ if ( $is_gutenberg_request ) { $this->base->get_class( 'log' )->add_to_debug_log( 'Gutenberg: Defer Update' ); update_post_meta( $post->ID, $this->base->plugin->filter_name . '_needs_updating', 1 ); // Don't need to do anything else, so exit. return; } /** * REST API */ if ( $is_rest_api_request ) { $this->base->get_class( 'log' )->add_to_debug_log( 'REST API: Update' ); add_action( 'rest_after_insert_' . $post->post_type, array( $this, 'rest_api_post_update' ), 10, 1 ); // Don't need to do anything else, so exit. return; } /** * Classic Editor */ $this->base->get_class( 'log' )->add_to_debug_log( 'Classic Editor: Update' ); add_action( 'wp_insert_post', array( $this, 'wp_insert_post_update' ), 999 ); // Don't need to do anything else, so exit. return; } } /** * Helper function to determine if the request is a Gutenberg REST API request. * * @since 3.9.1 * * @return bool Is Gutenberg REST API Request */ private function is_gutenberg_request() { if ( ! defined( 'REST_REQUEST' ) ) { return false; } if ( ! REST_REQUEST ) { return false; } // Gutenberg requests are REST API requests, but include a _locale key. // 'True' REST API requests do not include this key. if ( ! filter_has_var( INPUT_POST, '_locale' ) && ! filter_has_var( INPUT_GET, '_locale' ) ) { return false; } return true; } /** * Helper function to determine if the request is a REST API request. * * @since 3.9.1 * * @return bool Is REST API Request */ private function is_rest_api_request() { if ( ! defined( 'REST_REQUEST' ) ) { return false; } if ( ! REST_REQUEST ) { return false; } // Gutenberg requests are REST API requests, but include a _locale key. // 'True' REST API requests do not include this key. if ( filter_has_var( INPUT_POST, '_locale' ) || filter_has_var( INPUT_GET, '_locale' ) ) { return false; } return true; } /** * Helper function to determine if the Post contains Gutenberg Content. * * @since 3.9.1 * * @param WP_Post $post Post. * @return bool Post Content contains Gutenberg Block Markup */ private function is_gutenberg_post_content( $post ) { if ( strpos( $post->post_content, ' tag. * @return string Content */ private function get_content( $post, $to_more_tag = false ) { // Fetch content. // get_the_content() only works for WordPress 5.2+, which added the $post param. if ( $to_more_tag ) { $extended = get_extended( $post->post_content ); if ( isset( $extended['main'] ) && ! empty( $extended['main'] ) ) { $content = $extended['main']; } else { // Fallback to the Post Content. $content = $post->post_content; } } else { $content = $post->post_content; } // Strip shortcodes. $content = strip_shortcodes( $content ); // Remove the wpautop filter, as this converts double newlines into

tags. // In turn,

tags are correctly discarded later on in this function, as social networks don't support HTML. // However, this results in separation between paragraphs going from two newlines to one newline. // Some social media services further drop a single newline, meaning paragraphs become one long block of text, which isn't // intended. remove_filter( 'the_content', 'wpautop' ); // Remove some third party Plugin filters that wrongly output content that we don't want in a status. remove_filter( 'the_content', 'powerpress_content' ); // Apply filters to get true output. $content = apply_filters( 'the_content', $content ); // Restore wpautop that we just removed. add_filter( 'the_content', 'wpautop' ); // If the content originates from Gutenberg, remove double newlines and convert breaklines // into newlines. $is_gutenberg_request_content = $this->is_gutenberg_post_content( $post ); if ( $is_gutenberg_request_content ) { // Remove double newlines, which may occur due to using Gutenberg blocks. // (blocks are separated with HTML comments, stripped using apply_filters( 'the_content' ), which results in double, or even triple, breaklines). $content = preg_replace( '/(?:(?:\r\n|\r|\n)\s*){2}/s', "\n\n", $content ); // Convert
and
into newlines. $content = preg_replace( '//i', "\n", $content ); } // Convert to plain text. $content = $this->convert_to_plain_text( $content ); /** * Filters the dynamic {content} replacement, when a Post's status is being built. * * @since 3.7.3 * * @param string $content Post Content. * @param WP_Post $post WordPress Post. * @param bool $is_gutenberg_request_content Is Gutenberg Post Content. */ $content = apply_filters( $this->base->plugin->filter_name . '_publish_get_content', $content, $post, $is_gutenberg_request_content ); // Return. return $content; } /** * Returns the date in the locale specified in WordPress. * * @since 4.7.7 * * @param WP_Post $post WordPress Post. * @return string Date */ private function get_date( $post ) { $date = date_i18n( get_option( 'date_format' ), strtotime( $post->post_date ) ); /* * Filters the dynamic {date} replacement, when a Post's status is being built. * * @since 4.7.7 * * @param string $date Date. * @param WP_Post $post WordPress Post. */ $date = apply_filters( $this->base->plugin->filter_name . '_publish_get_date', $date, $post ); // Return. return $date; } /** * Returns the Permalink, including or excluding a trailing slash, depending on the Plugin settings. * * @since 4.0.6 * * @param WP_Post $post WordPress Post. * @return string WordPress Post Permalink */ private function get_permalink( $post ) { $force_trailing_forwardslash = $this->base->get_class( 'settings' )->get_option( 'force_trailing_forwardslash', false ); // Define the URL, depending on whether it should end with a forwardslash or not. // This is by design; more users complain that they get 301 redirects from site.com/post/ to site.com/post // than from site.com/post to site.com/post/. // We can't control misconfigured WordPress installs, so this option gives them the choice. if ( $force_trailing_forwardslash ) { $url = get_permalink( $post->ID ); // If the Permalink doesn't have a forwardslash at the end of it, add it now. if ( substr( $url, -1 ) !== '/' ) { $url .= '/'; } } else { $url = rtrim( get_permalink( $post->ID ), '/' ); } /** * Filters the Post's Permalink, including or excluding a trailing slash, depending on the Plugin settings * * @since 4.0.6 * * @param string $url WordPress Post Permalink. * @param WP_Post $post WordPress Post. * @param bool $force_trailing_forwardslash Force Trailing Forwardslash. */ $url = apply_filters( $this->base->plugin->filter_name . '_publish_get_permalink', $url, $post, $force_trailing_forwardslash ); // Return. return $url; } /** * Returns the Short Permalink * * @since 4.2.7 * * @param WP_Post $post WordPress Post. * @return string WordPress Post Permalink */ private function get_short_permalink( $post ) { // Define short permalink e.g http://yoursite.com/?p=1. $url = rtrim( get_bloginfo( 'url' ), '/' ) . '/?p=' . $post->ID; /** * Filters the Post's Permalink, including or excluding a trailing slash, depending on the Plugin settings * * @since 4.2.7 * * @param string $url WordPress Post Permalink. * @param WP_Post $post WordPress Post. */ $url = apply_filters( $this->base->plugin->filter_name . '_publish_get_short_permalink', $url, $post ); // Return. return $url; } /** * Converts the given string (which is typically HTML from a WordPress Post or Post Meta Field) * to plain text, by performing several functions: * - stripping shortcodes (if shortcodes need processing, do so before calling this function) * - removing all inline style elements and their contents, * - stripping HTML tags, excluding
,
, ,

  • * - decoding HTML entities to avoid encoding issues on status output * - converting
    and
    to newlines * - removing double spaces * - trimming the final result of any leading or trailing spaces * * @since 4.6.9 * * @param string $text Text. * @param bool $convert_links_to_inline true: Convert e.g. `
    text` to `text (http://foo.com)`. * false: Convert e.g. `text` to `text`. * @param bool $strip_urls Whether to strip URLs from the text. * @return string Text */ private function convert_to_plain_text( $text, $convert_links_to_inline = true, $strip_urls = false ) { // Strip any shortcodes still remaining. // If shortcodes need to be processed, they should be processed before calling this function. $text = strip_shortcodes( $text ); // Wrap content in , and tags with an UTF-8 Content-Type meta tag. // Forcibly tell DOMDocument that this HTML uses the UTF-8 charset. // isn't enough, as DOMDocument still interprets the HTML as ISO-8859, which breaks character encoding // Use of mb_convert_encoding() with HTML-ENTITIES is deprecated in PHP 8.2, so we have to use this method. // If we don't, special characters render incorrectly. $text = '' . $text . ''; // Load the HTML into a DOMDocument. libxml_use_internal_errors( true ); $html = new \DOMDocument(); $html->loadHTML( $text ); // Load DOMDocument into XPath. $xpath = new \DOMXPath( $html ); // Remove inline style tags and their contents. foreach ( $xpath->query( '//style' ) as $node ) { $node->parentNode->removeChild( $node ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } // Fetch revised HTML. $text = $html->saveHTML(); // Remove HTML, except breaklines, links and unordered list items. $retain_tags = ( $strip_urls ? '
  • ' : '
  • ' ); $text = strip_tags( $text, $retain_tags ); // Decode excerpt to avoid encoding issues on status output. $text = html_entity_decode( $text ); // Convert
    and
    into newlines. $text = preg_replace( '//i', "\n", $text ); // Convert
    to text and inline link. if ( $convert_links_to_inline ) { // Extract the text from the link, and add the link in brackets after the text. $text = preg_replace( '/]+href=\"(.*?)\"[^>]*>(.*?)<\/a>/i', '$2 ($1)', $text ); } else { // Just extract the text from the link and output it. $text = preg_replace( '/]+href=\"(.*?)\"[^>]*>(.*?)<\/a>/i', '$2', $text ); } // If URLs are to be stripped, remove them. if ( $strip_urls ) { $text = preg_replace( '/https?:\/\/[^\s]+/', '', $text ); } // Convert
  • to hyphenated. $text = preg_replace( '/]*>(.*?)<\/li>/i', '- $1', $text ); // Remove double spaces, but retain newlines and accented characters. $text = preg_replace( '/[ ]{2,}/', ' ', $text ); // Remove tabs. $text = str_replace( "\t", '', $text ); // Finally, trim the text. $text = trim( $text ); // Return. return $text; } /** * Returns a flag denoting whether a character limit can safely be applied * to the given tag. * * @since 3.7.8 * * @param string $tag Tag. * @return bool Can apply character limit */ private function can_apply_character_limit_to_tag( $tag ) { // Get Tags. $tags = $this->base->get_class( 'common' )->get_tags_excluded_from_character_limit(); // If the tag is in the array of tags excluded from character limits, we // cannot apply a character limit to this tag. if ( in_array( $tag, $tags, true ) ) { return false; } // Can apply character limit to tag. return true; } /** * Applies the given word limit to the given text * * @since 3.8.9 * * @param string $text Text. * @param int $word_limit Word Limit. * @return string Text */ private function apply_word_limit( $text, $word_limit = 0 ) { // Store original text. $original_text = $text; // Bail if the word limit is zero or false. if ( ! $word_limit || $word_limit === 0 ) { return $text; } // Limit text. $text = wp_trim_words( $text, $word_limit, '' ); /** * Applies the given word limit to the given text. * * @since 3.8.9 * * @param string $text Text, with word limit applied. * @param int $word_limit Sentence Limit. * @param string $original_text Original Text, with no limit applied. */ $text = apply_filters( $this->base->plugin->filter_name . '_publish_apply_word_limit', $text, $word_limit, $original_text ); return $text; } /** * Applies the given sentence limit to the given text * * @since 4.3.1 * * @param string $text Text. * @param int $sentence_limit Sentence Limit. * @param int $min_sentence_length Minimum Sentence Length. * @return string */ public function apply_sentence_limit( $text, $sentence_limit = 0, $min_sentence_length = 5 ) { // Store original text. $original_text = $text; // Bail if the sentence limit is zero or false. if ( ! $sentence_limit || $sentence_limit === 0 ) { return $text; } // Build array of sentences. $parts = preg_split( '/(?<=[.?!])\s+(?=[a-z])/i', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // Iterate through the array, adding sentences to the array until we hit the sentence limit. // Sentences do not count towards the limit if they are shorter than the minimum sentence length. // This ensures abbreviations do not count towards the limit. $sentences = array(); $sentence_count = 0; foreach ( $parts as $index => $sentence ) { // If we've hit the sentence limit, stop. if ( $sentence_count >= $sentence_limit ) { break; } // Trim the sentence, adding it to the array. $sentences[ $index ] = trim( $sentence ); // If the sentence is longer than the minimum sentence length, count this as a sentence. if ( mb_strlen( $sentences[ $index ] ) > $min_sentence_length ) { ++$sentence_count; } } // Implode into text, with a space between each sentence, trimming the array results to avoid double spacing. $text = implode( ' ', array_map( 'trim', $sentences ) ); /** * Applies the given sentence limit to the given text. * * @since 4.3.1 * * @param string $text Text, with word limit applied. * @param int $sentence_limit Sentence Limit. * @param string $original_text Original Text, with no limit applied. */ $text = apply_filters( $this->base->plugin->filter_name . '_publish_apply_sentence_limit', $text, $sentence_limit, $original_text ); // Return. return $text; } /** * Applies the given character limit to the given text * * @since 3.7.3 * * @param string $text Text. * @param int $character_limit Character Limit. * @return string Text */ private function apply_character_limit( $text, $character_limit = 0 ) { // Bail if the character limit is zero or false. if ( ! $character_limit || $character_limit === 0 ) { return $text; } // Bail if the content isn't longer than the character limit. if ( strlen( $text ) <= $character_limit ) { return $text; } // Limit text. // Use mb_substr so that emojis don't break, which would result in text not being saved // by the social network when the status is sent. $text = mb_substr( $text, 0, $character_limit ); /** * Filters the character limited text. * * @since 3.7.3 * * @param string $text Text, with character limit applied. * @param int $character_limit Character Limit used. */ $text = apply_filters( $this->base->plugin->filter_name . '_publish_apply_character_limit', $text, $character_limit ); // Return. return $text; } /** * Helper method to iterate through statuses, sending each via a separate API call * to the API. * * @since 3.0.0 * * @param array $statuses Statuses. * @param int $post_id Post ID. * @param string $action Action. * @param array $profiles All Enabled Profiles. * @param bool $test_mode Test Mode (won't send to API). * @return array API Result for each status */ public function send( $statuses, $post_id, $action, $profiles, $test_mode = false ) { // Assume no errors. $errors = false; // Setup logging. $logs = array(); $log_error = array(); $log_enabled = $this->base->get_class( 'log' )->is_enabled(); foreach ( $statuses as $index => $status ) { // If the status is a WP_Error, something went wrong in building the status to be sent. // Log the error and continue to the next status. if ( isset( $status['error'] ) && is_wp_error( $status['error'] ) ) { // Error. $errors = true; $logs[] = array( 'action' => $action, 'request_sent' => gmdate( 'Y-m-d H:i:s' ), 'profile_id' => $status['profile_ids'][0], 'profile_name' => $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'], 'result' => 'error', 'result_message' => sprintf( /* translators: %1$s: Plugin Error string, %2$s: Error message from Plugin */ '%1$s: %2$s', __( 'Plugin Error', 'wp-to-buffer' ), $status['error']->get_error_message() ), 'status_text' => false, ); $log_error[] = ( $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'] . ': ' . $status['error']->get_error_message() ); continue; } // If this is a test, add to the log array only. if ( $test_mode ) { $logs[] = array( 'action' => $action, 'request_sent' => gmdate( 'Y-m-d H:i:s' ), 'profile_id' => $status['profile_ids'][0], 'profile_name' => $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'], 'result' => 'test', 'result_message' => '', 'status_text' => $status['text'], 'status_created_at' => gmdate( 'Y-m-d H:i:s', strtotime( 'now' ) ), 'status_due_at' => ( isset( $status['scheduled_at'] ) ? $status['scheduled_at'] : '' ), ); continue; } // Setup API. $this->base->get_class( 'api' )->set_tokens( $this->base->get_class( 'settings' )->get_access_token_by_profile_id( $status['profile_ids'][0] ), $this->base->get_class( 'settings' )->get_refresh_token_by_profile_id( $status['profile_ids'][0] ), $this->base->get_class( 'settings' )->get_token_expires_by_profile_id( $status['profile_ids'][0] ) ); // Send request. $result = $this->base->get_class( 'api' )->updates_create( $status, $profiles[ $status['profile_ids'][0] ]['service'] ); // Store result in log array. if ( is_wp_error( $result ) ) { // Error. $errors = true; $logs[] = array( 'action' => $action, 'request_sent' => gmdate( 'Y-m-d H:i:s' ), 'profile_id' => $status['profile_ids'][0], 'profile_name' => $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'], 'result' => 'error', 'result_message' => $result->get_error_message(), 'status_text' => $status['text'], ); $log_error[] = ( $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'] . ': ' . $result->get_error_message() ); } else { // OK. $logs[] = array( 'action' => $action, 'request_sent' => gmdate( 'Y-m-d H:i:s' ), 'profile_id' => $result['profile_id'], 'profile_name' => $profiles[ $status['profile_ids'][0] ]['formatted_service'] . ': ' . $profiles[ $status['profile_ids'][0] ]['formatted_username'], 'result' => 'success', 'result_message' => $result['message'], 'status_text' => $result['status_text'], 'status_created_at' => gmdate( 'Y-m-d H:i:s', $result['status_created_at'] ), 'status_due_at' => ( $result['due_at'] !== '0000-00-00 00:00:00' ? gmdate( 'Y-m-d H:i:s', $result['due_at'] ) : '0000-00-00 00:00:00' ), ); } } // Set the last sent timestamp, which we may use to prevent duplicate statuses. update_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_last_sent', time() ); // If we're reposting, update the last reposted date against the Post. // We do this here to ensure the Post isn't reposting again where e.g. one profile status worked + one profile status failed, // which would be deemed a failure. if ( $action === 'repost' && ! $test_mode ) { $this->base->get_class( 'repost' )->update_last_reposted_date( $post_id ); } // If no errors were reported, set a meta key to show a success message. // This triggers admin_notices() to tell the user what happened. if ( ! $errors ) { // Only set a success message if test mode is disabled. if ( ! $test_mode ) { update_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_success', 1 ); } delete_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_error' ); delete_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_errors' ); // Request that the user review the plugin. Notification displayed later, // can be called multiple times and won't re-display the notification if dismissed. $this->base->dashboard->request_review(); } else { update_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_success', 0 ); update_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_error', 1 ); update_post_meta( $post_id, '_' . $this->base->plugin->filter_name . '_errors', $log_error ); } // Save the log, if logging is enabled. if ( $log_enabled ) { foreach ( $logs as $log ) { $this->base->get_class( 'log' )->add( $post_id, $log ); } } // Return log results. return $logs; } /** * Clears any searches and replacements stored in this class. * * @since 3.8.0 */ private function clear_search_replacements() { $this->all_possible_searches_replacements = array(); $this->searches_replacements = array(); } }