Skip to:
Content

bbPress.org

Changeset 4944


Ignore:
Timestamp:
05/23/2013 07:09:03 AM (8 years ago)
Author:
johnjamesjacoby
Message:

Hierarchical replies:

  • Introduce setting, option, functions, JS, CSS, and Walker class to support hierarchical replies.
  • Tweak functions where saving the additional reply_to meta data is necessary.
  • Add meta data field in dashboard to show the reply_to ID.
  • There will likely be more tweaking necessary, as we test this further and get more eyes on the code.
  • Fixes #2036.
  • Props jmdodd for this huge effort.
Location:
trunk
Files:
1 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/includes/admin/metaboxes.php

    r4902 r4944  
    401401    $reply_topic_id = bbp_get_reply_topic_id( $post_id );
    402402    $reply_forum_id = bbp_get_reply_forum_id( $post_id );
     403    $reply_to       = bbp_get_reply_to(       $post_id );
    403404
    404405    // Allow individual manipulation of reply forum
     
    436437    </p>
    437438
     439    <p>
     440        <strong class="label"><?php _e( 'Reply To:', 'bbpress' ); ?></strong>
     441        <label class="screen-reader-text" for="bbp_reply_to"><?php _e( 'Reply To', 'bbpress' ); ?></label>
     442        <input name="bbp_reply_to" id="bbp_reply_to" type="text" value="<?php echo esc_attr( $reply_to ); ?>" />
     443    </p>
     444
    438445    <?php
    439446    wp_nonce_field( 'bbp_reply_metabox_save', 'bbp_reply_metabox' );
  • trunk/includes/admin/replies.php

    r4909 r4944  
    221221                    '<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the reply belongs to. Select the forum, or leave the default (Use Forum of Topic) to post the reply in forum of the topic.', 'bbpress' ) . '</li>' .
    222222                    '<li>' . __( '<strong>Topic</strong> determines the parent topic that the reply belongs to.', 'bbpress' ) . '</li>' .
     223                    '<li>' . __( '<strong>Reply To</strong> determines the threading of the reply.', 'bbpress' ) . '</li>' .
    223224                '</ul>'
    224225        ) );
     
    301302        $topic_id = !empty( $_POST['parent_id']    ) ? (int) $_POST['parent_id']    : 0;
    302303        $forum_id = !empty( $_POST['bbp_forum_id'] ) ? (int) $_POST['bbp_forum_id'] : bbp_get_topic_forum_id( $topic_id );
     304        $reply_to = !empty( $_POST['bbp_reply_to'] ) ? (int) $_POST['bbp_reply_to'] : 0;
    303305
    304306        // Get reply author data
     
    308310
    309311        // Formally update the reply
    310         bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit );
     312        bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit, $reply_to );
    311313
    312314        // Allow other fun things to happen
    313         do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id );
     315        do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id, $reply_to );
    314316        do_action( 'bbp_author_metabox_save',           $reply_id, $anonymous_data      );
    315317
  • trunk/includes/admin/settings.php

    r4938 r4944  
    170170                'sanitize_callback' => 'intval',
    171171                'args'              => array()
     172            ),
     173
     174            // Set reply threading level
     175            '_bbp_thread_replies_depth' => array(
     176                'title'             => __( 'Thread replies to topics', 'bbpress' ),
     177                'callback'          => 'bbp_admin_setting_callback_thread_replies_depth',
     178                'sanitize_callback' => 'intval',
     179                'args'              => array()
    172180            )
    173181        ),
     
    177185        'bbp_settings_theme_compat' => array(
    178186
    179             // Replies per page setting
     187            // Theme package setting
    180188            '_bbp_theme_package_id' => array(
    181189                'title'             => __( 'Current Package', 'bbpress' ),
     
    492500 * Allow topic tags setting field
    493501 *
    494  * @since bbPress (r####)
     502 * @since bbPress (r4944)
    495503 *
    496504 * @uses checked() To display the checked attribute
     
    501509    <input id="_bbp_allow_topic_tags" name="_bbp_allow_topic_tags" type="checkbox" id="_bbp_allow_topic_tags" value="1" <?php checked( bbp_allow_topic_tags( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_topic_tags' ); ?> />
    502510    <label for="_bbp_allow_topic_tags"><?php _e( 'Allow topics to have tags', 'bbpress' ); ?></label>
     511
     512<?php
     513}
     514
     515/**
     516 * Hierarchical reply maximum depth level setting field
     517 *
     518 * Replies will be threaded if depth is 2 or greater
     519 *
     520 * @since bbPress (r4944)
     521 *
     522 * @uses apply_filters() Calls 'bbp_thread_replies_depth_max' to set a
     523 *                        maximum displayed level
     524 * @uses selected() To display the selected attribute
     525 */
     526function bbp_admin_setting_callback_thread_replies_depth() {
     527
     528    // Set maximum depth for dropdown
     529    $max_depth     = (int) apply_filters( 'bbp_thread_replies_depth_max', 10 );
     530    $current_depth = bbp_thread_replies_depth(); ?>
     531
     532    <select id="_bbp_thread_replies_depth" name="_bbp_thread_replies_depth">
     533    <?php for ( $i = 0; $i <= $max_depth; $i++ ) : ?>
     534
     535        <option value="<?php echo esc_attr( $i ); ?>" <?php selected( $i, $current_depth ); ?>><?php echo esc_html( $i ); ?></option>
     536
     537    <?php endfor; ?>
     538    </select>
     539
     540    <label for="_bbp_thread_replies_depth"><?php _e( 'levels deep', 'bbpress' ); ?></label>
    503541
    504542<?php
  • trunk/includes/common/classes.php

    r4501 r4944  
    260260}
    261261
     262/**
     263 * Create hierarchical list of bbPress replies.
     264 *
     265 * @package bbPress
     266 * @subpackage Classes
     267 *
     268 * @since bbPress (r4944)
     269 */
     270class BBP_Walker_Reply extends Walker {
     271
     272    /**
     273     * @see Walker::$tree_type
     274     *
     275     * @since bbPress (r4944)
     276     *
     277     * @var string
     278     */
     279    var $tree_type = 'reply';
     280
     281    /**
     282     * @see Walker::$db_fields
     283     *
     284     * @since bbPress (r4944)
     285     *
     286     * @var array
     287     */
     288    var $db_fields = array(
     289        'parent' => 'reply_to',
     290        'id'     => 'ID'
     291    );
     292
     293    /**
     294     * @see Walker::start_lvl()
     295     *
     296     * @since bbPress (r4944)
     297     *
     298     * @param string $output Passed by reference. Used to append additional content
     299     * @param int $depth Depth of reply
     300     * @param array $args Uses 'style' argument for type of HTML list
     301     */
     302    public function start_lvl( &$output = '', $depth = 0, $args = array() ) {
     303        bbpress()->reply_query->reply_depth = $depth + 1;
     304
     305        switch ( $args['style'] ) {
     306            case 'div':
     307                break;
     308            case 'ol':
     309                echo "<ol class='bbp-threaded-replies'>\n";
     310                break;
     311            case 'ul':
     312            default:
     313                echo "<ul class='bbp-threaded-replies'>\n";
     314                break;
     315        }
     316    }
     317
     318    /**
     319     * @see Walker::end_lvl()
     320     *
     321     * @since bbPress (r4944)
     322     *
     323     * @param string $output Passed by reference. Used to append additional content
     324     * @param int $depth Depth of reply
     325     * @param array $args Will only append content if style argument value is 'ol' or 'ul'
     326     */
     327    public function end_lvl( &$output = '', $depth = 0, $args = array() ) {
     328        bbpress()->reply_query->reply_depth = (int) $depth + 1;
     329
     330        switch ( $args['style'] ) {
     331            case 'div':
     332                break;
     333            case 'ol':
     334                echo "</ol>\n";
     335                break;
     336            case 'ul':
     337            default:
     338                echo "</ul>\n";
     339                break;
     340        }
     341    }
     342
     343    /**
     344     * @since bbPress (r4944)
     345     */
     346    public function display_element( $element = false, &$children_elements = array(), $max_depth = 0, $depth = 0, $args = array(), &$output = '' ) {
     347
     348        if ( empty( $element ) )
     349            return;
     350
     351        // Get element's id
     352        $id_field = $this->db_fields['id'];
     353        $id       = $element->$id_field;
     354
     355        // Display element
     356        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
     357
     358        // If we're at the max depth and the current element still has children, loop over those
     359        // and display them at this level to prevent them being orphaned to the end of the list.
     360        if ( ( $max_depth <= (int) $depth + 1 ) && isset( $children_elements[$id] ) ) {
     361            foreach ( $children_elements[$id] as $child ) {
     362                $this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
     363            }
     364            unset( $children_elements[$id] );
     365        }
     366    }
     367
     368    /**
     369     * @see Walker:start_el()
     370     *
     371     * @since bbPress (r4944)
     372     */
     373    public function start_el( &$output = '', $reply = false, $depth = 0, $args = array(), $id = 0 ) {
     374
     375        // Set up reply
     376        $depth++;
     377        bbpress()->reply_query->reply_depth = $depth;
     378        bbpress()->reply_query->post        = $reply;
     379        bbpress()->current_reply_id         = $reply->ID;
     380
     381        // Check for a callback and use it if specified
     382        if ( !empty( $args['callback'] ) ) {
     383            call_user_func( $args['callback'], $reply, $args, $depth );
     384            return;
     385        }
     386
     387        // Style for div or list element
     388        if ( 'div' === $args['style'] ) {
     389            $tag = 'div';
     390        } else {
     391            $tag = 'li';
     392        } ?>
     393
     394        <<?php echo $tag ?>>
     395
     396            <?php bbp_get_template_part( 'loop', 'single-reply' ); ?>
     397
     398        </<?php echo $tag ?>>
     399
     400        <?php
     401    }
     402
     403    /**
     404     * @since bbPress (r4944)
     405     */
     406    public function end_el( &$output = '', $reply = false, $depth = 0, $args = array() ) {
     407
     408        // Check for a callback and use it if specified
     409        if ( !empty( $args['end-callback'] ) ) {
     410            call_user_func( $args['end-callback'], $reply, $args, $depth );
     411            return;
     412        }
     413
     414        // Style for div or list element
     415        if ( !empty( $args['style'] ) && ( 'div' === $args['style'] ) ) {
     416            echo "</div>\n";
     417        } else {
     418            echo "</li>\n";
     419        }
     420    }
     421}
    262422endif; // class_exists check
  • trunk/includes/common/template-tags.php

    r4935 r4944  
    15831583        <input type="hidden" name="bbp_reply_title" id="bbp_reply_title" value="<?php bbp_reply_title(); ?>" />
    15841584        <input type="hidden" name="bbp_reply_id"    id="bbp_reply_id"    value="<?php bbp_reply_id(); ?>" />
     1585        <input type="hidden" name="bbp_reply_to"    id="bbp_reply_to"    value="<?php bbp_form_reply_to(); ?>" />
    15851586        <input type="hidden" name="action"          id="bbp_post_action" value="bbp-edit-reply" />
    15861587
     
    15941595        <input type="hidden" name="bbp_reply_title" id="bbp_reply_title" value="<?php printf( __( 'Reply To: %s', 'bbpress' ), bbp_get_topic_title() ); ?>" />
    15951596        <input type="hidden" name="bbp_topic_id"    id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />
     1597        <input type="hidden" name="bbp_reply_to"    id="bbp_reply_to"    value="<?php bbp_form_reply_to(); ?>" />
    15961598        <input type="hidden" name="action"          id="bbp_post_action" value="bbp-new-reply" />
    15971599
  • trunk/includes/core/actions.php

    r4918 r4944  
    182182
    183183// New/Edit Reply
    184 add_action( 'bbp_new_reply',  'bbp_update_reply', 10, 6 );
    185 add_action( 'bbp_edit_reply', 'bbp_update_reply', 10, 6 );
     184add_action( 'bbp_new_reply',  'bbp_update_reply', 10, 7 );
     185add_action( 'bbp_edit_reply', 'bbp_update_reply', 10, 7 );
    186186
    187187// Before Delete/Trash/Untrash Reply
  • trunk/includes/core/options.php

    r4932 r4944  
    3535        '_bbp_enable_subscriptions' => 1,                          // Subscriptions
    3636        '_bbp_allow_topic_tags'     => 1,                          // Topic Tags
     37        '_bbp_thread_replies_depth' => 0,                          // Thread replies depth
    3738        '_bbp_allow_anonymous'      => 0,                          // Allow anonymous posting
    3839        '_bbp_allow_global_access'  => 1,                          // Users from all sites can post
     
    225226function bbp_allow_topic_tags( $default = 1 ) {
    226227    return (bool) apply_filters( 'bbp_allow_topic_tags', (bool) get_option( '_bbp_allow_topic_tags', $default ) );
     228}
     229
     230/**
     231 * Are replies threaded
     232 *
     233 * @since bbPress (r4944)
     234 *
     235 * @param bool $default Optional. Default value true
     236 * @uses apply_filters() Calls 'bbp_thread_replies' with the calculated value and
     237 *                        the thread replies depth
     238 * @uses get_option() To get thread replies option
     239 * @return bool Are replies threaded?
     240 */
     241function bbp_thread_replies() {
     242    $depth  = bbp_thread_replies_depth();
     243    $retval = (bool) ( $depth > 1 );
     244
     245    return (bool) apply_filters( 'bbp_thread_replies', $retval, $depth );
     246}
     247
     248/**
     249 * Maximum reply thread depth
     250 *
     251 * @since bbPress (r4944)
     252 *
     253 * @param int $default Thread replies depth
     254 * @uses apply_filters() Calls 'bbp_thread_replies_depth' with the option value and
     255 *                       the default depth
     256 * @uses get_option() To get the thread replies depth
     257 * @return int Thread replies depth
     258 */
     259function bbp_thread_replies_depth( $default = 1 ) {
     260    return (int) apply_filters( 'bbp_thread_replies_depth', (int) get_option( '_bbp_thread_replies_depth', $default ) );
    227261}
    228262
  • trunk/includes/replies/functions.php

    r4906 r4944  
    9898 * @uses wp_insert_post() To insert the reply
    9999 * @uses do_action() Calls 'bbp_new_reply' with the reply id, topic id, forum
    100  *                    id, anonymous data and reply author
     100 *                    id, anonymous data, reply author, edit (false), and
     101 *                    the reply to id
    101102 * @uses bbp_get_reply_url() To get the paginated url to the reply
    102103 * @uses wp_safe_redirect() To redirect to the reply url
     
    117118
    118119    // Define local variable(s)
    119     $topic_id = $forum_id = $reply_author = $anonymous_data = 0;
     120    $topic_id = $forum_id = $reply_author = $anonymous_data = $reply_to = 0;
    120121    $reply_title = $reply_content = $terms = '';
    121122
     
    195196        }
    196197    }
     198
     199    /** Reply To **************************************************************/
     200
     201    // Handle Reply To of the reply; $_REQUEST for non-JS submissions
     202    if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
     203        $reply_to = (int) $_REQUEST['bbp_reply_to'];
     204    }
     205
     206    $reply_to = bbp_get_reply_id( $reply_to );
    197207
    198208    /** Unfiltered HTML *******************************************************/
     
    365375        /** Update counts, etc... *********************************************/
    366376
    367         do_action( 'bbp_new_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author );
     377        do_action( 'bbp_new_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author, false, $reply_to );
    368378
    369379        /** Additional Actions (After Save) ***********************************/
     
    422432 * @uses bbp_get_reply_topic_id() To get the reply topic id
    423433 * @uses bbp_get_topic_forum_id() To get the topic forum id
     434 * @uses bbp_get_reply_to() To get the reply to id
    424435 * @uses do_action() Calls 'bbp_edit_reply' with the reply id, topic id, forum
    425  *                    id, anonymous data, reply author and bool true (for edit)
     436 *                    id, anonymous data, reply author, bool true (for edit),
     437 *                    and the reply to id
    426438 * @uses bbp_get_reply_url() To get the paginated url to the reply
    427439 * @uses wp_safe_redirect() To redirect to the reply url
     
    501513
    502514    $forum_id = bbp_get_topic_forum_id( $topic_id );
     515
     516    /** Reply To **************************************************************/
     517
     518    $reply_to = bbp_get_reply_to( $reply_id );
    503519
    504520    // Forum exists
     
    661677
    662678        // Update counts, etc...
    663         do_action( 'bbp_edit_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author , true /* Is edit */ );
     679        do_action( 'bbp_edit_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author , true, $reply_to );
    664680
    665681        /** Additional Actions (After Save) ***********************************/
     
    703719 * @param int $author_id Author id
    704720 * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
     721 * @param int $reply_to Optional. Reply to id
    705722 * @uses bbp_get_reply_id() To get the reply id
    706723 * @uses bbp_get_topic_id() To get the topic id
     
    719736 * @uses bbp_update_reply_forum_id() To update the reply forum id
    720737 * @uses bbp_update_reply_topic_id() To update the reply topic id
     738 * @uses bbp_update_reply_to() To update the reply to id
    721739 * @uses bbp_update_reply_walker() To update the reply's ancestors' counts
    722740 */
    723 function bbp_update_reply( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $author_id = 0, $is_edit = false ) {
     741function bbp_update_reply( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $author_id = 0, $is_edit = false, $reply_to = 0 ) {
    724742
    725743    // Validate the ID's passed from 'bbp_new_reply' action
     
    727745    $topic_id = bbp_get_topic_id( $topic_id );
    728746    $forum_id = bbp_get_forum_id( $forum_id );
     747    $reply_to = bbp_get_reply_id( $reply_to );
    729748
    730749    // Bail if there is no reply
     
    790809    bbp_update_reply_forum_id( $reply_id, $forum_id );
    791810    bbp_update_reply_topic_id( $reply_id, $topic_id );
     811    bbp_update_reply_to      ( $reply_id, $reply_to );
    792812
    793813    // Update associated topic values if this is a new reply
     
    10271047}
    10281048
     1049/*
     1050 * Update the reply's meta data with its reply to id
     1051 *
     1052 * @since bbPress (r4944)
     1053 *
     1054 * @param int $reply_id Reply id to update
     1055 * @param int $reply_to Optional. Reply to id
     1056 * @uses bbp_get_reply_id() To get the reply id
     1057 * @uses update_post_meta() To update the reply to meta
     1058 * @uses apply_filters() Calls 'bbp_update_reply_to' with the reply id and
     1059 *                        and reply to id
     1060 * @return bool Reply's parent reply id
     1061 */
     1062function bbp_update_reply_to( $reply_id = 0, $reply_to = 0 ) {
     1063
     1064    // Validation
     1065    $reply_id = bbp_get_reply_id( $reply_id );
     1066    $reply_to = bbp_get_reply_id( $reply_to );
     1067
     1068    // Return if no reply
     1069    if ( empty( $reply_id ) )
     1070        return;
     1071
     1072    // Return if no reply to
     1073    if ( empty( $reply_to ) )
     1074        return;
     1075
     1076    // Set the reply to
     1077    update_post_meta( $reply_id, '_bbp_reply_to', $reply_to );
     1078
     1079    return (int) apply_filters( 'bbp_update_reply_to', (int) $reply_to, $reply_id );
     1080}
     1081
    10291082/**
    10301083 * Update the revision log of the reply
     
    12871340    $freshness     = $move_reply->post_date;
    12881341
     1342    // Get the reply to
     1343    $parent = bbp_get_reply_to( $move_reply->ID );
     1344
     1345    // Fix orphaned children
     1346    $children = get_posts( array(
     1347        'post_type'  => bbp_get_reply_post_type(),
     1348        'meta_key'   => '_bbp_reply_to',
     1349        'meta_value' => $move_reply->ID,
     1350    ) );
     1351    foreach ( $children as $child )
     1352        bbp_update_reply_to( $child->ID, $parent );
     1353
     1354    // Remove reply_to from moved reply
     1355    delete_post_meta( $move_reply->ID, '_bbp_reply_to' );
     1356
    12891357    // It is a new topic and we need to set some default metas to make
    12901358    // the topic display in bbp_has_topics() list
     
    20732141    return (int) $reply_position;
    20742142}
     2143
     2144/** Hierarchical Replies ******************************************************/
     2145
     2146/**
     2147 * List replies
     2148 *
     2149 * @since bbPress (r4944)
     2150 */
     2151function bbp_list_replies( $args = array() ) {
     2152
     2153    // Reset the reply depth
     2154    bbpress()->reply_query->reply_depth = 0;
     2155
     2156    // In reply loop
     2157    bbpress()->reply_query->in_the_loop = true;
     2158
     2159    $r = bbp_parse_args( $args, array(
     2160        'walker'       => null,
     2161        'max_depth'    => bbp_thread_replies_depth(),
     2162        'style'        => 'ul',
     2163        'callback'     => null,
     2164        'end_callback' => null,
     2165        'page'         => 1,
     2166        'per_page'     => -1
     2167    ), 'list_replies' );
     2168
     2169    // Get replies to loop through in $_replies
     2170    $walker = new BBP_Walker_Reply;
     2171    $walker->paged_walk( bbpress()->reply_query->posts, $r['max_depth'], $r['page'], $r['per_page'], $r );
     2172
     2173    bbpress()->max_num_pages            = $walker->max_pages;
     2174    bbpress()->reply_query->in_the_loop = false;
     2175}
  • trunk/includes/replies/template-tags.php

    r4924 r4944  
    6969
    7070    // Other defaults
    71     $default_reply_search = !empty( $_REQUEST['rs'] ) ? $_REQUEST['rs'] : false;
    72     $default_post_parent  = ( bbp_is_single_topic() ) ? bbp_get_topic_id() : 'any';
    73     $default_post_type    = ( bbp_is_single_topic() && bbp_show_lead_topic() ) ? bbp_get_reply_post_type() : array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
     71    $default_reply_search   = !empty( $_REQUEST['rs'] ) ? $_REQUEST['rs']    : false;
     72    $default_post_parent    = ( bbp_is_single_topic() ) ? bbp_get_topic_id() : 'any';
     73    $default_post_type      = ( bbp_is_single_topic() && bbp_show_lead_topic() ) ? bbp_get_reply_post_type() : array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
     74    $default_thread_replies = (bool) ( bbp_is_single_topic() && bbp_thread_replies() );
    7475
    7576    // Default query args
     
    8182        'orderby'             => 'date',                     // Sorted by date
    8283        'order'               => 'ASC',                      // Oldest to newest
     84        'hierarchical'        => $default_thread_replies,    // Hierarchical replies
    8385        'ignore_sticky_posts' => true,                       // Stickies not supported
    8486        's'                   => $default_reply_search,      // Maybe search
     
    114116    $r = bbp_parse_args( $args, $default, 'has_replies' );
    115117
     118    // Set posts_per_page value if replies are threaded
     119    $replies_per_page = $r['posts_per_page'];
     120    if ( true === $r['hierarchical'] ) {
     121        $r['posts_per_page'] = -1;
     122    }
     123
    116124    // Get bbPress
    117125    $bbp = bbpress();
     
    121129
    122130    // Add pagination values to query object
    123     $bbp->reply_query->posts_per_page = $r['posts_per_page'];
     131    $bbp->reply_query->posts_per_page = $replies_per_page;
    124132    $bbp->reply_query->paged          = $r['paged'];
    125133
     
    130138    if ( bbp_is_single_topic() ) {
    131139        $bbp->reply_query->is_single = true;
     140    }
     141
     142    // Only add reply to if query returned results
     143    if ( (int) $bbp->reply_query->found_posts ) {
     144
     145        // Get reply to for each reply
     146        foreach ( $bbp->reply_query->posts as &$post ) {
     147
     148            // Check for reply post type
     149            if ( bbp_get_reply_post_type() === $post->post_type ) {
     150                $reply_to = bbp_get_reply_to( $post->ID );
     151
     152                // Make sure it's a reply to a reply
     153                if ( empty( $reply_to ) || ( bbp_get_reply_topic_id( $post->ID ) == $reply_to ) ) {
     154                    $reply_to = 0;
     155                }
     156
     157                // Add reply_to to the post object so we can walk it later
     158                $post->reply_to = $reply_to;
     159            }
     160        }
    132161    }
    133162
     
    162191        }
    163192
    164         // Add pagination to query object
    165         $bbp->reply_query->pagination_links = paginate_links(
    166             apply_filters( 'bbp_replies_pagination', array(
     193        // Figure out total pages
     194        if ( true === $r['hierarchical'] ) {
     195            $walker      = new BBP_Walker_Reply;
     196            $total_pages = ceil( (int) $walker->get_number_of_root_elements( $bbp->reply_query->posts ) / (int) $replies_per_page );
     197        } else {
     198            $total_pages = ceil( (int) $bbp->reply_query->found_posts / (int) $replies_per_page );
     199
     200            // Add pagination to query object
     201            $bbp->reply_query->pagination_links = paginate_links( apply_filters( 'bbp_replies_pagination', array(
    167202                'base'      => $base,
    168203                'format'    => '',
    169                 'total'     => ceil( (int) $bbp->reply_query->found_posts / (int) $r['posts_per_page'] ),
     204                'total'     => $total_pages,
    170205                'current'   => (int) $bbp->reply_query->paged,
    171206                'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
     
    173208                'mid_size'  => 1,
    174209                'add_args'  => ( bbp_get_view_all() ) ? array( 'view' => 'all' ) : false
    175             ) )
    176         );
    177 
    178         // Remove first page from pagination
    179         if ( $wp_rewrite->using_permalinks() ) {
    180             $bbp->reply_query->pagination_links = str_replace( $wp_rewrite->pagination_base . '/1/', '', $bbp->reply_query->pagination_links );
    181         } else {
    182             $bbp->reply_query->pagination_links = str_replace( '&#038;paged=1', '', $bbp->reply_query->pagination_links );
     210            ) ) );
     211
     212            // Remove first page from pagination
     213            if ( $wp_rewrite->using_permalinks() ) {
     214                $bbp->reply_query->pagination_links = str_replace( $wp_rewrite->pagination_base . '/1/', '', $bbp->reply_query->pagination_links );
     215            } else {
     216                $bbp->reply_query->pagination_links = str_replace( '&#038;paged=1', '', $bbp->reply_query->pagination_links );
     217            }
    183218        }
    184219    }
     
    387422        $reply_id   = bbp_get_reply_id      ( $reply_id );
    388423        $topic_id   = bbp_get_reply_topic_id( $reply_id );
    389         $reply_page = ceil( (int) bbp_get_reply_position( $reply_id, $topic_id ) / (int) bbp_get_replies_per_page() );
     424
     425        // Hierarchical reply page
     426        if ( bbp_thread_replies() ) {
     427            $reply_page = 1;
     428
     429        // Standard reply page
     430        } else {
     431            $reply_page = ceil( (int) bbp_get_reply_position( $reply_id, $topic_id ) / (int) bbp_get_replies_per_page() );
     432        }
     433
    390434        $reply_hash = '#post-' . $reply_id;
    391435        $topic_link = bbp_get_topic_permalink( $topic_id, $redirect_to );
     
    13781422
    13791423/**
     1424 * Output the reply's ancestor reply id
     1425 *
     1426 * @since bbPress (r4944)
     1427 *
     1428 * @param int $reply_id Optional. Reply id
     1429 * @uses bbp_get_reply_ancestor_id() To get the reply's ancestor id
     1430 */
     1431function bbp_reply_ancestor_id( $reply_id = 0 ) {
     1432    echo bbp_get_reply_ancestor_id( $reply_id );
     1433}
     1434    /**
     1435     * Return the reply's ancestor reply id
     1436     *
     1437     * @since bbPress (r4944)
     1438     *
     1439     * @param in $reply_id Reply id
     1440     * @uses bbp_get_reply_id() To get the reply id
     1441     */
     1442    function bbp_get_reply_ancestor_id( $reply_id = 0 ) {
     1443
     1444        // Validation
     1445        $reply_id = bbp_get_reply_id( $reply_id );
     1446        if ( empty( $reply_id ) )
     1447            return false;
     1448
     1449        // Find highest reply ancestor
     1450        $ancestor_id = $reply_id;
     1451        while ( $parent_id = bbp_get_reply_to( $ancestor_id ) ) {
     1452            if ( empty( $parent_id ) || ( $parent_id === $ancestor_id ) || ( bbp_get_reply_topic_id( $reply_id ) === $parent_id ) || ( $parent_id == $reply_id ) ) {
     1453                break;
     1454            }
     1455            $ancestor_id = $parent_id;
     1456        }
     1457
     1458        return (int) $ancestor_id;
     1459    }
     1460
     1461/**
     1462 * Output the reply to id of a reply
     1463 *
     1464 * @since bbPress (r4944)
     1465 *
     1466 * @param int $reply_id Optional. Reply id
     1467 * @uses bbp_get_reply_to() To get the reply to id
     1468 */
     1469function bbp_reply_to( $reply_id = 0 ) {
     1470    echo bbp_get_reply_to( $reply_id );
     1471}
     1472    /**
     1473     * Return the reply to id of a reply
     1474     *
     1475     * @since bbPress (r4944)
     1476     *
     1477     * @param int $reply_id Optional. Reply id
     1478     * @uses bbp_get_reply_id() To get the reply id
     1479     * @uses get_post_meta() To get the reply to id
     1480     * @uses apply_filters() Calls 'bbp_get_reply_to' with the reply to id and
     1481     *                        reply id
     1482     * @return int Reply's reply to id
     1483     */
     1484    function bbp_get_reply_to( $reply_id = 0 ) {
     1485
     1486        // Assume there is no reply_to set
     1487        $reply_to = 0;
     1488
     1489        // Check that reply_id is valid
     1490        if ( $reply_id = bbp_get_reply_id( $reply_id ) )
     1491
     1492            // Get reply_to value
     1493            $reply_to = (int) get_post_meta( $reply_id, '_bbp_reply_to', true );
     1494
     1495        return (int) apply_filters( 'bbp_get_reply_to', $reply_to, $reply_id );
     1496    }
     1497
     1498/**
     1499 * Output the link for the reply to
     1500 *
     1501 * @since bbPress (r4944)
     1502 *
     1503 * @param array $args
     1504 * @uses bbp_get_reply_to_link() To get the reply to link
     1505 */
     1506function bbp_reply_to_link( $args = array() ) {
     1507    echo bbp_get_reply_to_link( $args );
     1508}
     1509
     1510    /**
     1511     * Return the link for a reply to a reply
     1512     *
     1513     * @since bbPress (r4944)
     1514     *
     1515     * @param array $args Arguments
     1516     * @uses bbp_current_user_can_access_create_reply_form() To check permissions
     1517     * @uses bbp_get_reply_id() To validate the reply id
     1518     * @uses bbp_get_reply() To get the reply
     1519     * @uses apply_filters() Calls 'bbp_get_reply_to_link' with the formatted link,
     1520     *                        the arguments array, and the reply
     1521     * @return string Link for a reply to a reply
     1522     */
     1523    function bbp_get_reply_to_link( $args = array() ) {
     1524
     1525        // Parse arguments against default values
     1526        $r = bbp_parse_args( $args, array(
     1527            'id'           => 0,
     1528            'link_before'  => '',
     1529            'link_after'   => '',
     1530            'reply_text'   => __( 'Reply', 'bbpress' ),
     1531            'depth'        => 0,
     1532            'add_below'    => 'post',
     1533            'respond_id'   => 'new-reply-' . bbp_get_topic_id(),
     1534        ), 'get_reply_to_link' );
     1535
     1536        $reply = bbp_get_reply( bbp_get_reply_id( (int) $r['id'] ) );
     1537
     1538        // Bail if no reply or user cannot reply
     1539        if ( empty( $reply ) || ! bbp_current_user_can_access_create_reply_form() )
     1540            return;
     1541
     1542        // Build the URI and return value
     1543        $uri      = remove_query_arg( array( 'bbp_reply_to' ) );
     1544        $uri      = add_query_arg( array( 'bbp_reply_to' => $reply->ID ) );
     1545        $uri      = esc_url( wp_nonce_url( $uri, 'respond_id_' . $reply->ID ) );
     1546        $uri      = $uri . '#new-post';
     1547        $onclick  = 'return addReply.moveForm("' . $r['add_below'] . '-' . $reply->ID . '","' . $reply->ID . '","' . $r['respond_id'] . '","' . $reply->post_parent . '")';
     1548        $r['uri'] = $uri;
     1549        $retval   = $r['link_before'] . '<a href="' . $r['uri'] . '" class="bbp-reply-to-link" onclick=' . "'{$onclick}' >" . $r['reply_text'] . '</a>' . $r['link_after'];
     1550
     1551        return apply_filters( 'bbp_get_reply_to_link', $retval, $r, $args );
     1552    }
     1553
     1554/**
     1555 * Output the reply to a reply cancellation link
     1556 *
     1557 * @since bbPress (r4944)
     1558 *
     1559 * @uses bbp_get_cancel_reply_to_link() To get the reply cancellation link
     1560 */
     1561function bbp_cancel_reply_to_link( $text = '' ) {
     1562    echo bbp_get_cancel_reply_to_link( $text );
     1563}
     1564    /**
     1565     * Return the cancellation link for a reply to a reply
     1566     *
     1567     * @since bbPress (r4944)
     1568     *
     1569     * @param string $text The cancel text
     1570     * @uses apply_filters() Calls 'bbp_get_cancel_reply_to_link' with the cancellation
     1571     *                        link and the cancel text
     1572     * @return string The cancellation link
     1573     */
     1574    function bbp_get_cancel_reply_to_link( $text = '' ) {
     1575
     1576        // Bail if not hierarchical or editing a reply
     1577        if ( ! bbp_thread_replies() || bbp_is_reply_edit() ) {
     1578            return;
     1579        }
     1580
     1581        // Set default text
     1582        if ( empty( $text ) ) {
     1583            $text = __( 'Cancel', 'bbpress' );
     1584        }
     1585
     1586        $reply_to = isset( $_GET['bbp_reply_to'] ) ? (int) $_GET['bbp_reply_to'] : 0;
     1587
     1588        // Set visibility
     1589        $style  = !empty( $reply_to ) ? '' : ' style="display:none;"';
     1590        $link   = esc_url( remove_query_arg( array( 'bbp_reply_to', '_wpnonce' ) ) ) . '#post-' . $reply_to;
     1591        $retval = '<a rel="nofollow" id="bbp-cancel-reply-to-link" href="' . $link . '"' . $style . '>' . $text . '</a>';
     1592
     1593        return apply_filters( 'bbp_get_cancel_reply_to_link', $retval, $link, $text );
     1594    }
     1595
     1596/**
    13801597 * Output the numeric position of a reply within a topic
    13811598 *
     
    15171734                'trash' => bbp_get_reply_trash_link( $r ),
    15181735                'spam'  => bbp_get_reply_spam_link ( $r ),
     1736                'reply' => bbp_get_reply_to_link   ( $r )
    15191737            ), $r['id'] );
    15201738        }
     
    20122230        $total     = bbp_number_format( $total_int );
    20132231
     2232        // We are threading replies
     2233        if ( bbp_thread_replies() ) {
     2234            $walker  = new BBP_Walker_Reply;
     2235            $threads = (int) $walker->get_number_of_root_elements( $bbp->reply_query->posts );
     2236
     2237            // Adjust for topic
     2238            $threads--;
     2239            $retstr  = sprintf( _n( 'Viewing %1$s reply thread', 'Viewing %1$s reply threads', $threads, 'bbbpress' ), bbp_number_format( $threads ) );
     2240
    20142241        // We are not including the lead topic
    2015         if ( bbp_show_lead_topic() ) {
     2242        } elseif ( bbp_show_lead_topic() ) {
    20162243
    20172244            // Several replies in a topic with a single page
     
    21092336
    21102337/**
     2338 * Output the value of the reply to field
     2339 *
     2340 * @since bbPress (r4944)
     2341 *
     2342 * @uses bbp_get_form_reply_to() To get value of the reply to field
     2343 */
     2344function bbp_form_reply_to() {
     2345    echo bbp_get_form_reply_to();
     2346}
     2347
     2348    /**
     2349     * Return the value of reply to field
     2350     *
     2351     * @since bbPress (r4944)
     2352     *
     2353     * @uses bbp_get_reply_id() To validate the reply to
     2354     * @uses apply_filters() Calls 'bbp_get_form_reply_to' with the reply to
     2355     * @return string Value of reply to field
     2356     */
     2357    function bbp_get_form_reply_to() {
     2358
     2359        // Set initial value
     2360        $reply_to = 0;
     2361
     2362        // Get $_REQUEST data
     2363        if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
     2364            $reply_to = (int) $_REQUEST['bbp_reply_to'];
     2365        }
     2366
     2367        // If empty, get from meta
     2368        if ( empty( $reply_to ) ) {
     2369            $reply_to = bbp_get_reply_to();
     2370        }
     2371
     2372        // Validate
     2373        $reply_to = bbp_get_reply_id( $reply_to );
     2374
     2375        return (int) apply_filters( 'bbp_get_form_reply_to', $reply_to );
     2376    }
     2377
     2378/**
    21112379 * Output checked value of reply log edit field
    21122380 *
  • trunk/includes/topics/functions.php

    r4903 r4944  
    12601260            bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
    12611261
     1262            // Adjust reply to values
     1263            $reply_to = bbp_get_reply_to( $reply->ID );
     1264            if ( empty( $reply_to ) ) {
     1265                bbp_update_reply_to( $reply->ID, $source_topic->ID );
     1266            }
     1267
    12621268            // Do additional actions per merged reply
    12631269            do_action( 'bbp_merged_topic_reply', $reply->ID, $destination_topic->ID );
     
    15931599        }
    15941600
     1601        // Save reply ids
     1602        $reply_ids = array();
     1603
    15951604        // Change the post_parent of each reply to the destination topic id
    15961605        foreach ( $replies as $reply ) {
     
    16121621            wp_update_post( $postarr );
    16131622
     1623            // Gather reply ids
     1624            $reply_ids[] = $reply->ID;
     1625
    16141626            // Adjust reply meta values
    16151627            bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID                           );
    16161628            bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
    16171629
     1630            // Adjust reply to values
     1631            $reply_to = bbp_get_reply_to( $reply->ID );
     1632
     1633            // Not a reply to a reply that moved over
     1634            if ( !in_array( $reply_to, $reply_ids ) ) {
     1635                bbp_update_reply_to( $reply->ID, 0 );
     1636            }
     1637
     1638            // New topic from reply can't be a reply to
     1639            if ( ( $from_reply->ID == $destination_topic->ID && $from_reply->ID == $reply_to ) ) {
     1640                bbp_update_reply_to( $reply->ID, 0 );
     1641            }
     1642
    16181643            // Do additional actions per split reply
    16191644            do_action( 'bbp_split_topic_reply', $reply->ID, $destination_topic->ID );
     1645        }
     1646
     1647        // Remove reply to from new topic
     1648        if ( $from_reply->ID == $destination_topic->ID ) {
     1649            delete_post_meta( $from_reply->ID, '_bbp_reply_to' );
    16201650        }
    16211651
  • trunk/includes/topics/template-tags.php

    r4935 r4944  
    789789        global $wp_rewrite;
    790790
     791        // Bail if threading replies
     792        if ( bbp_thread_replies() ) {
     793            return;
     794        }
     795
    791796        // Parse arguments against default values
    792797        $r = bbp_parse_args( $args, array(
  • trunk/templates/default/bbpress-functions.php

    r4872 r4944  
    180180        }
    181181
    182         // Topic favorite/subscribe
     182        // Topic-specific scripts
    183183        if ( bbp_is_single_topic() ) {
     184
     185            // Topic favorite/unsubscribe
    184186            wp_enqueue_script( 'bbpress-topic', $this->url . 'js/topic.js', array( 'jquery' ), $this->version );
     187
     188            // Hierarchical replies
     189            if ( bbp_thread_replies() ) {
     190                wp_enqueue_script( 'bbpress-reply', $this->url . 'js/reply.js', array(), $this->version );
     191            }
    185192        }
    186193
  • trunk/templates/default/bbpress/form-reply.php

    r4733 r4944  
    143143                        <?php do_action( 'bbp_theme_before_reply_form_submit_button' ); ?>
    144144
     145                        <?php bbp_cancel_reply_to_link(); ?>
     146
    145147                        <button type="submit" tabindex="<?php bbp_tab_index(); ?>" id="bbp_reply_submit" name="bbp_reply_submit" class="button submit"><?php _e( 'Submit', 'bbpress' ); ?></button>
    146148
  • trunk/templates/default/bbpress/loop-replies.php

    r4733 r4944  
    4040    <li class="bbp-body">
    4141
    42         <?php while ( bbp_replies() ) : bbp_the_reply(); ?>
     42        <?php if ( bbp_thread_replies() ) : ?>
    4343
    44             <?php bbp_get_template_part( 'loop', 'single-reply' ); ?>
     44            <?php bbp_list_replies(); ?>
    4545
    46         <?php endwhile; ?>
     46        <?php else : ?>
     47
     48            <?php while ( bbp_replies() ) : bbp_the_reply(); ?>
     49
     50                <?php bbp_get_template_part( 'loop', 'single-reply' ); ?>
     51
     52            <?php endwhile; ?>
     53
     54        <?php endif; ?>
    4755
    4856    </li><!-- .bbp-body -->
  • trunk/templates/default/css/bbpress-rtl.css

    r4889 r4944  
    6464    margin: 0;
    6565    padding: 0;
     66}
     67
     68#bbpress-forums ul.bbp-threaded-replies {
     69    margin-right: 50px;
    6670}
    6771
     
    351355}
    352356
     357/* =Reply to
     358-------------------------------------------------------------- */
     359
     360#bbpress-forums div.bbp-reply-to {
     361    margin-right: 130px;
     362    padding: 12px 0px 12px 12px;
     363    text-align: left;
     364}
     365
     366#bbpress-forums div#bbp-cancel-reply-to {
     367    text-align: left;
     368}
     369
    353370/* =Breadcrumb and Tags
    354371-------------------------------------------------------------- */
  • trunk/templates/default/css/bbpress.css

    r4889 r4944  
    6565    padding: 0;
    6666}
     67
     68#bbpress-forums ul.bbp-threaded-replies {
     69    margin-left: 50px;
     70}
    6771
    6872#bbpress-forums li {
     
    351355}
    352356
     357/* =Reply to
     358-------------------------------------------------------------- */
     359
     360#bbpress-forums div.bbp-reply-to {
     361    margin-left: 130px;
     362    padding: 12px 12px 12px 0;
     363    text-align: right;
     364}
     365
     366#bbpress-forums div#bbp-cancel-reply-to {
     367    text-align: right;
     368}
     369
    353370/* =Breadcrumb and Tags
    354371-------------------------------------------------------------- */
Note: See TracChangeset for help on using the changeset viewer.