ts current commenter's name, email, and URL. * * Expects cookies content to already be sanitized. User of this function might * wish to recheck the returned array for validity. * * @see sanitize_comment_cookies() Use to sanitize cookies * * @since 2.0.4 * * @return array { * An array of current commenter variables. * * @type string $comment_author The name of the current commenter, or an empty string. * @type string $comment_author_email The email address of the current commenter, or an empty string. * @type string $comment_author_url The URL address of the current commenter, or an empty string. * } */ function wp_get_current_commenter() { // Cookies should already be sanitized. $comment_author = ''; if ( isset( $_COOKIE[ 'comment_author_' . COOKIEHASH ] ) ) { $comment_author = $_COOKIE[ 'comment_author_' . COOKIEHASH ]; } $comment_author_email = ''; if ( isset( $_COOKIE[ 'comment_author_email_' . COOKIEHASH ] ) ) { $comment_author_email = $_COOKIE[ 'comment_author_email_' . COOKIEHASH ]; } $comment_author_url = ''; if ( isset( $_COOKIE[ 'comment_author_url_' . COOKIEHASH ] ) ) { $comment_author_url = $_COOKIE[ 'comment_author_url_' . COOKIEHASH ]; } /** * Filters the current commenter's name, email, and URL. * * @since 3.1.0 * * @param array $comment_author_data { * An array of current commenter variables. * * @type string $comment_author The name of the current commenter, or an empty string. * @type string $comment_author_email The email address of the current commenter, or an empty string. * @type string $comment_author_url The URL address of the current commenter, or an empty string. * } */ return apply_filters( 'wp_get_current_commenter', compact( 'comment_author', 'comment_author_email', 'comment_author_url' ) ); } /** * Gets unapproved comment author's email. * * Used to allow the commenter to see their pending comment. * * @since 5.1.0 * @since 5.7.0 The window within which the author email for an unapproved comment * can be retrieved was extended to 10 minutes. * * @return string The unapproved comment author's email (when supplied). */ function wp_get_unapproved_comment_author_email() { $commenter_email = ''; if ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) { $comment_id = (int) $_GET['unapproved']; $comment = get_comment( $comment_id ); if ( $comment && hash_equals( $_GET['moderation-hash'], wp_hash( $comment->comment_date_gmt ) ) ) { // The comment will only be viewable by the comment author for 10 minutes. $comment_preview_expires = strtotime( $comment->comment_date_gmt . '+10 minutes' ); if ( time() < $comment_preview_expires ) { $commenter_email = $comment->comment_author_email; } } } if ( ! $commenter_email ) { $commenter = wp_get_current_commenter(); $commenter_email = $commenter['comment_author_email']; } return $commenter_email; } /** * Inserts a comment into the database. * * @since 2.0.0 * @since 4.4.0 Introduced the `$comment_meta` argument. * @since 5.5.0 Default value for `$comment_type` argument changed to `comment`. * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $commentdata { * Array of arguments for inserting a new comment. * * @type string $comment_agent The HTTP user agent of the `$comment_author` when * the comment was submitted. Default empty. * @type int|string $comment_approved Whether the comment has been approved. Default 1. * @type string $comment_author The name of the author of the comment. Default empty. * @type string $comment_author_email The email address of the `$comment_author`. Default empty. * @type string $comment_author_IP The IP address of the `$comment_author`. Default empty. * @type string $comment_author_url The URL address of the `$comment_author`. Default empty. * @type string $comment_content The content of the comment. Default empty. * @type string $comment_date The date the comment was submitted. To set the date * manually, `$comment_date_gmt` must also be specified. * Default is the current time. * @type string $comment_date_gmt The date the comment was submitted in the GMT timezone. * Default is `$comment_date` in the site's GMT timezone. * @type int $comment_karma The karma of the comment. Default 0. * @type int $comment_parent ID of this comment's parent, if any. Default 0. * @type int $comment_post_ID ID of the post that relates to the comment, if any. * Default 0. * @type string $comment_type Comment type. Default 'comment'. * @type array $comment_meta Optional. Array of key/value pairs to be stored in commentmeta for the * new comment. * @type int $user_id ID of the user who submitted the comment. Default 0. * } * @return int|false The new comment's ID on success, false on failure. */ function wp_insert_comment( $commentdata ) { global $wpdb; $data = wp_unslash( $commentdata ); $comment_author = ! isset( $data['comment_author'] ) ? '' : $data['comment_author']; $comment_author_email = ! isset( $data['comment_author_email'] ) ? '' : $data['comment_author_email']; $comment_author_url = ! isset( $data['comment_author_url'] ) ? '' : $data['comment_author_url']; $comment_author_ip = ! isset( $data['comment_author_IP'] ) ? '' : $data['comment_author_IP']; $comment_date = ! isset( $data['comment_date'] ) ? current_time( 'mysql' ) : $data['comment_date']; $comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt']; $comment_post_id = ! isset( $data['comment_post_ID'] ) ? 0 : $data['comment_post_ID']; $comment_content = ! isset( $data['comment_content'] ) ? '' : $data['comment_content']; $comment_karma = ! isset( $data['comment_karma'] ) ? 0 : $data['comment_karma']; $comment_approved = ! isset( $data['comment_approved'] ) ? 1 : $data['comment_approved']; $comment_agent = ! isset( $data['comment_agent'] ) ? '' : $data['comment_agent']; $comment_type = empty( $data['comment_type'] ) ? 'comment' : $data['comment_type']; $comment_parent = ! isset( $data['comment_parent'] ) ? 0 : $data['comment_parent']; $user_id = ! isset( $data['user_id'] ) ? 0 : $data['user_id']; $compacted = array( 'comment_post_ID' => $comment_post_id, 'comment_author_IP' => $comment_author_ip, ); $compacted += compact( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id' ); if ( ! $wpdb->insert( $wpdb->comments, $compacted ) ) { return false; } $id = (int) $wpdb->insert_id; if ( 1 == $comment_approved ) { wp_update_comment_count( $comment_post_id ); $data = array(); foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) { $data[] = "lastcommentmodified:$timezone"; } wp_cache_delete_multiple( $data, 'timeinfo' ); } clean_comment_cache( $id ); $comment = get_comment( $id ); // If metadata is provided, store it. if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) { foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) { add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true ); } } /** * Fires immediately after a comment is inserted into the database. * * @since 2.8.0 * * @param int $id The comment ID. * @param WP_Comment $comment Comment object. */ do_action( 'wp_insert_comment', $id, $comment ); return $id; } /** * Filters and sanitizes comment data. * * Sets the comment data 'filtered' field to true when finished. This can be * checked as to whether the comment should be filtered and to keep from * filtering the same comment more than once. * * @since 2.0.0 * * @param array $commentdata Contains information on the comment. * @return array Parsed comment information. */ function wp_filter_comment( $commentdata ) { if ( isset( $commentdata['user_ID'] ) ) { /** * Filters the comment author's user ID before it is set. * * The first time this filter is evaluated, `user_ID` is checked * (for back-compat), followed by the standard `user_id` value. * * @since 1.5.0 * * @param int $user_id The comment author's user ID. */ $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_ID'] ); } elseif ( isset( $commentdata['user_id'] ) ) { /** This filter is documented in wp-includes/comment.php */ $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] ); } /** * Filters the comment author's browser user agent before it is set. * * @since 1.5.0 * * @param string $comment_agent The comment author's browser user agent. */ $commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) ); /** This filter is documented in wp-includes/comment.php */ $commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] ); /** * Filters the comment content before it is set. * * @since 1.5.0 * * @param string $comment_content The comment content. */ $commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] ); /** * Filters the comment author's IP address before it is set. * * @since 1.5.0 * * @param string $comment_author_ip The comment author's IP address. */ $commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] ); /** This filter is documented in wp-includes/comment.php */ $commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] ); /** This filter is documented in wp-includes/comment.php */ $commentdata['comment_author_email'] = apply_filters( 'pre_comment_author_email', $commentdata['comment_author_email'] ); $commentdata['filtered'] = true; return $commentdata; } /** * Determines whether a comment should be blocked because of comment flood. * * @since 2.1.0 * * @param bool $block Whether plugin has already blocked comment. * @param int $time_lastcomment Timestamp for last comment. * @param int $time_newcomment Timestamp for new comment. * @return bool Whether comment should be blocked. */ function wp_throttle_comment_flood( $block, $time_lastcomment, $time_newcomment ) { if ( $block ) { // A plugin has already blocked... we'll let that decision stand. return $block; } if ( ( $time_newcomment - $time_lastcomment ) < 15 ) { return true; } return false; } /** * Adds a new comment to the database. * * Filters new comment to ensure that the fields are sanitized and valid before * inserting comment into database. Calls {@see 'comment_post'} action with comment ID * and whether comment is approved by WordPress. Also has {@see 'preprocess_comment'} * filter for processing the comment data before the function handles it. * * We use `REMOTE_ADDR` here directly. If you are behind a proxy, you should ensure * that it is properly set, such as in wp-config.php, for your environment. * * See {@link https://core.trac.wordpress.org/ticket/9235} * * @since 1.5.0 * @since 4.3.0 Introduced the `comment_agent` and `comment_author_IP` arguments. * @since 4.7.0 The `$avoid_die` parameter was added, allowing the function * to return a WP_Error object instead of dying. * @since 5.5.0 The `$avoid_die` parameter was renamed to `$wp_error`. * @since 5.5.0 Introduced the `comment_type` argument. * * @see wp_insert_comment() * @global wpdb $wpdb WordPress database abstraction object. * * @param array $commentdata { * Comment data. * * @type string $comment_author The name of the comment author. * @type string $comment_author_email The comment author email address. * @type string $comment_author_url The comment author URL. * @type string $comment_content The content of the comment. * @type string $comment_date The date the comment was submitted. Default is the current time. * @type string $comment_date_gmt The date the comment was submitted in the GMT timezone. * Default is `$comment_date` in the GMT timezone. * @type string $comment_type Comment type. Default 'comment'. * @type int $comment_parent The ID of this comment's parent, if any. Default 0. * @type int $comment_post_ID The ID of the post that relates to the comment. * @type int $user_id The ID of the user who submitted the comment. Default 0. * @type int $user_ID Kept for backward-compatibility. Use `$user_id` instead. * @type string $comment_agent Comment author user agent. Default is the value of 'HTTP_USER_AGENT' * in the `$_SERVER` superglobal sent in the original request. * @type string $comment_author_IP Comment author IP address in IPv4 format. Default is the value of * 'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request. * } * @param bool $wp_error Should errors be returned as WP_Error objects instead of * executing wp_die()? Default false. * @return int|false|WP_Error The ID of the comment on success, false or WP_Error on failure. */ function wp_new_comment( $commentdata, $wp_error = false ) { global $wpdb; /* * Normalize `user_ID` to `user_id`, but pass the old key * to the `preprocess_comment` filter for backward compatibility. */ if ( isset( $commentdata['user_ID'] ) ) { $commentdata['user_ID'] = (int) $commentdata['user_ID']; $commentdata['user_id'] = $commentdata['user_ID']; } elseif ( isset( $commentdata['user_id'] ) ) { $commentdata['user_id'] = (int) $commentdata['user_id']; $commentdata['user_ID'] = $commentdata['user_id']; } $prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0; if ( ! isset( $commentdata['comment_author_IP'] ) ) { $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR']; } if ( ! isset( $commentdata['comment_agent'] ) ) { $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : ''; } /** * Filters a comment's data before it is sanitized and inserted into the database. * * @since 1.5.0 * @since 5.6.0 Comment data includes the `comment_agent` and `comment_author_IP` values. * * @param array $commentdata Comment data. */ $commentdata = apply_filters( 'preprocess_comment', $commentdata ); $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID']; // Normalize `user_ID` to `user_id` again, after the filter. if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) { $commentdata['user_ID'] = (int) $commentdata['user_ID']; $commentdata['user_id'] = $commentdata['user_ID']; } elseif ( isset( $commentdata['user_id'] ) ) { $commentdata['user_id'] = (int) $commentdata['user_id']; $commentdata['user_ID'] = $commentdata['user_id']; } $commentdata['comment_parent'] = isset( $commentdata['comment_parent'] ) ? absint( $commentdata['comment_parent'] ) : 0; $parent_status = ( $commentdata['comment_parent'] > 0 ) ? wp_get_comment_status( $commentdata['comment_parent'] ) : ''; $commentdata['comment_parent'] = ( 'approved' === $parent_status || 'unapproved' === $parent_status ) ? $commentdata['comment_parent'] : 0; $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] ); $commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 ); if ( empty( $commentdata['comment_date'] ) ) { $commentdata['comment_date'] = current_time( 'mysql' ); } if ( empty( $commentdata['comment_date_gmt'] ) ) { $commentdata['comment_date_gmt'] = current_time( 'mysql', 1 ); } if ( empty( $commentdata['comment_type'] ) ) { $commentdata['comment_type'] = 'comment'; } $commentdata = wp_filter_comment( $commentdata ); $commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error ); if ( is_wp_error( $commentdata['comment_approved'] ) ) { return $commentdata['comment_approved']; } $comment_id = wp_insert_comment( $commentdata ); if ( ! $comment_id ) { $fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' ); foreach ( $fields as $field ) { if ( isset( $commentdata[ $field ] ) ) { $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] ); } } $commentdata = wp_filter_comment( $commentdata ); $commentdata['comment_approved'] = wp_allow_comment( $commentdata, $wp_error ); if ( is_wp_error( $commentdata['comment_approved'] ) ) { return $commentdata['comment_approved']; } $comment_id = wp_insert_comment( $commentdata ); if ( ! $comment_id ) { return false; } } /** * Fires immediately after a comment is inserted into the database. * * @since 1.2.0 * @since 4.5.0 The `$commentdata` parameter was added. * * @param int $comment_id The comment ID. * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam. * @param array $commentdata Comment data. */ do_action( 'comment_post', $comment_id, $commentdata['comment_approved'], $commentdata ); return $comment_id; } /** * Sends a comment moderation notification to the comment moderator. * * @since 4.4.0 * * @param int $comment_id ID of the comment. * @return bool True on success, false on failure. */ function wp_new_comment_notify_moderator( $comment_id ) { $comment = get_comment( $comment_id ); // Only send notifications for pending comments. $maybe_notify = ( '0' == $comment->comment_approved ); /** This filter is documented in wp-includes/pluggable.php */ $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id ); if ( ! $maybe_notify ) { return false; } return wp_notify_moderator( $comment_id ); } /** * Sends a notification of a new comment to the post author. * * @since 4.4.0 * * Uses the {@see 'notify_post_author'} filter to determine whether the post author * should be notified when a new comment is added, overriding site setting. * * @param int $comment_id Comment ID. * @return bool True on success, false on failure. */ function wp_new_comment_notify_postauthor( $comment_id ) { $comment = get_comment( $comment_id ); $maybe_notify = get_option( 'comments_notify' ); /** * Filters whether to send the post author new comment notification emails, * overriding the site setting. * * @since 4.4.0 * * @param bool $maybe_notify Whether to notify the post author about the new comment. * @param int $comment_id The ID of the comment for the notification. */ $maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_id ); /* * wp_notify_postauthor() checks if notifying the author of their own comment. * By default, it won't, but filters can override this. */ if ( ! $maybe_notify ) { return false; } // Only send notifications for approved comments. if ( ! isset( $comment->comment_approved ) || '1' != $comment->comment_approved ) { return false; } return wp_notify_postauthor( $comment_id ); } /** * Sets the status of a comment. * * The {@see 'wp_set_comment_status'} action is called after the comment is handled. * If the comment status is not in the list, then false is returned. * * @since 1.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Comment $comment_id Comment ID or WP_Comment object. * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'. * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default false. * @return bool|WP_Error True on success, false or WP_Error on failure. */ function wp_set_comment_status( $comment_id, $comment_status, $wp_error = false ) { global $wpdb; switch ( $comment_status ) { case 'hold': case '0': $status = '0'; break; case 'approve': case '1': $status = '1'; add_action( 'wp_set_comment_status', 'wp_new_comment_notify_postauthor' ); break; case 'spam': $status = 'spam'; break; case 'trash': $status = 'trash'; break; default: return false; } $comment_old = clone get_comment( $comment_id ); if ( ! $wpdb->update( $wpdb->comments, array( 'comment_approved' => $status ), array( 'comment_ID' => $comment_old->comment_ID ) ) ) { if ( $wp_error ) { return new WP_Error( 'db_update_error', __( 'Could not update comment status.' ), $wpdb->last_error ); } else { return false; } } clean_comment_cache( $comment_old->comment_ID ); $comment = get_comment( $comment_old->comment_ID ); /** * Fires immediately after transitioning a comment's status from one to another in the database * and removing the comment from the object cache, but prior to all status transition hooks. * * @since 1.5.0 * * @param string $comment_id Comment ID as a numeric string. * @param string $comment_status Current comment status. Possible values include * 'hold', '0', 'approve', '1', 'spam', and 'trash'. */ do_action( 'wp_set_comment_status', $comment->comment_ID, $comment_status ); wp_transition_comment_status( $comment_status, $comment_old->comment_approved, $comment ); wp_update_comment_count( $comment->comment_post_ID ); return true; } /** * Updates an existing comment in the database. * * Filters the comment and makes sure certain fields are valid before updating. * * @since 2.0.0 * @since 4.9.0 Add updating comment meta during comment update. * @since 5.5.0 The `$wp_error` parameter was added. * @since 5.5.0 The return values for an invalid comment or post ID * were changed to false instead of 0. * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $commentarr Contains information on the comment. * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false. * @return int|false|WP_Error The value 1 if the comment was updated, 0 if not updated. * False or a WP_Error object on failure. */ function wp_update_comment( $commentarr, $wp_error = false ) { global $wpdb; // First, get all of the original fields. $comment = get_comment( $commentarr['comment_ID'], ARRAY_A ); if ( empty( $comment ) ) { if ( $wp_error ) { return new WP_Error( 'invalid_comment_id', __( 'Invalid comment ID.' ) ); } else { return false; } } // Make sure that the comment post ID is valid (if specified). if ( ! empty( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) { if ( $wp_error ) { return new WP_Error( 'invalid_post_id', __( 'Invalid post ID.' ) ); } else { return false; } } $filter_comment = false; if ( ! has_filter( 'pre_comment_content', 'wp_filter_kses' ) ) { $filter_comment = ! user_can( isset( $comment['user_id'] ) ? $comment['user_id'] : 0, 'unfiltered_html' ); } if ( $filter_comment ) { add_filter( 'pre_comment_content', 'wp_filter_kses' ); } // Escape data pulled from DB. $comment = wp_slash( $comment ); $old_status = $comment['comment_approved']; // Merge old and new fields with new fields overwriting old ones. $commentarr = array_merge( $comment, $commentarr ); $commentarr = wp_filter_comment( $commentarr ); if ( $filter_comment ) { remove_filter( 'pre_comment_content', 'wp_filter_kses' ); } // Now extract the merged array. $data = wp_unslash( $commentarr ); /** * Filters the comment content before it is updated in the database. * * @since 1.5.0 * * @param string $comment_content The comment data. */ $data['comment_content'] = apply_filters( 'comment_save_pre', $data['comment_content'] ); $data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] ); if ( ! isset( $data['comment_approved'] ) ) { $data['comment_approved'] = 1; } elseif ( 'hold' === $data['comment_approved'] ) { $data['comment_approved'] = 0; } elseif ( 'approve' === $data['comment_approved'] ) { $data['comment_approved'] = 1; } $comment_id = $data['comment_ID']; $comment_post_id = $data['comment_post_ID']; /** * Filters the comment data immediately before it is updated in the database. * * Note: data being passed to the filter is already unslashed. * * @since 4.7.0 * @since 5.5.0 Returning a WP_Error value from the filter will short-circuit comment update * and allow skipping further processing. * * @param array|WP_Error $data The new, processed comment data, or WP_Error. * @param array $comment The old, unslashed comment data. * @param array $commentarr The new, raw comment data. */ $data = apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr ); // Do not carry on on failure. if ( is_wp_error( $data ) ) { if ( $wp_error ) { return $data; } else { return false; } } $keys = array( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id', ); $data = wp_array_slice_assoc( $data, $keys ); $result = $wpdb->update( $wpdb->comments, $data, array( 'comment_ID' => $comment_id ) ); if ( false === $result ) { if ( $wp_error ) { return new WP_Error( 'db_update_error', __( 'Could not update comment in the database.' ), $wpdb->last_error ); } else { return false; } } // If metadata is provided, store it. if ( isset( $commentarr['comment_meta'] ) && is_array( $commentarr['comment_meta'] ) ) { foreach ( $commentarr['comment_meta'] as $meta_key => $meta_value ) { update_comment_meta( $comment_id, $meta_key, $meta_value ); } } clean_comment_cache( $comment_id ); wp_update_comment_count( $comment_post_id ); /** * Fires immediately after a comment is updated in the database. * * The hook also fires immediately before comment status transition hooks are fired. * * @since 1.2.0 * @since 4.6.0 Added the `$data` parameter. * * @param int $comment_id The comment ID. * @param array $data Comment data. */ do_action( 'edit_comment', $comment_id, $data ); $comment = get_comment( $comment_id ); wp_transition_comment_status( $comment->comment_approved, $old_status, $comment ); return $result; } /** * Determines whether to defer comment counting. * * When setting $defer to true, all post comment counts will not be updated * until $defer is set to false. When $defer is set to false, then all * previously deferred updated post comment counts will then be automatically * updated without having to call wp_update_comment_count() after. * * @since 2.5.0 * * @param bool $defer * @return bool */ function wp_defer_comment_counting( $defer = null ) { static $_defer = false; if ( is_bool( $defer ) ) { $_defer = $defer; // Flush any deferred counts. if ( ! $defer ) { wp_update_comment_count( null, true ); } } return $_defer; } /** * Updates the comment count for post(s). * * When $do_deferred is false (is by default) and the comments have been set to * be deferred, the post_id will be added to a queue, which will be updated at a * later date and only updated once per post ID. * * If the comments have not be set up to be deferred, then the post will be * updated. When $do_deferred is set to true, then all previous deferred post * IDs will be updated along with the current $post_id. * * @since 2.1.0 * * @see wp_update_comment_count_now() For what could cause a false return value * * @param int|null $post_id Post ID. * @param bool $do_deferred Optional. Whether to process previously deferred * post comment counts. Default false. * @return bool|void True on success, false on failure or if post with ID does * not exist. */ function wp_update_comment_count( $post_id, $do_deferred = false ) { static $_deferred = array(); if ( empty( $post_id ) && ! $do_deferred ) { return false; } if ( $do_deferred ) { $_deferred = array_unique( $_deferred ); foreach ( $_deferred as $i => $_post_id ) { wp_update_comment_count_now( $_post_id ); unset( $_deferred[ $i ] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */ } } if ( wp_defer_comment_counting() ) { $_deferred[] = $post_id; return true; } elseif ( $post_id ) { return wp_update_comment_count_now( $post_id ); } } /** * Updates the comment count for the post. * * @since 2.5.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $post_id Post ID * @return bool True on success, false if the post does not exist. */ function wp_update_comment_count_now( $post_id ) { global $wpdb; $post_id = (int) $post_id; if ( ! $post_id ) { return false; } wp_cache_delete( 'comments-0', 'counts' ); wp_cache_delete( "comments-{$post_id}", 'counts' ); $post = get_post( $post_id ); if ( ! $post ) { return false; } $old = (int) $post->comment_count; /** * Filters a post's comment count before it is updated in the database. * * @since 4.5.0 * * @param int|null $new The new comment count. Default null. * @param int $old The old comment count. * @param int $post_id Post ID. */ $new = apply_filters( 'pre_wp_update_comment_count_now', null, $old, $post_id ); if ( is_null( $new ) ) { $new = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id ) ); } else { $new = (int) $new; } $wpdb->update( $wpdb->posts, array( 'comment_count' => $new ), array( 'ID' => $post_id ) ); clean_post_cache( $post ); /** * Fires immediately after a post's comment count is updated in the database. * * @since 2.3.0 * * @param int $post_id Post ID. * @param int $new The new comment count. * @param int $old The old comment count. */ do_action( 'wp_update_comment_count', $post_id, $new, $old ); /** This action is documented in wp-includes/post.php */ do_action( "edit_post_{$post->post_type}", $post_id, $post ); /** This action is documented in wp-includes/post.php */ do_action( 'edit_post', $post_id, $post ); return true; } // // Ping and trackback functions. // /** * Finds a pingback server URI based on the given URL. * * Checks the HTML for the rel="pingback" link and X-Pingback headers. It does * a check for the X-Pingback headers first and returns that, if available. * The check for the rel="pingback" has more overhead than just the header. * * @since 1.5.0 * * @param string $url URL to ping. * @param string $deprecated Not Used. * @return string|false String containing URI on success, false on failure. */ function discover_pingback_server_uri( $url, $deprecated = '' ) { if ( ! empty( $deprecated ) ) { _deprecated_argument( __FUNCTION__, '2.7.0' ); } $pingback_str_dquote = 'rel="pingback"'; $pingback_str_squote = 'rel=\'pingback\''; /** @todo Should use Filter Extension or custom preg_match instead. */ $parsed_url = parse_url( $url ); if ( ! isset( $parsed_url['host'] ) ) { // Not a URL. This should never happen. return false; } // Do not search for a pingback server on our own uploads. $uploads_dir = wp_get_upload_dir(); if ( str_starts_with( $url, $uploads_dir['baseurl'] ) ) { return false; } $response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0', ) ); if ( is_wp_error( $response ) ) { return false; } if ( wp_remote_retrieve_header( $response, 'X-Pingback' ) ) { return wp_remote_retrieve_header( $response, 'X-Pingback' ); } // Not an (x)html, sgml, or xml page, no use going further. if ( preg_match( '#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'Content-Type' ) ) ) { return false; } // Now do a GET since we're going to look in the HTML headers (and we're sure it's not a binary file). $response = wp_safe_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0', ) ); if ( is_wp_error( $response ) ) { return false; } $contents = wp_remote_retrieve_body( $response ); $pingback_link_offset_dquote = strpos( $contents, $pingback_str_dquote ); $pingback_link_offset_squote = strpos( $contents, $pingback_str_squote ); if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) { $quote = ( $pingback_link_offset_dquote ) ? '"' : '\''; $pingback_link_offset = ( '"' === $quote ) ? $pingback_link_offset_dquote : $pingback_link_offset_squote; $pingback_href_pos = strpos( $contents, 'href=', $pingback_link_offset ); $pingback_href_start = $pingback_href_pos + 6; $pingback_href_end = strpos( $contents, $quote, $pingback_href_start ); $pingback_server_url_len = $pingback_href_end - $pingback_href_start; $pingback_server_url = substr( $contents, $pingback_href_start, $pingback_server_url_len ); // We may find rel="pingback" but an incomplete pingback URL. if ( $pingback_server_url_len > 0 ) { // We got it! return $pingback_server_url; } } return false; } /** * Performs all pingbacks, enclosures, trackbacks, and sends to pingback services. * * @since 2.1.0 * @since 5.6.0 Introduced `do_all_pings` action hook for individual services. */ function do_all_pings() { /** * Fires immediately after the `do_pings` event to hook services individually. * * @since 5.6.0 */ do_action( 'do_all_pings' ); } /** * Performs all pingbacks. * * @since 5.6.0 */ function do_all_pingbacks() { $pings = get_posts( array( 'post_type' => get_post_types(), 'suppress_filters' => false, 'nopaging' => true, 'meta_key' => '_pingme', 'fields' => 'ids', ) ); foreach ( $pings as $ping ) { delete_post_meta( $ping, '_pingme' ); pingback( null, $ping ); } } /** * Performs all enclosures. * * @since 5.6.0 */ function do_all_enclosures() { $enclosures = get_posts( array( 'post_type' => get_post_types(), 'suppress_filters' => false, 'nopaging' => true, 'meta_key' => '_encloseme', 'fields' => 'ids', ) ); foreach ( $enclosures as $enclosure ) { delete_post_meta( $enclosure, '_encloseme' ); do_enclose( null, $enclosure ); } } /** * Performs all trackbacks. * * @since 5.6.0 */ function do_all_trackbacks() { $trackbacks = get_posts( array( 'post_type' => get_post_types(), 'suppress_filters' => false, 'nopaging' => true, 'meta_key' => '_trackbackme', 'fields' => 'ids', ) ); foreach ( $trackbacks as $trackback ) { delete_post_meta( $trackback, '_trackbackme' ); do_trackbacks( $trackback ); } } /** * Performs trackbacks. * * @since 1.5.0 * @since 4.7.0 `$post` can be a WP_Post object. * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Post $post Post ID or object to do trackbacks on. * @return void|false Returns false on failure. */ function do_trackbacks( $post ) { global $wpdb; $post = get_post( $post ); if ( ! $post ) { return false; } $to_ping = get_to_ping( $post ); $pinged = get_pung( $post ); if ( empty( $to_ping ) ) { $wpdb->update( $wpdb->posts, array( 'to_ping' => '' ), array( 'ID' => $post->ID ) ); return; } if ( empty( $post->post_excerpt ) ) { /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'the_content', $post->post_content, $post->ID ); } else { /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'the_excerpt', $post->post_excerpt ); } $excerpt = str_replace( ']]>', ']]>', $excerpt ); $excerpt = wp_html_excerpt( $excerpt, 252, '…' ); /** This filter is documented in wp-includes/post-template.php */ $post_title = apply_filters( 'the_title', $post->post_title, $post->ID ); $post_title = strip_tags( $post_title ); if ( $to_ping ) { foreach ( (array) $to_ping as $tb_ping ) { $tb_ping = trim( $tb_ping ); if ( ! in_array( $tb_ping, $pinged, true ) ) { trackback( $tb_ping, $post_title, $excerpt, $post->ID ); $pinged[] = $tb_ping; } else { $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post->ID ) ); } } } } /** * Sends pings to all of the ping site services. * * @since 1.2.0 * * @param int $post_id Post ID. * @return int Same post ID as provided. */ function generic_ping( $post_id = 0 ) { $services = get_option( 'ping_sites' ); $services = explode( "\n", $services ); foreach ( (array) $services as $service ) { $service = trim( $service ); if ( '' !== $service ) { weblog_ping( $service ); } } return $post_id; } /** * Pings back the links found in a post. * * @since 0.71 * @since 4.7.0 `$post` can be a WP_Post object. * * @param string $content Post content to check for links. If empty will retrieve from post. * @param int|WP_Post $post Post ID or object. */ function pingback( $content, $post ) { require_once ABSPATH . WPINC . '/class-IXR.php'; require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php'; // Original code by Mort (http://mort.mine.nu:8080). $post_links = array(); $post = get_post( $post ); if ( ! $post ) { return; } $pung = get_pung( $post ); if ( empty( $content ) ) { $content = $post->post_content; } /* * Step 1. * Parsing the post, external links (if any) are stored in the $post_links array. */ $post_links_temp = wp_extract_urls( $content ); /* * Step 2. * Walking through the links array. * First we get rid of links pointing to sites, not to specific files. * Example: * http://dummy-weblog.org * http://dummy-weblog.org/ * http://dummy-weblog.org/post.php * We don't wanna ping first and second types, even if they have a valid . */ foreach ( (array) $post_links_temp as $link_test ) { // If we haven't pung it already and it isn't a link to itself. if ( ! in_array( $link_test, $pung, true ) && ( url_to_postid( $link_test ) != $post->ID ) // Also, let's never ping local attachments. && ! is_local_attachment( $link_test ) ) { $test = parse_url( $link_test ); if ( $test ) { if ( isset( $test['query'] ) ) { $post_links[] = $link_test; } elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) { $post_links[] = $link_test; } } } } $post_links = array_unique( $post_links ); /** * Fires just before pinging back links found in a post. * * @since 2.0.0 * * @param string[] $post_links Array of link URLs to be checked (passed by reference). * @param string[] $pung Array of link URLs already pinged (passed by reference). * @param int $post_id The post ID. */ do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post->ID ) ); foreach ( (array) $post_links as $pagelinkedto ) { $pingback_server_url = discover_pingback_server_uri( $pagelinkedto ); if ( $pingback_server_url ) { if ( function_exists( 'set_time_limit' ) ) { set_time_limit( 60 ); } // Now, the RPC call. $pagelinkedfrom = get_permalink( $post ); // Using a timeout of 3 seconds should be enough to cover slow servers. $client = new WP_HTTP_IXR_Client( $pingback_server_url ); $client->timeout = 3; /** * Filters the user agent sent when pinging-back a URL. * * @since 2.9.0 * * @param string $concat_useragent The user agent concatenated with ' -- WordPress/' * and the WordPress version. * @param string $useragent The useragent. * @param string $pingback_server_url The server URL being linked to. * @param string $pagelinkedto URL of page linked to. * @param string $pagelinkedfrom URL of page linked from. */ $client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . get_bloginfo( 'version' ), $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom ); // When set to true, this outputs debug messages by itself. $client->debug = false; if ( $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto ) || ( isset( $client->error->code ) && 48 == $client->error->code ) ) { // Already registered. add_ping( $post, $pagelinkedto ); } } } } /** * Checks whether blog is public before returning sites. * * @since 2.1.0 * * @param mixed $sites Will return if blog is public, will not return if not public. * @return mixed Empty string if blog is not public, returns $sites, if site is public. */ function privacy_ping_filter( $sites ) { if ( '0' != get_option( 'blog_public' ) ) { return $sites; } else { return ''; } } /** * Sends a Trackback. * * Updates database when sending trackback to prevent duplicates. * * @since 0.71 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $trackback_url URL to send trackbacks. * @param string $title Title of post. * @param string $excerpt Excerpt of post. * @param int $post_id Post ID. * @return int|false|void Database query from update. */ function trackback( $trackback_url, $title, $excerpt, $post_id ) { global $wpdb; if ( empty( $trackback_url ) ) { return; } $options = array(); $options['timeout'] = 10; $options['body'] = array( 'title' => $title, 'url' => get_permalink( $post_id ), 'blog_name' => get_option( 'blogname' ), 'excerpt' => $excerpt, ); $response = wp_safe_remote_post( $trackback_url, $options ); if ( is_wp_error( $response ) ) { return; } $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $post_id ) ); return $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $post_id ) ); } /** * Sends a pingback. * * @since 1.2.0 * * @param string $server Host of blog to connect to. * @param string $path Path to send the ping. */ function weblog_ping( $server = '', $path = '' ) { require_once ABSPATH . WPINC . '/class-IXR.php'; require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php'; // Using a timeout of 3 seconds should be enough to cover slow servers. $client = new WP_HTTP_IXR_Client( $server, ( ( ! strlen( trim( $path ) ) || ( '/' === $path ) ) ? false : $path ) ); $client->timeout = 3; $client->useragent .= ' -- WordPress/' . get_bloginfo( 'version' ); // When set to true, this outputs debug messages by itself. $client->debug = false; $home = trailingslashit( home_url() ); if ( ! $client->query( 'weblogUpdates.extendedPing', get_option( 'blogname' ), $home, get_bloginfo( 'rss2_url' ) ) ) { // Then try a normal ping. $client->query( 'weblogUpdates.ping', get_option( 'blogname' ), $home ); } } /** * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI. * * @since 3.5.1 * * @see wp_http_validate_url() * * @param string $source_uri * @return string */ function pingback_ping_source_uri( $source_uri ) { return (string) wp_http_validate_url( $source_uri ); } /** * Default filter attached to xmlrpc_pingback_error. * * Returns a generic pingback error code unless the error code is 48, * which reports that the pingback is already registered. * * @since 3.5.1 * * @link https://www.hixie.ch/specs/pingback/pingback#TOC3 * * @param IXR_Error $ixr_error * @return IXR_Error */ function xmlrpc_pingback_error( $ixr_error ) { if ( 48 === $ixr_error->code ) { return $ixr_error; } return new IXR_Error( 0, '' ); } // // Cache. // /** * Removes a comment from the object cache. * * @since 2.3.0 * * @param int|array $ids Comment ID or an array of comment IDs to remove from cache. */ function clean_comment_cache( $ids ) { $comment_ids = (array) $ids; wp_cache_delete_multiple( $comment_ids, 'comment' ); foreach ( $comment_ids as $id ) { /** * Fires immediately after a comment has been removed from the object cache. * * @since 4.5.0 * * @param int $id Comment ID. */ do_action( 'clean_comment_cache', $id ); } wp_cache_set_comments_last_changed(); } /** * Updates the comment cache of given comments. * * Will add the comments in $comments to the cache. If comment ID already exists * in the comment cache then it will not be updated. The comment is added to the * cache using the comment group with the key using the ID of the comments. * * @since 2.3.0 * @since 4.4.0 Introduced the `$update_meta_cache` parameter. * * @param WP_Comment[] $comments Array of comment objects * @param bool $update_meta_cache Whether to update commentmeta cache. Default true. */ function update_comment_cache( $comments, $update_meta_cache = true ) { $data = array(); foreach ( (array) $comments as $comment ) { $data[ $comment->comment_ID ] = $comment; } wp_cache_add_multiple( $data, 'comment' ); if ( $update_meta_cache ) { // Avoid `wp_list_pluck()` in case `$comments` is passed by reference. $comment_ids = array(); foreach ( $comments as $comment ) { $comment_ids[] = $comment->comment_ID; } update_meta_cache( 'comment', $comment_ids ); } } /** * Adds any comments from the given IDs to the cache that do not already exist in cache. * * @since 4.4.0 * @since 6.1.0 This function is no longer marked as "private". * @since 6.3.0 Use wp_lazyload_comment_meta() for lazy-loading of comment meta. * * @see update_comment_cache() * @global wpdb $wpdb WordPress database abstraction object. * * @param int[] $comment_ids Array of comment IDs. * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. */ function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) { global $wpdb; $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' ); if ( ! empty( $non_cached_ids ) ) { $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", implode( ',', array_map( 'intval', $non_cached_ids ) ) ) ); update_comment_cache( $fresh_comments, false ); } if ( $update_meta_cache ) { wp_lazyload_comment_meta( $comment_ids ); } } // // Internal. // /** * Closes comments on old posts on the fly, without any extra DB queries. Hooked to the_posts. * * @since 2.7.0 * @access private * * @param WP_Post $posts Post data object. * @param WP_Query $query Query object. * @return array */ function _close_comments_for_old_posts( $posts, $query ) { if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) ) { return $posts; } /** * Filters the list of post types to automatically close comments for. * * @since 3.2.0 * * @param string[] $post_types An array of post type names. */ $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) ); if ( ! in_array( $posts[0]->post_type, $post_types, true ) ) { return $posts; } $days_old = (int) get_option( 'close_comments_days_old' ); if ( ! $days_old ) { return $posts; } if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) { $posts[0]->comment_status = 'closed'; $posts[0]->ping_status = 'closed'; } return $posts; } /** * Closes comments on an old post. Hooked to comments_open and pings_open. * * @since 2.7.0 * @access private * * @param bool $open Comments open or closed. * @param int $post_id Post ID. * @return bool $open */ function _close_comments_for_old_post( $open, $post_id ) { if ( ! $open ) { return $open; } if ( ! get_option( 'close_comments_for_old_posts' ) ) { return $open; } $days_old = (int) get_option( 'close_comments_days_old' ); if ( ! $days_old ) { return $open; } $post = get_post( $post_id ); /** This filter is documented in wp-includes/comment.php */ $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) ); if ( ! in_array( $post->post_type, $post_types, true ) ) { return $open; } // Undated drafts should not show up as comments closed. if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) { return $open; } if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) { return false; } return $open; } /** * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form. * * This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which * expect slashed data. * * @since 4.4.0 * * @param array $comment_data { * Comment data. * * @type string|int $comment_post_ID The ID of the post that relates to the comment. * @type string $author The name of the comment author. * @type string $email The comment author email address. * @type string $url The comment author URL. * @type string $comment The content of the comment. * @type string|int $comment_parent The ID of this comment's parent, if any. Default 0. * @type string $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML. * } * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure. */ function wp_handle_comment_submission( $comment_data ) { $comment_post_id = 0; $comment_author = ''; $comment_author_email = ''; $comment_author_url = ''; $comment_content = ''; $comment_parent = 0; $user_id = 0; if ( isset( $comment_data['comment_post_ID'] ) ) { $comment_post_id = (int) $comment_data['comment_post_ID']; } if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) { $comment_author = trim( strip_tags( $comment_data['author'] ) ); } if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) { $comment_author_email = trim( $comment_data['email'] ); } if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) { $comment_author_url = trim( $comment_data['url'] ); } if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) { $comment_content = trim( $comment_data['comment'] ); } if ( isset( $comment_data['comment_parent'] ) ) { $comment_parent = absint( $comment_data['comment_parent'] ); $comment_parent_object = get_comment( $comment_parent ); if ( 0 !== $comment_parent && ( ! $comment_parent_object instanceof WP_Comment || 0 === (int) $comment_parent_object->comment_approved ) ) { /** * Fires when a comment reply is attempted to an unapproved comment. * * @since 6.2.0 * * @param int $comment_post_id Post ID. * @param int $comment_parent Parent comment ID. */ do_action( 'comment_reply_to_unapproved_comment', $comment_post_id, $comment_parent ); return new WP_Error( 'comment_reply_to_unapproved_comment', __( 'Sorry, replies to unapproved comments are not allowed.' ), 403 ); } } $post = get_post( $comment_post_id ); if ( empty( $post->comment_status ) ) { /** * Fires when a comment is attempted on a post that does not exist. * * @since 1.5.0 * * @param int $comment_post_id Post ID. */ do_action( 'comment_id_not_found', $comment_post_id ); return new WP_Error( 'comment_id_not_found' ); } // get_post_status() will get the parent status for attachments. $status = get_post_status( $post ); if ( ( 'private' === $status ) && ! current_user_can( 'read_post', $comment_post_id ) ) { return new WP_Error( 'comment_id_not_found' ); } $status_obj = get_post_status_object( $status ); if ( ! comments_open( $comment_post_id ) ) { /** * Fires when a comment is attempted on a post that has comments closed. * * @since 1.5.0 * * @param int $comment_post_id Post ID. */ do_action( 'comment_closed', $comment_post_id ); return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 ); } elseif ( 'trash' === $status ) { /** * Fires when a comment is attempted on a trashed post. * * @since 2.9.0 * * @param int $comment_post_id Post ID. */ do_action( 'comment_on_trash', $comment_post_id ); return new WP_Error( 'comment_on_trash' ); } elseif ( ! $status_obj->public && ! $status_obj->private ) { /** * Fires when a comment is attempted on a post in draft mode. * * @since 1.5.1 * * @param int $comment_post_id Post ID. */ do_action( 'comment_on_draft', $comment_post_id ); if ( current_user_can( 'read_post', $comment_post_id ) ) { return new WP_Error( 'comment_on_draft', __( 'Sorry, comments are not allowed for this item.' ), 403 ); } else { return new WP_Error( 'comment_on_draft' ); } } elseif ( post_password_required( $comment_post_id ) ) { /** * Fires when a comment is attempted on a password-protected post. * * @since 2.9.0 * * @param int $comment_post_id Post ID. */ do_action( 'comment_on_password_protected', $comment_post_id ); return new WP_Error( 'comment_on_password_protected' ); } else { /** * Fires before a comment is posted. * * @since 2.8.0 * * @param int $comment_post_id Post ID. */ do_action( 'pre_comment_on_post', $comment_post_id ); } // If the user is logged in. $user = wp_get_current_user(); if ( $user->exists() ) { if ( empty( $user->display_name ) ) { $user->display_name = $user->user_login; } $comment_author = $user->display_name; $comment_author_email = $user->user_email; $comment_author_url = $user->user_url; $user_id = $user->ID; if ( current_user_can( 'unfiltered_html' ) ) { if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] ) || ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_id ) ) { kses_remove_filters(); // Start with a clean slate. kses_init_filters(); // Set up the filters. remove_filter( 'pre_comment_content', 'wp_filter_post_kses' ); add_filter( 'pre_comment_content', 'wp_filter_kses' ); } } } else { if ( get_option( 'comment_registration' ) ) { return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to comment.' ), 403 ); } } $comment_type = 'comment'; if ( get_option( 'require_name_email' ) && ! $user->exists() ) { if ( '' == $comment_author_email || '' == $comment_author ) { return new WP_Error( 'require_name_email', __( 'Error: Please fill the required fields.' ), 200 ); } elseif ( ! is_email( $comment_author_email ) ) { return new WP_Error( 'require_valid_email', __( 'Error: Please enter a valid email address.' ), 200 ); } } $commentdata = array( 'comment_post_ID' => $comment_post_id, ); $commentdata += compact( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_id' ); /** * Filters whether an empty comment should be allowed. * * @since 5.1.0 * * @param bool $allow_empty_comment Whether to allow empty comments. Default false. * @param array $commentdata Array of comment data to be sent to wp_insert_comment(). */ $allow_empty_comment = apply_filters( 'allow_empty_comment', false, $commentdata ); if ( '' === $comment_content && ! $allow_empty_comment ) { return new WP_Error( 'require_valid_comment', __( 'Error: Please type your comment text.' ), 200 ); } $check_max_lengths = wp_check_comment_data_max_lengths( $commentdata ); if ( is_wp_error( $check_max_lengths ) ) { return $check_max_lengths; } $comment_id = wp_new_comment( wp_slash( $commentdata ), true ); if ( is_wp_error( $comment_id ) ) { return $comment_id; } if ( ! $comment_id ) { return new WP_Error( 'comment_save_error', __( 'Error: The comment could not be saved. Please try again later.' ), 500 ); } return get_comment( $comment_id ); } /** * Registers the personal data exporter for comments. * * @since 4.9.6 * * @param array[] $exporters An array of personal data exporters. * @return array[] An array of personal data exporters. */ function wp_register_comment_personal_data_exporter( $exporters ) { $exporters['wordpress-comments'] = array( 'exporter_friendly_name' => __( 'WordPress Comments' ), 'callback' => 'wp_comments_personal_data_exporter', ); return $exporters; } /** * Finds and exports personal data associated with an email address from the comments table. * * @since 4.9.6 * * @param string $email_address The comment author email address. * @param int $page Comment page number. * @return array { * An array of personal data. * * @type array[] $data An array of personal data arrays. * @type bool $done Whether the exporter is finished. * } */ function wp_comments_personal_data_exporter( $email_address, $page = 1 ) { // Limit us to 500 comments at a time to avoid timing out. $number = 500; $page = (int) $page; $data_to_export = array(); $comments = get_comments( array( 'author_email' => $email_address, 'number' => $number, 'paged' => $page, 'orderby' => 'comment_ID', 'order' => 'ASC', 'update_comment_meta_cache' => false, ) ); $comment_prop_to_export = array( 'comment_author' => __( 'Comment Author' ), 'comment_author_email' => __( 'Comment Author Email' ), 'comment_author_url' => __( 'Comment Author URL' ), 'comment_author_IP' => __( 'Comment Author IP' ), 'comment_agent' => __( 'Comment Author User Agent' ), 'comment_date' => __( 'Comment Date' ), 'comment_content' => __( 'Comment Content' ), 'comment_link' => __( 'Comment URL' ), ); foreach ( (array) $comments as $comment ) { $comment_data_to_export = array(); foreach ( $comment_prop_to_export as $key => $name ) { $value = ''; switch ( $key ) { case 'comment_author': case 'comment_author_email': case 'comment_author_url': case 'comment_author_IP': case 'comment_agent': case 'comment_date': $value = $comment->{$key}; break; case 'comment_content': $value = get_comment_text( $comment->comment_ID ); break; case 'comment_link': $value = get_comment_link( $comment->comment_ID ); $value = sprintf( '%s', esc_url( $value ), esc_html( $value ) ); break; } if ( ! empty( $value ) ) { $comment_data_to_export[] = array( 'name' => $name, 'value' => $value, ); } } $data_to_export[] = array( 'group_id' => 'comments', 'group_label' => __( 'Comments' ), 'group_description' => __( 'User’s comment data.' ), 'item_id' => "comment-{$comment->comment_ID}", 'data' => $comment_data_to_export, ); } $done = count( $comments ) < $number; return array( 'data' => $data_to_export, 'done' => $done, ); } /** * Registers the personal data eraser for comments. * * @since 4.9.6 * * @param array $erasers An array of personal data erasers. * @return array An array of personal data erasers. */ function wp_register_comment_personal_data_eraser( $erasers ) { $erasers['wordpress-comments'] = array( 'eraser_friendly_name' => __( 'WordPress Comments' ), 'callback' => 'wp_comments_personal_data_eraser', ); return $erasers; } /** * Erases personal data associated with an email address from the comments table. * * @since 4.9.6 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $email_address The comment author email address. * @param int $page Comment page number. * @return array { * Data removal results. * * @type bool $items_removed Whether items were actually removed. * @type bool $items_retained Whether items were retained. * @type string[] $messages An array of messages to add to the personal data export file. * @type bool $done Whether the eraser is finished. * } */ function wp_comments_personal_data_eraser( $email_address, $page = 1 ) { global $wpdb; if ( empty( $email_address ) ) { return array( 'items_removed' => false, 'items_retained' => false, 'messages' => array(), 'done' => true, ); } // Limit us to 500 comments at a time to avoid timing out. $number = 500; $page = (int) $page; $items_removed = false; $items_retained = false; $comments = get_comments( array( 'author_email' => $email_address, 'number' => $number, 'paged' => $page, 'orderby' => 'comment_ID', 'order' => 'ASC', 'include_unapproved' => true, ) ); /* translators: Name of a comment's author after being anonymized. */ $anon_author = __( 'Anonymous' ); $messages = array(); foreach ( (array) $comments as $comment ) { $anonymized_comment = array(); $anonymized_comment['comment_agent'] = ''; $anonymized_comment['comment_author'] = $anon_author; $anonymized_comment['comment_author_email'] = ''; $anonymized_comment['comment_author_IP'] = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP ); $anonymized_comment['comment_author_url'] = ''; $anonymized_comment['user_id'] = 0; $comment_id = (int) $comment->comment_ID; /** * Filters whether to anonymize the comment. * * @since 4.9.6 * * @param bool|string $anon_message Whether to apply the comment anonymization (bool) or a custom * message (string). Default true. * @param WP_Comment $comment WP_Comment object. * @param array $anonymized_comment Anonymized comment data. */ $anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment ); if ( true !== $anon_message ) { if ( $anon_message && is_string( $anon_message ) ) { $messages[] = esc_html( $anon_message ); } else { /* translators: %d: Comment ID. */ $messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id ); } $items_retained = true; continue; } $args = array( 'comment_ID' => $comment_id, ); $updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args ); if ( $updated ) { $items_removed = true; clean_comment_cache( $comment_id ); } else { $items_retained = true; } } $done = count( $comments ) < $number; return array( 'items_removed' => $items_removed, 'items_retained' => $items_retained, 'messages' => $messages, 'done' => $done, ); } /** * Sets the last changed time for the 'comment' cache group. * * @since 5.0.0 */ function wp_cache_set_comments_last_changed() { wp_cache_set_last_changed( 'comment' ); } /** * Updates the comment type for a batch of comments. * * @since 5.5.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function _wp_batch_update_comment_type() { global $wpdb; $lock_name = 'update_comment_type.lock'; // Try to lock. $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) ); if ( ! $lock_result ) { $lock_result = get_option( $lock_name ); // Bail if we were unable to create a lock, or if the existing lock is still valid. if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) { wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' ); return; } } // Update the lock, as by this point we've definitely got a lock, just need to fire the actions. update_option( $lock_name, time() ); // Check if there's still an empty comment type. $empty_comment_type = $wpdb->get_var( "SELECT comment_ID FROM $wpdb->comments WHERE comment_type = '' LIMIT 1" ); // No empty comment type, we're done here. if ( ! $empty_comment_type ) { update_option( 'finished_updating_comment_type', true ); delete_option( $lock_name ); return; } // Empty comment type found? We'll need to run this script again. wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' ); /** * Filters the comment batch size for updating the comment type. * * @since 5.5.0 * * @param int $comment_batch_size The comment batch size. Default 100. */ $comment_batch_size = (int) apply_filters( 'wp_update_comment_type_batch_size', 100 ); // Get the IDs of the comments to update. $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM {$wpdb->comments} WHERE comment_type = '' ORDER BY comment_ID DESC LIMIT %d", $comment_batch_size ) ); if ( $comment_ids ) { $comment_id_list = implode( ',', $comment_ids ); // Update the `comment_type` field value to be `comment` for the next batch of comments. $wpdb->query( "UPDATE {$wpdb->comments} SET comment_type = 'comment' WHERE comment_type = '' AND comment_ID IN ({$comment_id_list})" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared ); // Make sure to clean the comment cache. clean_comment_cache( $comment_ids ); } delete_option( $lock_name ); } /** * In order to avoid the _wp_batch_update_comment_type() job being accidentally removed, * check that it's still scheduled while we haven't finished updating comment types. * * @ignore * @since 5.5.0 */ function _wp_check_for_scheduled_update_comment_type() { if ( ! get_option( 'finished_updating_comment_type' ) && ! wp_next_scheduled( 'wp_update_comment_type_batch' ) ) { wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_update_comment_type_batch' ); } } {"id":4631,"date":"2023-07-12T00:11:41","date_gmt":"2023-07-12T00:11:41","guid":{"rendered":"https:\/\/roozeavval.ir\/?p=4631"},"modified":"2023-07-12T00:11:41","modified_gmt":"2023-07-12T00:11:41","slug":"%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7","status":"publish","type":"post","link":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/","title":{"rendered":"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627"},"content":{"rendered":"

\"\"<\/p>\n

\u0645\u062f\u06cc\u0631\u06a9\u0644 \u0631\u0648\u0627\u0628\u0637 \u0639\u0645\u0648\u0645\u06cc \u062f\u0641\u062a\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0628\u0627 \u0627\u0634\u0627\u0631\u0647 \u0628\u0647 \u0633\u0641\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0627\u06cc\u0631\u0627\u0646 \u0628\u0647 \u0642\u0627\u0631\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u067e\u0633 \u0627\u0632 \u06f1\u06f1 \u0633\u0627\u0644\u060c \u062f\u0631 \u062a\u0648\u06cc\u06cc\u062a\u06cc \u0646\u0648\u0634\u062a: \u062f\u0631 \u0645\u0633\u06cc\u0631 \u0627\u062d\u06cc\u0627\u06cc \u0641\u0631\u0635\u062a \u0647\u0627\u06cc \u062a\u062c\u0627\u0631\u06cc-\u0633\u06cc\u0627\u0633\u06cc\u060c \u200e\u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 \u0647\u0645 \u0645\u0648\u0631\u062f \u062a\u0648\u062c\u0647 \u0627\u0633\u062a. <\/P>
\n

\u0628\u0647 \u06af\u0632\u0627\u0631\u0634 \u0627\u06cc\u0633\u0646\u0627\u060c \u0645\u062a\u0646 \u062a\u0648\u06cc\u06cc\u062a \u0645\u062d\u0645\u062f\u0645\u0647\u062f\u06cc \u0631\u062d\u06cc\u0645\u06cc \u0628\u0647 \u0634\u0631\u062d \u0632\u06cc\u0631 \u0627\u0633\u062a:<\/P>
\n

“\u0648 \u062d\u0627\u0644\u0627 \u0627\u0641\u0631\u06cc\u0642\u0627 \u067e\u0633 \u0627\u0632 \u06f1\u06f1 \u0633\u0627\u0644!
\u0622\u0641\u0631\u06cc\u0642\u0627 \u0627\u0632 \u0646\u0638\u0631 \u062a\u0639\u062f\u0627\u062f \u06a9\u0634\u0648\u0631 \u0627\u0648\u0644\u06cc\u0646 \u0648 \u0627\u0632 \u0646\u0638\u0631 \u062c\u0645\u0639\u06cc\u062a \u062f\u0648\u0645\u06cc\u0646 \u0642\u0627\u0631\u0647 \u0627\u0633\u062a.
\u0627\u0645\u0627 \u0645\u062a\u0627\u0633\u0641\u0627\u0646\u0647 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0633\u0627\u0628\u0642 \u0628\u0647 \u0647\u06cc\u0686 \u06cc\u06a9 \u0627\u0632 \u0627\u06cc\u0646 \u06f5\u06f4 \u06a9\u0634\u0648\u0631 \u0633\u0641\u0631 \u0646\u06a9\u0631\u062f\u061b\u0646\u0647 \u0641\u0642\u0637 \u0633\u0641\u0631 \u0631\u0633\u0645\u06cc \u06a9\u0647 \u062d\u062a\u06cc \u0628\u0631\u0627\u06cc \u06cc\u06a9 \u0627\u062c\u0644\u0627\u0633 \u06cc\u0627 \u062a\u0648\u0642\u0641 \u062f\u0631 \u0645\u0633\u06cc\u0631 \u0633\u0641\u0631 \u0628\u0647 \u063a\u0631\u0628!
\u0646\u06af\u0627\u0647 \u06a9\u0646\u06cc\u062f \u0628\u0647 \u062a\u0639\u062f\u0627\u062f \u0633\u0641\u0631\u0647\u0627\u06cc \u0631\u0648\u0633\u0627\u06cc \u062c\u0645\u0647\u0648\u0631 \u0686\u06cc\u0646\u060c\u062a\u0631\u06a9\u06cc\u0647\u060c\u0647\u0646\u062f \u062f\u0631 \u0622\u0646 \u0627\u06cc\u0627\u0645.<\/P>\u0645\u0646\u0628\u0639 \u062e\u0628\u0631: \u062e\u0628\u0631 \u06af\u0632\u0627\u0631\u06cc \u0627\u06cc\u0633\u0646\u0627\u0622\u062e\u0631\u06cc\u0646 \u0627\u062e\u0628\u0627\u0631,\u067e\u0631\u0628\u0627\u0632\u062f\u06cc\u062f \u062a\u0631\u06cc\u0646 \u0627\u062e\u0628\u0627\u0631, \u0627\u062e\u0628\u0627\u0631 \u0631\u0648\u0632
\n\u0644\u06cc\u0646\u06a9 \u0645\u0637\u0627\u0644\u0628 \u062f\u06cc\u06af\u0631\u0645\u0648\u062a\u0648\u0631 \u0628\u0631\u0642 \u0686\u06cc\u0633\u062a \u0648 \u0686\u0647 \u06a9\u0627\u0631\u0628\u0631\u062f\u0647\u0627\u06cc\u06cc \u062f\u0627\u0631\u062f\u061f<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"

\u0645\u062f\u06cc\u0631\u06a9\u0644 \u0631\u0648\u0627\u0628\u0637 \u0639\u0645\u0648\u0645\u06cc \u062f\u0641\u062a\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0628\u0627 \u0627\u0634\u0627\u0631\u0647 \u0628\u0647 \u0633\u0641\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0627\u06cc\u0631\u0627\u0646 \u0628\u0647 \u0642\u0627\u0631\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u067e\u0633 \u0627\u0632 \u06f1\u06f1 \u0633\u0627\u0644\u060c \u062f\u0631 \u062a\u0648\u06cc\u06cc\u062a\u06cc \u0646\u0648\u0634\u062a: \u062f\u0631 \u0645\u0633\u06cc\u0631 \u0627\u062d\u06cc\u0627\u06cc \u0641\u0631\u0635\u062a \u0647\u0627\u06cc \u062a\u062c\u0627\u0631\u06cc-\u0633\u06cc\u0627\u0633\u06cc\u060c \u200e\u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 \u0647\u0645 \u0645\u0648\u0631\u062f \u062a\u0648\u062c\u0647...<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[],"class_list":["post-4631","post","type-post","status-publish","format-standard","hentry","category-1"],"yoast_head":"\n\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 - \u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/roozeavval.ir\/\u062a\u0648\u062c\u0647-\u062f\u0648\u0644\u062a-\u0628\u0647-\u0622\u0641\u0631\u06cc\u0642\u0627-\u0642\u0627\u0631\u0647-\u0641\u0631\u0635\u062a\u0647\u0627\/\" \/>\n<meta property=\"og:locale\" content=\"fa_IR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 - \u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f\" \/>\n<meta property=\"og:description\" content=\"\u0645\u062f\u06cc\u0631\u06a9\u0644 \u0631\u0648\u0627\u0628\u0637 \u0639\u0645\u0648\u0645\u06cc \u062f\u0641\u062a\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0628\u0627 \u0627\u0634\u0627\u0631\u0647 \u0628\u0647 \u0633\u0641\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0627\u06cc\u0631\u0627\u0646 \u0628\u0647 \u0642\u0627\u0631\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u067e\u0633 \u0627\u0632 \u06f1\u06f1 \u0633\u0627\u0644\u060c \u062f\u0631 \u062a\u0648\u06cc\u06cc\u062a\u06cc \u0646\u0648\u0634\u062a: \u062f\u0631 \u0645\u0633\u06cc\u0631 \u0627\u062d\u06cc\u0627\u06cc \u0641\u0631\u0635\u062a \u0647\u0627\u06cc \u062a\u062c\u0627\u0631\u06cc-\u0633\u06cc\u0627\u0633\u06cc\u060c \u200e\u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 \u0647\u0645 \u0645\u0648\u0631\u062f \u062a\u0648\u062c\u0647...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/roozeavval.ir\/\u062a\u0648\u062c\u0647-\u062f\u0648\u0644\u062a-\u0628\u0647-\u0622\u0641\u0631\u06cc\u0642\u0627-\u0642\u0627\u0631\u0647-\u0641\u0631\u0635\u062a\u0647\u0627\/\" \/>\n<meta property=\"og:site_name\" content=\"\u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f\" \/>\n<meta property=\"article:published_time\" content=\"2023-07-12T00:11:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.isna.ir\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0646\u0648\u0634\u062a\u0647\u200c\u0634\u062f\u0647 \u0628\u062f\u0633\u062a\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin_mti1360\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"http:\/\/roozeavval.ir\/#website\",\"url\":\"http:\/\/roozeavval.ir\/\",\"name\":\"\\u0622\\u06cc\\u0627 \\u062e\\u0634\\u06a9\\u0633\\u0627\\u0644\\u06cc \\u0628\\u0627 \\u0628\\u0627\\u0631\\u0648\\u0631\\u06cc \\u0627\\u0628\\u0631\\u0647\\u0627 \\u0627\\u0632 \\u0628\\u06cc\\u0646 \\u0645\\u06cc\\u200c\\u0631\\u0648\\u062f\\u061f\",\"description\":\"\\u0627\\u0637\\u0644\\u0627\\u0639\\u0627\\u062a \\u0639\\u0645\\u0648\\u0645\\u06cc\\u060c\\u0633\\u0631\\u06af\\u0631\\u0645\\u06cc\\u060c\\u0631\\u0648\\u0627\\u0646\\u0634\\u0646\\u0627\\u0633\\u06cc\\u060c\\u067e\\u0632\\u0634\\u06a9\\u06cc\\u060c\\u06af\\u0631\\u062f\\u0634\\u06af\\u0631\\u06cc\\u060c\\u0637\\u0628 \\u0633\\u0646\\u062a\\u06cc\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/roozeavval.ir\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fa-IR\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#primaryimage\",\"inLanguage\":\"fa-IR\",\"url\":\"https:\/\/cdn.isna.ir\",\"contentUrl\":\"https:\/\/cdn.isna.ir\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#webpage\",\"url\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/\",\"name\":\"\\u062a\\u0648\\u062c\\u0647 \\u062f\\u0648\\u0644\\u062a \\u0628\\u0647 \\u0622\\u0641\\u0631\\u06cc\\u0642\\u0627 \\u0642\\u0627\\u0631\\u0647 \\u0641\\u0631\\u0635\\u062a\\u0647\\u0627 - \\u0622\\u06cc\\u0627 \\u062e\\u0634\\u06a9\\u0633\\u0627\\u0644\\u06cc \\u0628\\u0627 \\u0628\\u0627\\u0631\\u0648\\u0631\\u06cc \\u0627\\u0628\\u0631\\u0647\\u0627 \\u0627\\u0632 \\u0628\\u06cc\\u0646 \\u0645\\u06cc\\u200c\\u0631\\u0648\\u062f\\u061f\",\"isPartOf\":{\"@id\":\"http:\/\/roozeavval.ir\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#primaryimage\"},\"datePublished\":\"2023-07-12T00:11:41+00:00\",\"dateModified\":\"2023-07-12T00:11:41+00:00\",\"author\":{\"@id\":\"http:\/\/roozeavval.ir\/#\/schema\/person\/3c121e170e4846b901b250f3cd25b8cb\"},\"breadcrumb\":{\"@id\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#breadcrumb\"},\"inLanguage\":\"fa-IR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\\u062e\\u0627\\u0646\\u0647\",\"item\":\"http:\/\/roozeavval.ir\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\\u062a\\u0648\\u062c\\u0647 \\u062f\\u0648\\u0644\\u062a \\u0628\\u0647 \\u0622\\u0641\\u0631\\u06cc\\u0642\\u0627 \\u0642\\u0627\\u0631\\u0647 \\u0641\\u0631\\u0635\\u062a\\u0647\\u0627\"}]},{\"@type\":\"Person\",\"@id\":\"http:\/\/roozeavval.ir\/#\/schema\/person\/3c121e170e4846b901b250f3cd25b8cb\",\"name\":\"admin_mti1360\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/roozeavval.ir\/#personlogo\",\"inLanguage\":\"fa-IR\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cfd5d4ace14c34c6d6c3a34182721cd1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cfd5d4ace14c34c6d6c3a34182721cd1?s=96&d=mm&r=g\",\"caption\":\"admin_mti1360\"},\"sameAs\":[\"http:\/\/roozeavval.ir\"],\"url\":\"https:\/\/roozeavval.ir\/author\/admin_mti1360\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 - \u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/roozeavval.ir\/\u062a\u0648\u062c\u0647-\u062f\u0648\u0644\u062a-\u0628\u0647-\u0622\u0641\u0631\u06cc\u0642\u0627-\u0642\u0627\u0631\u0647-\u0641\u0631\u0635\u062a\u0647\u0627\/","og_locale":"fa_IR","og_type":"article","og_title":"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 - \u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f","og_description":"\u0645\u062f\u06cc\u0631\u06a9\u0644 \u0631\u0648\u0627\u0628\u0637 \u0639\u0645\u0648\u0645\u06cc \u062f\u0641\u062a\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0628\u0627 \u0627\u0634\u0627\u0631\u0647 \u0628\u0647 \u0633\u0641\u0631 \u0631\u0626\u06cc\u0633 \u062c\u0645\u0647\u0648\u0631 \u0627\u06cc\u0631\u0627\u0646 \u0628\u0647 \u0642\u0627\u0631\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u067e\u0633 \u0627\u0632 \u06f1\u06f1 \u0633\u0627\u0644\u060c \u062f\u0631 \u062a\u0648\u06cc\u06cc\u062a\u06cc \u0646\u0648\u0634\u062a: \u062f\u0631 \u0645\u0633\u06cc\u0631 \u0627\u062d\u06cc\u0627\u06cc \u0641\u0631\u0635\u062a \u0647\u0627\u06cc \u062a\u062c\u0627\u0631\u06cc-\u0633\u06cc\u0627\u0633\u06cc\u060c \u200e\u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 \u0647\u0645 \u0645\u0648\u0631\u062f \u062a\u0648\u062c\u0647...","og_url":"https:\/\/roozeavval.ir\/\u062a\u0648\u062c\u0647-\u062f\u0648\u0644\u062a-\u0628\u0647-\u0622\u0641\u0631\u06cc\u0642\u0627-\u0642\u0627\u0631\u0647-\u0641\u0631\u0635\u062a\u0647\u0627\/","og_site_name":"\u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f","article_published_time":"2023-07-12T00:11:41+00:00","og_image":[{"url":"https:\/\/cdn.isna.ir"}],"twitter_card":"summary_large_image","twitter_misc":{"\u0646\u0648\u0634\u062a\u0647\u200c\u0634\u062f\u0647 \u0628\u062f\u0633\u062a":"admin_mti1360"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebSite","@id":"http:\/\/roozeavval.ir\/#website","url":"http:\/\/roozeavval.ir\/","name":"\u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f","description":"\u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0639\u0645\u0648\u0645\u06cc\u060c\u0633\u0631\u06af\u0631\u0645\u06cc\u060c\u0631\u0648\u0627\u0646\u0634\u0646\u0627\u0633\u06cc\u060c\u067e\u0632\u0634\u06a9\u06cc\u060c\u06af\u0631\u062f\u0634\u06af\u0631\u06cc\u060c\u0637\u0628 \u0633\u0646\u062a\u06cc","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/roozeavval.ir\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fa-IR"},{"@type":"ImageObject","@id":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#primaryimage","inLanguage":"fa-IR","url":"https:\/\/cdn.isna.ir","contentUrl":"https:\/\/cdn.isna.ir"},{"@type":"WebPage","@id":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#webpage","url":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/","name":"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627 - \u0622\u06cc\u0627 \u062e\u0634\u06a9\u0633\u0627\u0644\u06cc \u0628\u0627 \u0628\u0627\u0631\u0648\u0631\u06cc \u0627\u0628\u0631\u0647\u0627 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f\u061f","isPartOf":{"@id":"http:\/\/roozeavval.ir\/#website"},"primaryImageOfPage":{"@id":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#primaryimage"},"datePublished":"2023-07-12T00:11:41+00:00","dateModified":"2023-07-12T00:11:41+00:00","author":{"@id":"http:\/\/roozeavval.ir\/#\/schema\/person\/3c121e170e4846b901b250f3cd25b8cb"},"breadcrumb":{"@id":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#breadcrumb"},"inLanguage":"fa-IR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/roozeavval.ir\/%d8%aa%d9%88%d8%ac%d9%87-%d8%af%d9%88%d9%84%d8%aa-%d8%a8%d9%87-%d8%a2%d9%81%d8%b1%db%8c%d9%82%d8%a7-%d9%82%d8%a7%d8%b1%d9%87-%d9%81%d8%b1%d8%b5%d8%aa%d9%87%d8%a7\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u062e\u0627\u0646\u0647","item":"http:\/\/roozeavval.ir\/"},{"@type":"ListItem","position":2,"name":"\u062a\u0648\u062c\u0647 \u062f\u0648\u0644\u062a \u0628\u0647 \u0622\u0641\u0631\u06cc\u0642\u0627 \u0642\u0627\u0631\u0647 \u0641\u0631\u0635\u062a\u0647\u0627"}]},{"@type":"Person","@id":"http:\/\/roozeavval.ir\/#\/schema\/person\/3c121e170e4846b901b250f3cd25b8cb","name":"admin_mti1360","image":{"@type":"ImageObject","@id":"http:\/\/roozeavval.ir\/#personlogo","inLanguage":"fa-IR","url":"https:\/\/secure.gravatar.com\/avatar\/cfd5d4ace14c34c6d6c3a34182721cd1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cfd5d4ace14c34c6d6c3a34182721cd1?s=96&d=mm&r=g","caption":"admin_mti1360"},"sameAs":["http:\/\/roozeavval.ir"],"url":"https:\/\/roozeavval.ir\/author\/admin_mti1360\/"}]}},"_links":{"self":[{"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/posts\/4631"}],"collection":[{"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/comments?post=4631"}],"version-history":[{"count":1,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/posts\/4631\/revisions"}],"predecessor-version":[{"id":4632,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/posts\/4631\/revisions\/4632"}],"wp:attachment":[{"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/media?parent=4631"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/categories?post=4631"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/roozeavval.ir\/wp-json\/wp\/v2\/tags?post=4631"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}