1

I'm trying to figure out a way to not redirect users to the single post when adding a threaded comment on any post on the "Home" Posts page.

What I have now:

• My Home page shows latest posts (say 10 as an example) and uses index.php instead of archives.php.

• Threaded comments are enabled in Dashboard>Discussion (User must be logged in, if it matters).

• Under each post on the Home page, all comments and a comment reply box are shown. When a user adds a new comment to any of the posts, they stay on the Home page and are not taken to the single post.

But when a user tries to add a new threaded comment via the "Reply" link, they are redirected to the single post to comment.

Right now, by using this in functions.php:

add_filter('comment_post_redirect', 'redirect_after_comment');
function redirect_after_comment($location)
{
return $_SERVER["HTTP_REFERER"];
}

I can redirect users back to the Home page after they submit a new (unthreaded) comment.

However, this doesn't work for threaded comments. The "Reply" link to submit a threaded comment points to the single post and then doesn't redirect back to Home/Posts.

enter image description here


How can I change the "Reply" link to allow users to add a threaded comment while staying on the Home/Posts page?

Is there any other functionality that I need to be aware of in order to keep users on the Home page for all threaded comments?

index.php:

<?php
/**
 * The main template file
 *
 * This is the most generic template file in a WordPress theme
 * and one of the two required files for a theme (the other being style.css).
 * It is used to display a page when nothing more specific matches a query.
 * E.g., it puts together the home page when no home.php file exists.
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package newco_theme
 */

get_header();
?>
<div class="g-columns__group">
    <div class="g-columns__item--nine">

    <main id="primary" class="g-layout__content">

        <?php
        if ( have_posts() ) :

            if ( is_home() && ! is_front_page() ) :
                ?>
                <header>
                    <h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
                </header>
                <?php
            endif;

            /* Start the Loop */
            while ( have_posts() ) :
                the_post();

                /*
                 * Include the Post-Type-specific template for the content.
                 * If you want to override this in a child theme, then include a file
                 * called content-___.php (where ___ is the Post Type name) and that will be used instead.
                 */
                get_template_part( 'template-parts/content', get_post_type() );

            endwhile;

        endif;
        ?>
        
<br />

<?php if(function_exists('wp_paginate')) { wp_paginate(); } ?>



    </main><!-- #main -->
    </div>

<?php
get_sidebar();
get_footer();

content.php:

<?php
/**
 * Template part for displaying posts
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package newco_theme
 */

?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php
        
        if ( is_singular() ) :
            the_title( '<h1 class="entry-title">', '</h1>' );
        else :
            the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
        endif;

        if ( 'post' === get_post_type() ) :
            ?>
            <div class="entry-meta">
                <?php
                echo 'Posted on: ' .get_the_date();
                newco_theme_posted_by();
                ?>
            </div><!-- .entry-meta -->
        <?php endif; ?>
    </header><!-- .entry-header -->


    <div class="entry-content">
        <?php
        the_content(
            sprintf(
                wp_kses(
                    /* translators: %s: Name of current post. Only visible to screen readers */
                    __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'newco-theme' ),
                    array(
                        'span' => array(
                            'class' => array(),
                        ),
                    )
                ),
                wp_kses_post( get_the_title() )
            )
        );

        wp_link_pages(
            array(
                'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'newco-theme' ),
                'after'  => '</div>',
            )
        );
        ?>
    </div><!-- .entry-content -->


<?php if(!is_single()){?>



    <footer class="entry-footer">
        <div class="_post-loop">
            <div class="_post-links"><?php no_comments_entry_footer(); ?></div>

        <?php global $withcomments; $withcomments = true; comments_template(); ?>

        
        </div>

<?php comment_form(); ?>

<hr>

    </footer><!-- .entry-footer -->
    <?php } ?>

</article><!-- #post-<?php the_ID(); ?> -->

comments.php

<?php
/**
 * The template for displaying comments
 *
 * This is the template that displays the area of the page that contains both the current comments
 * and the comment form.
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package newco_theme
 */

/*
 * If the current post is protected by a password and
 * the visitor has not yet entered the password we will
 * return early without loading the comments.
 */
if ( post_password_required() ) {
    return;
}
?>

<div id="comments" class="comments-area">

    <?php
    // You can start editing here -- including this comment!
    if ( have_comments() ) :
        ?>
        <h2 class="comments-title">
            <?php
            $newco_theme_comment_count = get_comments_number();
            if ( '1' === $newco_theme_comment_count ) {
                printf(
                    /* translators: 1: title. */
                    esc_html__( 'One comment on &ldquo;%1$s&rdquo;', 'newco-theme' ),
                    '<span>' . wp_kses_post( get_the_title() ) . '</span>'
                );
            } else {
                printf( 
                    /* translators: 1: comment count number, 2: title. */
                    esc_html( _nx( '%1$s comments on &ldquo;%2$s&rdquo;', '%1$s comments on &ldquo;%2$s&rdquo;', $newco_theme_comment_count, 'comments title', 'newco-theme' ) ),
                    number_format_i18n( $newco_theme_comment_count ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
                    '<span>' . wp_kses_post( get_the_title() ) . '</span>'
                );
            }
            ?>
        </h2><!-- .comments-title -->

        <?php the_comments_navigation(); ?>

        <ol class="comment-list">
            <?php
            wp_list_comments(
                array(
                    'style'      => 'ol',
                    'short_ping' => true,
                )
            );
            ?>
        </ol><!-- .comment-list -->

        <?php
        the_comments_navigation();

        // If comments are closed and there are comments, let's leave a little note, shall we?
        if ( ! comments_open() ) :
            ?>
            <p class="no-comments"><?php esc_html_e( 'Comments are closed.', 'newco-theme' ); ?></p>
            <?php
        endif;

    endif; // Check for have_comments().

    comment_form();
    ?>

</div><!-- #comments -->

the function no_comments_entry_footer:

if ( ! function_exists( 'no_comments_entry_footer' ) ) :
    /**
     * Prints HTML with meta information for the categories, tags and comments.
     */
    function no_comments_entry_footer() {
        // Hide category and tag text for pages.
        if ( 'post' === get_post_type() ) {
            /* translators: used between list items, there is a space after the comma */
            $categories_list = get_the_category_list( esc_html__( ', ', 'newco-theme' ) );
            if ( $categories_list ) {
                /* translators: 1: list of categories. */
                printf( '<span class="cat-links">' . esc_html__( 'Posted in %1$s', 'newco-theme' ) . '</span>', $categories_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }

            /* translators: used between list items, there is a space after the comma */
            $tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'newco-theme' ) );
            if ( $tags_list ) {
                /* translators: 1: list of tags. */
                printf( '<span class="tags-links">' . esc_html__( 'Tagged %1$s', 'newco-theme' ) . '</span>', $tags_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }
        }

        edit_post_link(
            sprintf(
                wp_kses(
                    /* translators: %s: Name of current post. Only visible to screen readers */
                    __( 'Edit <span class="screen-reader-text">%s</span>', 'newco-theme' ),
                    array(
                        'span' => array(
                            'class' => array(),
                        ),
                    )
                ),
                wp_kses_post( get_the_title() )
            ),
            '<span class="edit-link">',
            '</span>'
        );
    }
endif;

2 Answers 2

2
+100

As you may have guessed WordPress deals differently with threaded comments. By default the comment reply link is generated by the get_comment_reply_link function and the comment form with the send-button by comment_form.

If your theme supports threaded comments it adds the comment-reply script. This script moves around the comment form to the (threaded) comment that the user wishes to reply to. In the process it needs to change the POST call, else the server won't know to which comment to attach the reply. Your scenario is not taken into account and the script has no hooks.

So, this leaves you two options. One is to write your own script. The other, more feasible one is to intercept the POST call, like you have done for regular comments, with the comment_post_redirect hook (which is bypassed when the form is submitted by the script). Here's what I would do roughly:

5
  • Thanks, this is interesting; I'm trying to understand it. So does the hidden field contain the comment? Or it is only to test for commenting on the front page? And when the commenter is returned to the home page, are we sure that the threaded reply will be displayed as threaded? And I guess I could use jQuery to scroll the user back to he comment once posted. Commented Sep 16 at 19:26
  • The hidden field does not contain anything. You just use its presence to distinguish between a comment form filled in on the single page or the home page, so you can redirect in the latter case. The idea is to interfere as less as possible with the usual affairs. Theoretically, this is a new page load and the comment should end up where it belongs by itself (you could use jQuery if you want to scroll to that comment, but you can also add an anchor #comment-1234 to the url). However, you are hacking the system here, so it's difficult to predict exactly what will happen.
    – cjbj
    Commented Sep 17 at 7:36
  • So it sounds like WordPress was never designed to work this way? I thought of a possible workaround to trying to keep users on home when commenting; clicking Reply on home takes a commenter to the single post, but then redirect them back to home after comment submit. Since the comment ID will be the same, maybe I can scroll to that comment on home. Commented Sep 18 at 4:44
  • I'm not an insider, but yes, I think the comment section was designed for single pages, not for multipost pages
    – cjbj
    Commented Sep 18 at 8:20
  • 1
    Thanks, I think what I will try now is to redirect back to home after comment submit, and if there is a referrer from Home from the 'Reply" link, as I don't want to redirect if someone is already on a single post and comments. Commented Sep 20 at 16:25
0

One way to fix this problem is to add reply via AJAX.

The following codes use SweetAlert to make a reply popup. When you click on the Reply button, the popup will appear for you to fill in the reply. When click Submit Reply, it will submit via AJAX, so no redirection here. When the form submission is successful, it will reload the page to show new replies.

The codes are written and tested with the default Twenty Twenty-Four theme. If your theme use a different class for the reply button, please update as needed:

Step 1: Enqueue Scripts

Ensure you enqueue the necessary scripts in your theme's functions.php file:

function enqueue_custom_scripts() {
    // Enqueue jQuery, remove this if your theme has already enqueue jQuery
    wp_enqueue_script('jquery');

    // Enqueue SweetAlert
    wp_enqueue_script('sweetalert', 'https://cdn.jsdelivr.net/npm/sweetalert2@11', [], null, true);

    // Enqueue custom script for handling AJAX
    wp_enqueue_script('custom-ajax-script', get_template_directory_uri() . '/js/custom-ajax.js', ['jquery'], null, true);

    // Localize script to pass AJAX URL
    wp_localize_script('custom-ajax-script', 'ajax_object', [
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('comment_nonce')
    ]);
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');

Step 2: Create the AJAX Handler in PHP

Add the following code in your functions.php to handle the AJAX request for adding comments:

function handle_ajax_comment() {
    // Check nonce for security
    check_ajax_referer('comment_nonce', 'nonce');

    // Get the comment data
    $comment_post_ID = intval($_POST['post_id']);
    $comment_content = sanitize_text_field($_POST['comment_content']);
    $parent_comment_id = isset($_POST['parent_id']) ? intval($_POST['parent_id']) : 0;

    // Prepare the comment data
    $comment_data = [
        'comment_post_ID' => $comment_post_ID,
        'comment_content' => $comment_content,
        'comment_type' => '',
        'comment_parent' => $parent_comment_id,
        'user_id' => get_current_user_id(),
        'comment_approved' => 1, // Automatically approve the comment
    ];

    // Insert the comment
    $comment_id = wp_insert_comment($comment_data);

    if ($comment_id) {
        // Send a success response
        wp_send_json_success(['message' => 'Comment added successfully!']);
    } else {
        // Send an error response
        wp_send_json_error(['message' => 'Failed to add comment.']);
    }

    wp_die(); // Required to terminate immediately and return a proper response
}
add_action('wp_ajax_add_comment', 'handle_ajax_comment');
add_action('wp_ajax_nopriv_add_comment', 'handle_ajax_comment'); // For non-logged in users

Step 3: Create the JavaScript File

Create a JavaScript file named custom-ajax.js in your theme's js directory with the following content:

jQuery(document).ready(function($) {
    // Attach a click event handler to the reply button
    $('.comment-reply-link').on('click', function(e) {
        e.preventDefault(); // Prevent the default action

        // Get the post ID and parent comment ID
        var postID = $(this).data('postid'); // Assuming the button has a data attribute for post ID
        var parentID = $(this).data('commentid'); // Assuming the button has a data attribute for parent comment ID

        // Create the comment form HTML
        var commentFormHtml = `
            <form id="ajax-comment-form">
                <textarea name="comment_content" required placeholder="Your reply..." rows="4" style="width: 100%;"></textarea>
                <input type="hidden" name="parent_id" value="${parentID}" />
                <input type="hidden" name="post_id" value="${postID}" />
            </form>
        `;

        // Show SweetAlert with the comment form
        Swal.fire({
            title: 'Leave a Reply',
            html: commentFormHtml,
            showCancelButton: true,
            confirmButtonText: 'Submit Reply',
            preConfirm: () => {
                // Get the form data
                const form = document.getElementById('ajax-comment-form');
                const commentContent = form.querySelector('textarea[name="comment_content"]').value;
                const postID = form.querySelector('input[name="post_id"]').value;
                const parentID = form.querySelector('input[name="parent_id"]').value;

                return { comment_content: commentContent, post_id: postID, parent_id: parentID };
            }
        }).then((result) => {
            if (result.isConfirmed) {
                // Proceed with AJAX request
                $.ajax({
                    type: 'POST',
                    url: ajax_object.ajax_url,
                    data: {
                        action: 'add_comment',
                        post_id: result.value.post_id,
                        comment_content: result.value.comment_content,
                        parent_id: result.value.parent_id,
                        nonce: ajax_object.nonce // Send the nonce for security
                    },
                    success: function(response) {
                        if (response.success) {
                            Swal.fire('Success!', response.data.message, 'success').then(() => {
                                location.reload(); // Reload the page after successful submission
                            });
                        } else {
                            Swal.fire('Error!', response.data.message, 'error');
                        }
                    },
                    error: function() {
                        Swal.fire('Error!', 'An error occurred while adding the comment.', 'error');
                    }
                });
            }
        });
        return false;
    });
});

1
  • Thanks for the examples, but I don't want to use a popup or increase the complexity of what I am doing Commented Sep 20 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.